从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • JavaSE

    • 我的Java学习路线
    • 安装Java
    • Java数据类型

    • Java多版本配置
    • 面向对象

    • Java核心类

    • IO

    • Java与时间

      • Java中的时间
      • Date、Calendar和TimeZone
        • ​Date​​基本使用
        • Calendar基本使用
        • TimeZone类
        • SimpleDateFormat
        • 小结
      • LocalDate、LocalTime和LocalDateTime
      • 一些日期的枚举类
      • DateTimeFormatter
      • 时间调节器
      • Duration和Period
      • ZonedDateTime
      • Instant时刻
      • Java新旧时间API转换
    • 异常处理

    • 哈希和加密算法

    • Java8新特性

    • 网络编程

    • Java
  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • Java
  • JavaSE
  • Java与时间
2022-12-27
目录

Date、Calendar和TimeZone

# 51.Date、Calendar和TimeZone

简单聊聊Date、Calendar和TimeZone

# ​Date​​基本使用

前面我们说过,Java使用long类型来存储时间戳,我们来看看Date的源码,验证下:

public class Date implements java.io.Serializable, Cloneable, Comparable<Date>{
    private transient long fastTime;
}
1
2
3

‍

现在我们演示下其基本用法,比较简单,直接列出代码:

Date date = new Date();
System.out.println(date.getYear());     //返回年份
System.out.println(date.getMonth());    //返回月份
System.out.println(date.getDate());    //返回天数
System.out.println(date.toString());    //时间的String类型
System.out.println(date.toGMTString());    //GMT时区下的时间
System.out.println(date.toLocaleString());    //当地时间
1
2
3
4
5
6
7

‍

‍

编译和运行(笔者运行的时候是2022-12-21 20:43左右):

> javac .\TestDate.java
注: .\TestDate.java使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。

> java TestDate      
122
11
21
Wed Dec 21 20:43:18 CST 2022
21 Dec 2022 12:43:18 GMT
2022-12-21 20:43:18
1
2
3
4
5
6
7
8
9
10
11

首先我们看到,编译的时候就提示我们用了已过时的API。

接下来我们来看看输出的内容,并讲解。

‍

# ​date.getYear()​

首先是date.getYear()​的输出,顾名思义,是输出年份的,但为什么是122?运行的时候不是2022年吗?相差了1900年!我们可以看看其源码和注释:

 /**
     * Returns a value that is the result of subtracting 1900 from the
     * year that contains or begins with the instant in time represented
     * by this Date object, as interpreted in the local
     * time zone.
     *
     * @return  the year represented by this date, minus 1900.
     * @see     java.util.Calendar
     * @deprecated As of JDK version 1.1,
     * replaced by Calendar.get(Calendar.YEAR) - 1900.
     */
    @Deprecated
    public int getYear() {
        return normalize().getYear() - 1900;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到其返回的是一个整数,并且是根据从1900年开始到今年,过了多少年来计算的(是不是很令人无语的设计🤔)。所以我们如果要获取当前年份,得加上1900:

date.getYear() + 1900;
1

‍

‍

# ​date.getMonth()​​

下面我们来看看date.getMonth()​,其用来输出当前月份,为什么是输出11?运行的时候明明是12月! 老规矩,我们先看看注释和源码

/**
     * Returns a number representing the month that contains or begins
     * with the instant in time represented by this <tt>Date</tt> object.
     * The value returned is between 0 and 11,
     * with the value 0 representing January.
     *
     * @return  the month represented by this date.
     * @see     java.util.Calendar
     * @deprecated As of JDK version 1.1,
     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
     */
    @Deprecated
    public int getMonth() {
        return normalize().getMonth() - 1; // adjust 1-based to 0-based
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注释的大意是说,0表示1月,1表示2月…… 11表示12月 (这设计就更离谱了吧🙄,跟JavaScript里的时间的设计有的比)。所以我们如果要获取当前月份,得加上1:

date.getMont() + 1;
1

‍

# ​date.getDate()​​​

​date.getDate()​是输出天数,这里输出的是21,和运行的时候2022年12月21日一致,返回的日期范围是1​~31​,不做多解释。

‍

# ​date.toString()

​date.toString()​就是返回一串字符串,其格式在不同计算机下可能不同。我们可以使用一个格式化工具类SimpleDateFormat ,精确的控制其格式,具体我们后面再说。

‍

‍

# ​date.toGMTString()​

​date.toGMTString()​返回的是格林尼治时间的时间字符串,这里不多解释。

‍

# ​Date.parse()​获取毫秒

可以通过Date.parse()​来获取毫秒

    long t = Date.parse("Mon 6 Jan 1997 13:3:00");
    System.out.println(t);  //852526980000
1
2

Date.parse接受什么格式的字符串呢?很多,规则也很复杂,读者记住一两个格式就行。感兴趣的可以看看官网文档Date (Java Platform SE 8 ) (opens new window),

‍

如果输入的格式有问题,会抛出参数不合法的异常,注意捕获:

Exception in thread "main" java.lang.IllegalArgumentException
        at java.util.Date.parse(Date.java:617)
        at TestDate.main(TestDate.java:19)
1
2
3

‍

# 其他构造方法

还可以通过如下方式创建Date对象:

Date(int year, int month, int date);
Date(int year, int month, int date, int hrs, int min)
Date(int year, int month, int date, int hrs, int min, int sec)
Date(long date) //毫秒数,可以通过Date.parse()来获取毫秒
Date(String s)    //s - 日期的字符串表示形式,和Date.parse(String s)中s的格式相同
1
2
3
4
5

注意

  • year的值需要-1900. 例如你想设置2022年,得传入2022-1900 = 122年
  • month的值域为0~11,0代表1月,11表代表12月
  • date的值域在1~31之间,min和sec的值域在0~59之间

‍

‍

# Date类小结

一番演示下来,可以看到除了其API不好用之外,其实​Date​对象有几个严重的问题:它不能转换时区,除了toGMTString()​可以按GMT+0:00​输出外,Date总是以当前计算机系统的默认时区为基础进行输出。

另外,Date对象没有提供时间相关运算的API,例如对日期和时间进行加减、计算相差的天数等

‍

# Calendar基本使用

​Calendar​可以用于获取并设置年、月、日、时、分、秒,它和Date​比,主要多了一个可以做简单的日期和时间运算的功能。

我们还是先演示下其基本用法:

Calendar c = Calendar.getInstance();   //创建Calendar实例
int y = c.get(Calendar.YEAR);    //获取年份
int m = c.get(Calendar.MONTH) + 1;    //获取月份
int d = c.get(Calendar.DAY_OF_MONTH);    //天数
int w = c.get(Calendar.DAY_OF_WEEK);    //星期几
int hh = c.get(Calendar.HOUR_OF_DAY);    //小时
int mm = c.get(Calendar.MINUTE);    //分钟
int ss = c.get(Calendar.SECOND);    //秒数
int ms = c.get(Calendar.MILLISECOND);  //毫秒数
System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
1
2
3
4
5
6
7
8
9
10

输出:

2022-12-21 4 21:51:21.155
1

这里就不一一说明各个方法了,很多方法看名字就知道其用处,也加了注释。

‍

这里需要注意的:

  • ​Calendar​只有一种方式获取,即Calendar.getInstance()​,而且一获取到就是当前时间... 其构造方法是protected,无法new。
  • 返回的月份仍然要加1…… 😒
  • DAY_OF_WEEK返回的星期几,但是其值范围是1​~7​分别表示周日,周一,……,周六。所以2022-12-21是星期三,但是输出的4 (还是令人无语的设计😶)

‍

‍

# 设置Calendar

由于Calendar​只有一种方式获取,如果我们想要指定时间,怎么做呢?用set方法。

Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, 2023); //设置年份
c.set(Calendar.MONTH, 8); //设置月份,注意8表示9月.... 
c.set(Calendar.DATE, 2);  //设置天数


//设置时分秒
c.set(Calendar.HOUR_OF_DAY, 21); 
c.set(Calendar.MINUTE, 30); 
c.set(Calendar.SECOND, 45); 
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(c.getTime()));    //2023-09-02 21:30:45

//一步到位:
c.set(2022,11,22,7,48,00);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

‍

其他注意事项:

  • 设置小时,如果使用HOUR_OF_DAY设置的是24小时制,使用HOUR表示的是12小时制。
  • 也可以一次性设置完所有字段:c.set(2019, 10, 20, 8, 15, 0);​
  • 设置毫秒时,注意毫秒的范围是0-999 (1秒 = 1000毫秒)。如果超过999会怎么样呢?就会自动转为秒。。。。 例如c.set(Calendar.MILLISECOND, 2000);​,就会增加2秒。set其他字段同理

‍

# ​Calendar.getTime()​

直接打印Calendar对象,其输出并不是时间,而是其内部的一些属性,例如:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai"...............
1

所以我们可以通过Calendar的getTime方法返回一个Date对象,并打印。

‍

# 重置Calendar

如果想要重置Calendar呢?可以用clear方法,这样Calendar是从1970-1-1 00:00:00开始

    Calendar c = Calendar.getInstance();
    c.clear();
    System.out.println(c.getTime());//Thu Jan 01 00:00:00 CST 1970
1
2
3

‍

‍

# 对日期进行加减

Calendar可以对日期进行简单的加减

Calendar c = Calendar.getInstance();
c.set(2022,11,22,7,48,00);
System.out.println(sdf.format(c.getTime()));  //2022-12-22 07:48:00

c.add(Calendar.DAY_OF_MONTH, 5);    //加5天
c.add(Calendar.SECOND, -1);    //减一秒
System.out.println(sdf.format(c.getTime())); //2022-12-27 07:47:59
1
2
3
4
5
6
7

‍

# 比较Calendar对象

可以用compareTo方法比较两个Calendar对象。小于返回-1,相等(年月日时分秒和毫秒都相等)则返回0,大于则返回1

    Calendar c = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    System.out.println(c.compareTo(c2)); //-1
1
2
3

由于代码运行需要一定的时间,所以如果是不同的创建语句,创建出来的对象基本上毫秒数是不同的。

‍

# TimeZone类

和Calendar​和Date​相比,TimeZone提供了时区转换的功能。

‍

‍

# ​TimeZone​​基本概念

    TimeZone tzDefault = TimeZone.getDefault(); //当前时区
    TimeZone tzGMT9 = TimeZone.getTimeZone("GMT+09:00");  //GMT + 9:00 时区
    TimeZone tzNewYork = TimeZone.getTimeZone("America/New_York"); //纽约时区

    System.out.println(tzDefault.getID());    //Asia/Shanghai
    System.out.println(tzGMT9.getID());    //GMT+09:00
    System.out.println(tzNewYork.getID());    //America/New_York
1
2
3
4
5
6
7

时区的唯一标识是以字符串表示的ID,我们获取指定TimeZone​对象也是以这个ID为参数获取,GMT+09:00​、Asia/Shanghai​都是有效的时区ID。

要列出系统支持的所有ID,可以用TimeZone.getAvailableIDs()​,

String str[] = TimeZone.getAvailableIDs();
System.out.println(str.length);    //2022年12月22日运行的时候,是628个
for (int i = 0; i < str.length; i++) {
  System.out.println(str[i]);
}
1
2
3
4
5

‍

# 根据时区转换时间

举个例子,将北京时间转为纽约时间

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Calendar c = Calendar.getInstance();

    c.clear();
    c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    c.set(2022, 11,22,7,57,00);
    System.out.println("北京时间: " + sdf.format(c.getTime()));
    //北京时间: 2022-12-22 07:57:00

    sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    System.out.println("纽约时间: " + sdf.format(c.getTime()));
    //纽约时间: 2022-12-21 18:57:00
1
2
3
4
5
6
7
8
9
10
11
12

说明下时区转换的步骤:

  1. 获取Calendar实例,清除所有字段并设置时间
  2. 创建SimpleDateFormat​并设定目标时区
  3. 通过SimpleDateFormat​显示转换后的时间

‍

‍

# SimpleDateFormat

‍

我们可以用SimpleDateFormat来控制Date类型的打印格式:

Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
System.out.println(sdf.format(date));    //format返回的是一个String类型
1
2
3

这里的yyyy-MM-dd HH:mm:ss 分别指年份、月份、日期、小时、分钟和秒数。编译和运行:

2022-12-21 21:23:17
1

SimpleDateFormat的参数的更多说明,可以看文档:SimpleDateFormat (Java SE 12 & JDK 12 ) (opens new window)

‍

‍

也可以使用SimpleDateFormat来转换字符串为Date对象:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = "2022-05-21 10:59:27";
Date date = sdf.parse(dateStr);
1
2
3

‍

需要注意的是,SimpleDateFormat​是线程不安全的。

‍

‍

‍

‍

# 小结

Date类常用方法:

  • 构造方法
    Date();
    Date(int year, int month, int date);
    Date(int year, int month, int date, int hrs, int min)
    Date(int year, int month, int date, int hrs, int min, int sec)
    Date(long date) //毫秒数,可以通过Date.parse()来获取毫秒
    Date(String s) //s - 日期的字符串表示形式,和Date.parse(String s)中s的格式相同

  • 常用方法

    date.getYear() 返回年份,注意得加上1900
    date.getMonth() 返回月份,注意0表示1月,1表示2月……
    date.getDate() 返回天数,范围是0~31
    date.toString() 返回时间的字符串,默认是西方的格式
    date.toGMTString() 返回GMT时区的时间
    date.toLocaleString() 返回当地时间
    Date.parse(String s) 获取时间的毫秒数

‍

‍

Calendar类常用方法:

  • Calendar c = Calendar.getInstance(); //唯一创建Calendar实例的方法

  • 常用方法

    c.getTime() 返回Date对象
    c.get(Calendar.YEAR); //获取年份
    c.get(Calendar.MONTH) + 1; //获取月份,注意0表示1月……
    c.get(Calendar.DAY_OF_MONTH); //获取天数
    c.get(Calendar.DAY_OF_WEEK); //获取星期几,注意1表示星期日,2表示星期一...
    c.get(Calendar.HOUR_OF_DAY); //获取小时
    c.get(Calendar.MINUTE); //获取分钟
    c.get(Calendar.SECOND); //秒数
    c.get(Calendar.MILLISECOND); //毫秒数

  • 设置Calendar
    c.set(2022,11,22,7,48,00);
    c.set(Calendar.YEAR, 2023);
    c.set(Calendar.MONTH, 8);
    c.set(Calendar.DATE, 2);
    c.set(Calendar.HOUR_OF_DAY, 21);
    c.set(Calendar.MINUTE, 30);
    c.set(Calendar.SECOND, 45);
    c.clear(); 重置为1970-1-1 0点0分,可用于初始化

  • 加减
    c.add(Calendar.DAY_OF_MONTH, 5); //加5天
    c.add(Calendar.SECOND, -1); //减一秒

  • 比较:c.compareTo(c2)

‍

TimeZone :可用于转换时区,根据SimpleDateFormat格式化输出
构造方法:
TimeZone.getDefault(); //当前时区
TimeZone.getTimeZone(时区ID) 例如"GMT+09:00" "America/New_York"
TimeZone.getAvailableIDs() 获取所有时区ID

‍

SimpleDateFormat
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date)
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(String s) ;返回一个Date对象
sdf.setTimeZone(TimeZone对象) 设置时区

在GitHub上编辑此页 (opens new window)
上次更新: 2022/12/27 22:03:10
Java中的时间
LocalDate、LocalTime和LocalDateTime

← Java中的时间 LocalDate、LocalTime和LocalDateTime→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式