时间格式:
//世界标准时间,其中T表示时分秒的开始(或者日期与时间的间隔),Z表示这是一个世界标准时间
2017-12-13T01:47:07.081Z
//本地时间,也叫不含时区信息的时间,末尾没有Z
2017-12-13T09:47:07.153
//含有时区信息的时间,+08:00表示该时间是由世界标准时间加了8个小时得到的,[Asia/Shanghai]表示时区
2017-12-13T09:47:07.153+08:00[Asia/Shanghai]
其中最难理解的是本地时间,2017-12-13T09:47:07.153
时间本身是不含有时区信息的,但是“本地”这两个字含有时间信息。所以我认为这个翻译并不好,不应该叫做“本地时间”,应该直接翻译为“不含时区信息的时间”。
协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。
世界时UT即格林尼治平太阳时间,是指格林尼治所在地的标准时间,也是表示地球自转速率的一种形式。以地球自转为基础的时间计量系统。
表示时间的主要有4类String、Instant、LocalDateTime、ZonedDateTime。
String是格式化的时间,Instant是时间戳,LocalDateTime是不含时区信息的时间,ZonedDateTime是含有时区信息的时间。
符合格式的String可以直接解析为LocalDateTime,如下:
System.out.println(LocalDateTime.parse("2017-12-13 10:10:10",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
输出:
2017-12-13T10:10:10
辨析LocalDateTime最好的办法就是不要把它当成“本地时间”,它就是“不含时区信息的时间”。它只是存储了年月日时分秒,没有存储任何时区信息,具体表示哪里的时间全靠输入和输出时进行解释。与String完全等价,本质上是对String的解析,只是年月日时分秒格式化的存储到了对象当中,方便取用。
Instant是时间戳,是指世界标准时格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,Instant本身实际上就指明时区了,0时区。
ZonedDateTime是含有时区信息的时间,本质上是根据时区对Instant的格式化显示。
ZonedDateTime ztime1=ZonedDateTime.ofInstant(Instant.now(),ZoneId.systemDefault());
System.out.println(ztime1);
System.out.println(ztime1.toInstant()); //1
System.out.println(ztime1.toLocalDateTime()); //3
ZonedDateTime ztime2=ZonedDateTime.ofInstant(Instant.now(),ZoneId.of("Australia/Darwin"));
System.out.println(ztime2);
System.out.println(ztime2.toInstant()); //2
System.out.println(ztime2.toLocalDateTime()); //4
输出:
2017-12-13T13:24:55.932+08:00[Asia/Shanghai]
2017-12-13T05:24:55.932Z
2017-12-13T13:24:55.932
2017-12-13T14:54:55.933+09:30[Australia/Darwin]
2017-12-13T05:24:55.933Z
2017-12-13T14:54:55.933
注释1、2输出相同,说明ZonedDateTime的存储本质是Instant;
注释3、4输出不同,说明ZonedDateTime会根据创建ZonedDateTime对象时传入的时区,进行格式化显示。
相同的Instant,在不同的时区有不同的展示时间,所以在用Instant构造ZonedDateTime的时候需要传入时区;ZonedDateTime可以直接转化为Instant,并且不同的ZonedDateTime可能会生成同样的Instant。
System.out.println(Instant.ofEpochMilli(System.currentTimeMillis()));
System.out.println(LocalDateTime.of(2017,12,13,10,0,0,0));
System.out.println(ZonedDateTime.of(2017,12,13,10,0,0,0,ZoneId.systemDefault()));
输出:
2017-12-13T06:22:06.581Z
2017-12-13T10:00
2017-12-13T10:00+08:00[Asia/Shanghai]
System.out.println(Instant.now()); //世界标准时间
System.out.println(LocalDateTime.now()); //会把世界标准时间转换为本时区的时间,但是时区信息会被丢弃
System.out.println(ZonedDateTime.now()); //会把世界标准时间转换为本时区的时间,但是时区信息会被保留
System.out.println(LocalDateTime.now(ZoneId.of("+00:00"))); //0时区的现在时间
System.out.println(ZonedDateTime.now(ZoneId.of("+00:00"))); //0时区的现在时间
输出:
2017-12-14T02:53:05.830Z
2017-12-14T10:53:05.904
2017-12-14T10:53:05.906+08:00[Asia/Shanghai]
2017-12-14T02:53:05.906
2017-12-14T02:53:05.906Z
System.out.println(Instant.parse("2007-12-03T10:15:30Z")); //只能解析这种格式,不能自己指定
System.out.println(LocalDateTime.parse("2017-12-13 11:51:12.083", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
System.out.println(ZonedDateTime.parse("2017-12-13 11:51:12.083 +04:30", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS ZZZZZ")));
输出:
2007-12-03T10:15:30Z
2017-12-13T11:51:12.083
2017-12-13T11:51:12.083+04:30
Instant instant=Instant.now();
LocalDateTime localDateTime=LocalDateTime.ofInstant(instant,ZoneId.systemDefault());
ZonedDateTime zonedDateTime=ZonedDateTime.ofInstant(instant,ZoneId.systemDefault());
System.out.println(instant);
System.out.println(localDateTime);
System.out.println(zonedDateTime);
System.out.println(ZoneOffset.systemDefault());
System.out.println(ZoneOffset.UTC);
System.out.println(ZoneOffset.MIN);
System.out.println(ZoneOffset.of("+08:00"));
System.out.println(localDateTime.toInstant(ZoneOffset.UTC)); //在把LocalDateTime转换为Instant时,需要明确指定当前这个时间指的是那个时区的时间
System.out.println(localDateTime.toInstant(ZoneOffset.of("+08:00")));
System.out.println(zonedDateTime.toInstant());
输出:
2017-12-14T01:50:26.098Z
2017-12-14T09:50:26.098
2017-12-14T09:50:26.098+08:00[Asia/Shanghai]
Asia/Shanghai
Z
-18:00
+08:00
2017-12-14T09:50:26.098Z
2017-12-14T01:50:26.098Z
2017-12-14T01:50:26.098Z
Instant instant=Instant.now();
LocalDateTime localDateTime=LocalDateTime.ofInstant(instant,ZoneId.systemDefault());
ZonedDateTime zonedDateTime=ZonedDateTime.ofInstant(instant,ZoneId.systemDefault());
System.out.println(instant);
System.out.println(localDateTime);
System.out.println(zonedDateTime);
System.out.println(ZonedDateTime.of(localDateTime,ZoneId.systemDefault())); //LocalDateTime转ZonedDateTime
System.out.println(zonedDateTime.toLocalDateTime()); //ZonedDateTime转LocalDateTime
输出:
2017-12-14T02:01:45.145Z
2017-12-14T10:01:45.145
2017-12-14T10:01:45.145+08:00[Asia/Shanghai]
2017-12-14T10:01:45.145+08:00[Asia/Shanghai]
2017-12-14T10:01:45.145
时区转换时要特别注意的是:用户输入的String类型的时间是没有时区信息的,需要人为指定解析。
解析的步骤分2步:
因为存在时区的概念,所以会造成2个问题:
LocalDateTime.now()
时,返回的结果并不同,如果操作不当很容易出现问题;JAVA API系列----日期和时间相关的类
【总结】java.util.Date vs. java.sql.Date
java.util.Date、java.sql.Date、java.sql.Time、java.sql.Timestamp区别和总结
时区转换:java new Date() 变成GMT&& GMT时间与CST时间转换
Date对象中,有一个默认时区,取得是操作系统的默认时区。可以通过下面的代码进行修改:
TimeZone.setDefault(TimeZone.getTimeZone("GMT")); // 将默认时区转化为GMT时区
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));// 将默认时区转化为东八区时区
新旧时间API连接的桥梁是Date类和Instant类,这两个都是世界标准时间,但是Date打印的时候会转化为本地时间。
Date date=Date.from(Instant.now());
Instant instant=date.toInstant();
System.out.println(date);
System.out.println(date.getTime()); //1
System.out.println(instant);
System.out.println(instant.toEpochMilli()); //2
输出:
Thu Dec 14 11:45:58 CST 2017
1513223158588
2017-12-14T03:45:58.588Z
1513223158588
注释1、2输出相同,说明Date类和Instant类是等价的;
请参考此文:Java8中计算日期时间差,为查阅方便整理记录如下。
在Java8中,我们可以使用以下类来计算日期时间差异:
1.Period: 主要是Period类方法getYears(),getMonths()和getDays()来计算.
2.Duration: 提供了使用基于时间的值(如秒,纳秒)测量时间量的方法。
3.ChronoUnit: ChronoUnit类可用于在单个时间单位内测量一段时间,例如天数或秒。
java.sql.Timestamp
接收java.sql.Date
接收java.util.Date
接收自己编写convert类,并注册到spring框架中
参见:
[1] springboot Date解析String类型的参数
[2] @DateTimeFormat格式化JSON日期时间(Date或timestamp)无效的原因 / Spring格式化json日期时间(Date或timestamp)的方法
自己编写可以作为参数的时间类
参见:Annotation Type QueryParam
被@QueryParam注解的参数,必须满足一下条件中的一个:
- 原始类型
- 有一个构造函数接受一个String参数
- 有一个名为valueOf或fromString的静态方法,它接受一个String参数(例如,参见Integer.valueOf(String))
- 列表< T>,< T>或SortedSet T,其中T满足上述2或3。生成的集合是只读的。