大部分Java程序员用得最多的时候就是Date,诚然,Date足够应付大部分场景。但是最不爽的就是DateFormat的线程不安全。每次在多线程场景下,我就会处于一种纠结状态,到底要用并发还是使用新的Java Api来解决这个问题。所以决定系统学习Java的日期和时间API。
Java的日期和时间API出了三个版本,如下所示,其中Date在Java1.0引进,Calendar在Java1.1引进,LoacalDate等是在Java8引进的。
- Date
- Calendar
- LocalDate、LocalDateTime等
Java8的时间表示主要通过四个类,LocalDate,LocalTime,LocalDateTime,Instant。他们支持很多Date没有的操作,如加一个小时等等,下面介绍其用法。
LocalDateTime
我们先看下LocalDateTime,它和Date类是最像的,可以同时表示日期(年月日)和时间(时分秒),其核心是两个字段,一个LocalDate对象和一个LocalTime对象。LocalDateTime没有public的构造函数,一般通过如下LocalDateTime.of()
、LocalDateTime.now()
来创建,其中now()
支持无参,of()
需要指定参数(如年月日时分秒),也可以通过LocalDateTime.parse()
解析字符串获得。下面介绍常见用法,具体看源码或者API。
代码:
import java.time.LocalDateTime;
public class LocalDateTimeTest {
public static void main(String[] args) {
// 通过of()和now()创建LocalDateTime对象
LocalDateTime localDateTime1 = LocalDateTime.now();
LocalDateTime localDateTime2 = LocalDateTime.of(2020, 4, 1, 0, 0, 0);
// 通过LocalDate和LocalTime的toString拼接而来的,通过T分隔
// LocalTime的秒0为时则省略
String dateTimeStr1 = localDateTime1.toString();
System.out.println(dateTimeStr1);
System.out.println(localDateTime2);
// 解析格式化的日期,比SimpleDateFormat用起来简单多了
// 解析后用equals判断为true
LocalDateTime localDateTime3 = LocalDateTime.parse(dateTimeStr1);
System.out.println(localDateTime3.equals(localDateTime1));
}
}
输出:
2020-03-29T23:39:23.744
2020-04-01T00:00
true
LocalDateTime是通过LocalDate和LocalTime对象组合的,所以他们之间有互相转换,有兴趣可以多多了解
Instant
而Instant直译"瞬时",明显它用于表达精确时间。Date可以表达到毫秒,而Instant可以表达到纳秒。可通过now
,ofEpochMilli
,ofEpochSecond
三种方法创建
代码:
import java.time.Instant;
public class InstantTest {
public static void main(String[] args) {
// 当前时间
Instant instant1 = Instant.now();
// 指定毫秒时间戳
Instant instant2 = Instant.ofEpochMilli(1585497442630L);
// 指定秒级时间戳和纳秒,纳秒不传默认为0。注意第二个参数的单位是纳秒,这里用 毫秒 * 100^6
Instant instant3 = Instant.ofEpochSecond(1585497442, 630 * 1000_000);
System.out.println(instant1);
System.out.println(instant2.equals(instant3));
}
}
输出
2020-03-29T16:04:02.079Z
true
日期和时间上的操作
修改时间
LocalDateTime可以通过with
开头的方法来指定年月日时分秒,如withYear
将会返回一个年份不同的对象。同时还可以通过plus
和minus
开头的方法来加减时间,这比Date好用多了。。。
代码:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class DateTimeOperateTest {
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.plusWeeks(1));
// LocalDateTime本身是一个没有时区的概念,可以认为只是记录了年月日时分秒这几个数字
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
// 获取timestamp
System.out.println(instant.toEpochMilli());
}
}
输出:
2020-04-06T01:41:11.303
1585503671303
格式化输出和解析时间
格式化输出和解析时间算是Java程序员对时间最常见的操作了,通过java.time.format.DateTimeFormatter
来实现格式化和解析,相比DateFormat而言,它是线程安全的,可以省去为DateFormat添加ThreadLocal。DateTimeFormatter内置了一些常用的日期格式
代码:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterTest {
public static void main(String[] args) {
// 自带的日期时间格式化器
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
// 自定义格式化器
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
LocalDateTime localDateTime = LocalDateTime.now();
String timeStr1 = localDateTime.format(dateTimeFormatter1);
String timeStr2 = localDateTime.format(dateTimeFormatter2);
System.out.println(timeStr1);
System.out.println(timeStr2);
System.out.println(LocalDateTime.parse(timeStr1, dateTimeFormatter1).equals(
LocalDateTime.parse(timeStr2, dateTimeFormatter2)));
}
}
输出:
2020-03-30T00:42:34.81
2020-03-30 00:42:34.810
true
网友评论