Date 和 Calendar
1265字约4分钟
2024-08-10
我们先来看下几种日期和时间
2019-11-20 0:15:01 GMT+00:00
2019年11月20日8:15:01
11/19/2019 19:15:01 America/New_York
它们实际上是数据的展示格式,分别按英国时区、中国时区、纽约时区对同一个时刻进行展示。而这个"同一个时刻"在计算机中存储的本质上只是一个整数,我们称它为 Epoch Time
Epoch Time
是计算从 1970
年 1
月 1
日零点(格林威治时区/GMT+00:00
)到现在所经历的秒数
1574208900
表示从从 1970
年 1
月 1
日零点GMT时区到该时刻一共经历了 1574208900
秒,换算成伦敦、北京和纽约时间分别是
1574208900 = 北京时间2019-11-20 8:15:00
= 伦敦时间2019-11-20 0:15:00
= 纽约时间2019-11-19 19:15:00
Epoch Time
又称为时间戳,在不同的编程语言中,会有几种存储方式
以秒为单位的整数:
1574208900
,缺点是精度只能到秒以毫秒为单位的整数:
1574208900123
,最后3位表示毫秒数以秒为单位的浮点数:
1574208900.123
,小数点后面表示零点几秒
它们之间转换非常简单。而在 Java
程序中,时间戳通常是用 long
表示的毫秒数
long t = 1574208900123L;
转换成北京时间就是 2019-11-20T8:15:00.123
。要获取当前时间戳,可以使用 System.currentTimeMillis()
,这是 Java
程序获取时间戳最常用的方法
标准库 API
Java标准库有两套处理日期和时间的API
一套定义在
java.util
这个包里面,主要包括Date
、Calendar
和TimeZone
这几个类一套新的
API
是在Java 8
引入的,定义在java.time
这个包里面,主要包括LocalDateTime
、ZonedDateTime
、ZoneId
等
因为历史遗留原因,旧的 API
存在很多问题,所以引入了新的 API
Date
java.util.Date
是用于表示一个日期和时间的对象,注意与 java.sql.Date
区分,后者用在数据库中。如果观察 Date
的源码,可以发现它实际上存储了一个 long
类型的以毫秒表示的时间戳
public class Date implements Serializable, Cloneable, Comparable<Date> {
private transient long fastTime;
...
}
Date
的基本用法
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.getYear() + 1900); // 必须机上 1900
System.out.println(date.getMonth() + 1); // 0~11,必须加上 1
System.out.println(date.getDate()); // 1~31,无需加 1
// 转换为 String
System.out.println(date.toString()); // Thu Feb 25 22:24:08 CST 2021
// 转换为 GMT 时区
System.out.println(date.toGMTString()); // 25 Feb 2021 14:24:08 GMT
// 转换为本地时区
System.out.println(date.toLocaleString()); // 2021-2-25 22:24:08
}
注意 getYear()
返回的年份必须加上 1900
,getMonth()
返回的月份是 0~11
分别表示 1~12
月,所以要加 1
,而 getDate()
返回的日期范围是 1~31
,又不能加 1
SimpleDateFormat
打印本地时区表示的日期和时间时,不同的计算机可能会有不同的结果。如果我们想要针对用户的偏好精确地控制日期和时间的格式,就可以使用 SimpleDateFormat
对一个 Date
进行转换
yyyy
:年MM
:月dd
: 日HH
: 小时mm
: 分钟ss
: 秒
public static void main(String[] args) {
// 获取当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date)); // 2021-02-25 22:29:19
}
Date
对象有几个严重的问题
它不能转换时区,除了
toGMTString()
可以按GMT+0:00
输出外Date
总是以当前计算机系统的默认时区为基础进行输出我们很难对日期和时间进行加减,计算两个日期相差多少天,计算某个月第一个星期一的日期等
Calendar
Calendar
可以用于获取并设置年、月、日、时、分、秒,它和 Date
比,主要多了一个可以做简单的日期和时间运算的功能
public static void main(String[] args) {
// 获取当前时间
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1;
int d = c.get(Calendar.DAY_OF_MONTH);
// 5 表示周四
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);
// 2021-2-25 5 22:36:13.458
System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
}
Calendar
获取年月日这些信息变成了 get(int field)
,返回的年份不必转换,返回的月份仍然要加 1
,返回的星期要特别注意,1~7
分别表示周日,周一,……,周六
利用 Calendar.getTime()
可以将一个 Calendar
对象转换成 Date
对象,然后就可以用 SimpleDateFormat
进行格式化
TimeZone
Calendar
和 Date
相比,它提供了时区转换的功能。时区用 TimeZone
对象表示
public static void main(String[] args) {
// 当前时区
TimeZone tzDefault = TimeZone.getDefault();
// GMT+9:00时区
TimeZone tzGMT9 = TimeZone.getTimeZone("GMT+09:00");
// 纽约时区
TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
System.out.println(tzDefault.getID()); // Asia/Shanghai
System.out.println(tzGMT9.getID()); // GMT+09:00
System.out.println(tzNY.getID()); // America/New_York
}
时区的唯一标识是以字符串表示的 ID
,我们获取指定 TimeZone
对象也是以这个 ID
为参数获取,GMT+09:00
、Asia/Shanghai
都是有效的时区 ID
。要列出系统支持的所有 ID
,请使用 TimeZone.getAvailableIDs()