跳转页尾1
获取当前时间:
ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间:" + now.format(formatter));
当前时间:2020-07-08 16:32:35
作为开发者,经常需要处理日期时间。如果你跟随者 Java 5 一路走来,那么一定会对
java.util.Date
、java.util.Calendar
、java.util.GregoiranCalendar
和java.text.SimpleDateFormat
四大类非常熟悉,它们分别用于处理日期、日历、日历表示、日期时间格式化
这四个类,对于编程老人来讲,应该是习惯了,但对于编程新人来讲,就有好多疑问,有好多陷阱和坑等着它们跳,比如:
非线程安全:java.util.Date 并不是线程安全的。开发者在使用这个类时必须自己处理多线程并发问题。
设计不佳:一方面日期和日期格式化分布在多个包中。另一方面,java.util.Date 的默认日期,年竟然是从
1900
开始,月从1
开始,日从0
开始,没有统一性。而且Date
类也缺少直接操作日期的相关方法。时区处理困难:因为设计不佳,开发人员不得不编写大量代码来处理时区问题。
还有其它一些问题
面对种种问题,Java 8 终于重新设计了所有日期时间、日历及时区相关的 API。并把它们都统一放置在 java.time 包和子包下。并作出了以下改进:
- 新的日期时间 API 是线程安全的。不仅没有 setter 方法,而且任何对实例的变更都会返回一个新的实例而保证原来的实例不变。
- 新的日期时间 API 提供了大量的方法,用于修改日期时间的各个部分,并返回一个新的实例。
- 在时区方面,新的日期时间 API引入了 域 ( domain ) 这个概念。
本地日期时间 API(一)
Java 8 为处理本地的日期时间提供了三个类 LocalDate 、LocalTime 和 LocalDateTime。分别用于处理 本地日期、本地时间 和 本地日期时间。
比如,可以使用 LocalDateTime.now()
方法返回当前的日期时间。
//import java.time.LocalDateTime;
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前时间日期:" + currentTime);
运行结果如下
当前时间日期:2020-07-08T09:53:56.153
比如,我们可以调用 LocalDateTime
对象的 toLocalDate()
方法和 toLocalTime()
分别返回当前的日期和当前的时间,也就是 LocalDate
和 LocalTime
两个类的实例
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前日期时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("当前日期: " + date1);
LocalTime time1 = currentTime.toLocalTime();
System.out.println("当前时间: " + time1);
运行结果如下
当前日期时间: 2020-07-08T10:01:37.870
当前日期: 2020-07-08
当前时间: 10:01:37.870
比如我们可以调用 LocalDateTime
对象的 getMonth()
方法返回当前的月份,调用 getDayOfMonth()
返回当前的日期,调用 getSecond()
返回当前时间的秒数
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前日期时间: " + currentTime);
Month month = currentTime.getMonth();
System.out.println("当前月份: " + month);
int day = currentTime.getDayOfMonth();
System.out.println("当前月中的第几天: " + day);
int seconds = currentTime.getSecond();
System.out.println("当前秒数: " + seconds);
运行结果如下
当前日期时间: 2020-07-08T11:06:08.962
当前月份: JULY
当前月中的第几天: 8
当前秒数: 8
比如我们可以调用 LocalDateTime
对象的 withDayOfMonth()
修改日并返回一个新的实例,调用 withYear()
修改年,调用其它 with*
方法修改其它属性。
这些 with
方法都是返回新的实例,而原来的实例并不会改变。
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前日期时间: " + currentTime);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("新的日期时间: " + date2);
System.out.println("原来的日期时间: " + currentTime);
运行结果如下
当前日期时间: 2020-07-08T11:09:57.747
新的日期时间: 2012-07-10T11:09:57.747
原来的日期时间: 2020-07-08T11:09:57.747
可以发现原先的实例并没有被修改。
同时,新的日期时间 API 还大量引入了 of()
方法,比如我们可以调用 LocalDate.of()
方法创建一个日期实例,调用 LocalTime.of()
方法创建一个时间实例。
LocalDate date = LocalDate.of(2020, Month.JULY, 8);
System.out.println("日期是: " + date);
// 22:15
LocalTime time = LocalTime.of(22, 15);
System.out.println("时间是: " + time);
运行结果如下
日期是: 2020-07-08
时间是: 22:15
我们还可以调用 LocalDateTime.parse()
、LocalDate.parse()
和 LocalTime.parse()
方法解析字符串格式的日期时间、日期和时间。
LocalDateTime datetime = LocalDateTime.parse("2012-10-10T21:58:00");
System.out.println("日期时间是:" + datetime);
LocalDate date = LocalDate.parse("2012-10-10");
System.out.println("日期是: " + date);
LocalTime time = LocalTime.parse("21:58:01");
System.out.println("时间是: " + time);
运行结果如下
日期时间是:2012-10-10T21:58
日期是: 2012-10-10
时间是: 21:58:01
本地日期时间 API(二)
以上对 Java 8 重新设计的日期时间 API 做了一些基础的介绍,同时详细介绍了和本地时间有关的几个类
LocalDateTime
、LocalDate
和LocalTime
。
我同时也发现,这三个类没有任何时区相关的信息,但也不能说它们没处理时区,而只能说它们有选择的隐藏了时区的处理。它们内部会使用操作系统当前的时区。
以此同时,Java 在java.time
包中也提供了几个类用于处理需要关注时区的日期时间 API。它们是java.time.ZonedDateTime
和java.time.ZoneId
。前者用于处理需要时区的日期时间,后者用于处理时区。
ZonedDateTime
和 LocalDateTime
类似,几乎有着相同的 API。从某些方面说,ZonedLocalTime
如果不传递时区信息,那么它会默认使用操作系统的时区,这样,结果其实和 LocalDateTime
是类似的。
比如,我们可以使用 ZonedDateTime
的 now()
方法返回当前时区 ( 操作系统时区 ) 的日期时间,调用parse()
方法可以将一个包含了时区信息的字符串格式的日期时间转化为一个 ZonedDateTime
实例。
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前日期时间是:" + now);
ZonedDateTime datetime = ZonedDateTime.parse("2020-07-08T15:48:37.404+08:00");
System.out.println("日期时间是:" + datetime);
运行结果如下
当前日期时间是:2020-07-08T15:49:18.571+08:00[Asia/Shanghai]
日期时间是:2020-07-08T15:48:37.404+08:00
我们还可以调用
ZonedDateTime
对象的toLocalDate()
和toLocalTime()
方法将获取该实例的转换为本地的日期和时间
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前日期时间是:" + now);
LocalDate date = now.toLocalDate();
System.out.println("本地日期是:" + date);
LocalTime time = now.toLocalTime();
System.out.println("本地时间是:" + time);
运行结果如下
当前日期时间是:2020-07-08T15:51:10.643+08:00[Asia/Shanghai]
本地日期是:2020-07-08
本地时间是:15:51:10.643
P.S 这个返回值好诡异,为啥
toLocalDate()
还返回了时间?
处理时区
时区相关的信息,我们可以使用
ZoneId
类来处理。
比如可以调用 ZoneId
类的静态方法systemDefault()
返回当前的时区。
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当前时区是: " + currentZone);
运行结果为
当前时区是: Asia/Shanghai
我们还可以调用 ZonedDateTime
实例的 getZone()
方法获取实例所在的时区
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前时区是: " + now.getZone());
运行结果如下
当前时区是: Asia/Shanghai
本地日期时间 API(三)
Java 8 似乎也对java.text.SimpleDateFormat
也不太满意,竟然重新创建了一个java.time.format
包,该包下包含了几个类和枚举用于格式化日期时间。
java.time.format 包
java.time.format
包提供了以下几个类用于格式化日期时间
项目 | 说明 |
---|---|
DateTimeFormatter | 用于打印和解析日期时间对象的格式化程序 |
DateTimeFormatterBuilder | 创建日期时间格式化样式的构建器 |
DecimalStyle | 日期和时间格式中使用的本地化十进制样式 |
java.time.format
包还提供了以下几个枚举,包含了常见的几种日期时间格式。
枚举 | 说明 |
---|---|
FormatStyle | 包含了本地化日期,时间或日期时间格式器的样式的枚举 |
ResolverStyle | 包含了解决日期和时间的不同方法的枚举 |
SignStyle | 包含了如何处理正/负号的方法的枚举 |
TextStyle | 包含了文本格式和解析的样式的枚举 |
DateTimeFormatter 类
DateTimeFormatter
类格式化日期时间的最重要的类,该类是一个最终类,只能实例化,不能被扩展和继承。
DateTimeFormatter
类的定义如下
public final class DateTimeFormatter extends Object
DateTimeFormatter
类用于打印和解析日期时间对象的格式化器。此类提供打印和解析的主要应用程序入口点,并提供DateTimeFormatter
的常见模式
- 使用预定义的常量,比如
ISO_LOCAL_DATE
- 使用模式字母,例如
uuuu-MMM-dd
- 使用本地化样式,例如
long
或medium
- 所有的日期时间类,包括本地日期时间和包含时区的日期时间类,都提供了两个重要的方法
1、 一个用于格式化,format(DateTimeFormatter formatter)
2、 另一个用于解析,parse(CharSequence text DateTimeFormatter formatter)
下面,我们写几个示例来演示下这两个方法,并演示下如和使用 DateTimeFormatter 类
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前时间是: " + now);
System.out.println("另一种表示形式:" + now.format(DateTimeFormatter.RFC_1123_DATE_TIME));
运行结果是
当前时间是: 2020-07-08T16:23:58.164+08:00[Asia/Shanghai]
另一种表示形式:Wed, 8 Jul 2020 16:23:58 +0800
我们还可以调用 DateTimeFormatter.ofPattern() 方法创建自己的日期时间格式,例如
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前时间是: " + now);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd H:m:s");
System.out.println("另一种表示形式:" + now.format(formatter));
运行结果如下
当前时间是: 2020-07-08T16:29:21.546+08:00[Asia/Shanghai]
另一种表示形式:2020/07/08 16:29:21
当然了,我们可以调用 LocalDateTime 类的静态方法 parse() 将我们刚刚自定义的日期时间格式给解析回来
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前时间是: " + now);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String text = now.format(formatter);
System.out.println("另一种表示形式:" + text );
LocalDateTime parsed = LocalDateTime.parse(text, formatter);
System.out.println("解析后:" + parsed );
运行结果如下
当前时间是: 2020-07-08T16:35:49.110+08:00[Asia/Shanghai]
另一种表示形式:2020-07-08 16:35:49
解析后:2020-07-08T16:35:49
获取当前时间代码查看 ↩︎