1. 简介
日期类型,常用的数据类型。内部记录的是从1970年1月1日0点(UTC)到当前时间经历的毫秒数。
关联的两个工具类Calendar
,SimpleDateFormat
提供了时间的运算,格式化等api。
2. 概念
- GMT,UT, UTC
- 时区,夏令时
3. 源码
toString(), wtb
// 用于parse方法,已经废弃。只有[2-20]用于表示toString中的月份和星期 private final static String wtb[] = { "am", "pm", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december", "gmt", "ut", "utc", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt" }; public String toString() { // "EEE MMM dd HH:mm:ss zzz yyyy"; ... // day of week,星期天是1,为了配置常量数组wtb,改为8 int index = date.getDayOfWeek(); if (index == BaseCalendar.SUNDAY) { index = 8; } ... }
parse() vs
DateFormat.parse(String s)
无设计 vs 有设计
4. 示例
- 格式化
@Test
public void testDate2String() {
Date d = new Date();
System.out.println(d);
DateFormat df = DateFormat.getDateInstance();
System.out.println(df.format(d));
}
- 涉及夏令时的操作
@Test
public void testDst() {
// 卢森堡
System.setProperty("user.timezone", "Europe/Luxembourg");
Date now = new Date();
System.out.println(now);
Calendar c = Calendar.getInstance();
c.setTime(now);
// 东1区,夏令时
System.out.println(c.get(Calendar.ZONE_OFFSET) / (1000*60*60));
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.add(Calendar.MONTH, 3);
// 非夏令时
System.out.println(c.getTime());
System.out.println(c.get(Calendar.ZONE_OFFSET) / (1000*60*60));
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
}
@Test
public void testOffsetDate() {
// 卢森堡
System.setProperty("user.timezone", "Europe/Luxembourg");
Calendar c = Calendar.getInstance();
// 此时仍是夏令时,DST OFFSET=1,偏移2个小时,包含一个DST切换补偿的一个小时
// 卢森堡在当地时间 2018年10月28日,03:00:00 时钟向后调整 1 小时 变为 2018年10月28日,02:00:00,结束夏令时
c.set(2018, 9, 28, 1, 59, 59);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.add(Calendar.HOUR, 2);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c = Calendar.getInstance();
// 2点以后,认为时区已经切换,不再有补偿
c.set(2018, 9, 28, 2, 0, 0);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.add(Calendar.HOUR, 1);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c = Calendar.getInstance();
// 进入夏令时,没有2点,直接到3点
// 卢森堡在当地时间 2018年03月25日,02:00:00 时钟向前调整 1 小时 变为 2018年03月25日,03:00:00,开始夏令时
c.set(2018, 2, 25, 2, 0, 0);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.add(Calendar.HOUR, 1);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.set(2018, 2, 25, 1, 59, 59);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
c.add(Calendar.HOUR, 1);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DST_OFFSET) / (1000*60*60));
}
5. 总结
- 前后台,涉及时间的传递时,建议使用字符串,避免客户端和服务端时区不一致,导致时间更新异常。
- 在存在夏令时的地区,时间处理需要特别注意下DST_OFFSET。
数据库中的时间需要统一时区来记录。 - 了解常用的几种日期格式即可。