第三代日期类(JDK8)
LocalDateTime
LocalDateTime:日期时间 / 年月日时分秒(LocalDate:日期 / 年月日、LocalTime:时间 / 时分秒)
表示本地日期和时间。
默认严格按照 ISO 8601 规定的日期和时间格式进行打印。
ISO 8601 规定的日期和时间分隔符是T。标准格式如下:
- 日期:yyyy-MM-dd
- 时间:HH:mm:ss
- 带毫秒的时间:HH:mm:ss.SSS
- 日期和时间:yyyy-MM-dd’T’HH:mm:ss
- 带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS
自定义格式打印需要使用DateTimeFormatter类。
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| LocalDateTime.now()
LocalDateTime dt2 = LocalDateTime.of(2019, 11, 30, 15, 16, 17);
LocalDateTime plusYearsResult = localDateTime.plusYears(2L);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String dateTime = LocalDateTime.now().format(formatter);
String dateTimeStr = "2023-10-30 09:48:11"; DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, dtf);
LocalDateTime.now().toInstant();
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
|
格式化类型,取代了SimpleDateFormat。
示例一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt);
LocalDate d2 = LocalDate.of(2017, 1, 29); LocalTime t2 = LocalTime.of(15, 16, 17); LocalDateTime dt2 = LocalDateTime.of(2017, 1, 29, 15, 16, 17); LocalDateTime dt3 = LocalDateTime.of(d2, t2); System.out.println(dt2);
System.out.println("年:" + ldt.getYear()); System.out.println("月:" + ldt.getMonthValue());
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒"); String format = dtf.format(ldt); System.out.println("格式化后:" + format);
LocalDateTime localDateTime = ldt.plusDays(180); System.out.println("180天后的现在 = " + dtf.format(localDateTime));
LocalDateTime localDateTime1 = ldt.minusMinutes(3456); System.out.println("3456分钟前是 = " + dtf.format(localDateTime1));
|
时区(ZoneDateTime)
LocalDateTime总是表示本地日期和时间,要表示一个带时区的日期和时间,我们就需要ZonedDateTime。
可以简单地把ZonedDateTime理解成LocalDateTime加ZoneId。ZoneId是java.time引入的新的时区类。
创建ZoneDateTime对象的两种方式:
1 2 3 4 5 6 7 8 9 10 11 12
| ZonedDateTime zbj = ZonedDateTime.now(); ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); System.out.println(zbj); System.out.println(zny);
LocalDateTime ldt = LocalDateTime.of(2019, 9, 15, 15, 16, 17); ZonedDateTime zbj2 = ldt.atZone(ZoneId.systemDefault()); ZonedDateTime zny2 = ldt.atZone(ZoneId.of("America/New_York")); System.out.println(zbj2); System.out.println(zny2);
|
时间、日期差(Duration 和 Period)
Duration表示两个时刻之间的时间间隔。Period表示两个日期之间的天数:
1 2 3 4 5 6 7
| LocalDateTime start = LocalDateTime.of(2020, 8, 1, 19, 48, 0); LocalDateTime end = LocalDateTime.of(2022, 7, 5, 19, 48, 30); Duration d = Duration.between(start, end); System.out.println(d);
Period p = LocalDate.of(2020, 8, 1).until(LocalDate.of(2022, 7, 5)); System.out.println(p);
|
代码解释:两个LocalDateTime之间的差值使用Duration表示,PT16872H30S表示16872小时30秒。而两个LocalDate之间的差值用Period表示,P1Y11M4D表示1年11个月4天。
Duration和Period的表示方法也符合ISO 8601的格式,它以P...T...的形式表示。
时间戳(Instant)
Java提供的System.currentTimeMillis()返回的就是以毫秒(long类型)表示的当前时间戳。
这个当前时间戳在java.time中以Instant类型表示,我们用Instant.now()获取当前时间戳,效果和System.currentTimeMillis()类似
实际上,Instant内部只有两个核心字段:
1 2
| private final long seconds; private final int nanos;
|
Instant是时间戳,那么,给它附加上一个时区,就可以创建出ZonedDateTime:
1 2 3
| Instant ins = Instant.ofEpochSecond(1568568760); ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault()); System.out.println(zdt);
|
可见,对于某一个时间戳,给它关联上指定的ZoneId,就得到了ZonedDateTime,继而可以获得了对应时区的LocalDateTime。
LocalDateTime,ZoneId,Instant,ZonedDateTime和long都可以互相转换:

第二代日期类
Calendar类(JDK1.1引入)
1)是一个抽象类,并且构造器是private
2)可以通过getInstance()方法来获取实例
3)Calendar没有提供对应的格式化的类,需要开发者自己组合显示
1 2 3 4 5 6 7 8 9 10 11 12 13
| Calendar c = Calendar.getInstance(); System.out.println(c);
System.out.println("年:" + c.get(Calendar.YEAR)); System.out.println("月:" + (c.get(Calendar.MONTH) + 1)); System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH)); System.out.println("时:" + c.get(Calendar.HOUR)); System.out.println("分:" + c.get(Calendar.MINUTE)); System.out.println("秒:" + c.get(Calendar.SECOND));
System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH) + " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND));
|
前两代的不足
Date类的大多数方法已经在引入Calendar类后被弃用。
(1)可变性:像日期和时间这样的类应该是不可变的;
(2)偏移性:Date中年份是从1900开始,而月份都从0开始;
(3)格式化:格式化类只支持Date,不支持Calendar;
(4)其他:线程不安全、不能处理闰秒等(每隔2天,多出1s)
第一代日期类
Date类(JDK1.0引入)
精确到毫秒,代表特定的瞬间
允许进行格式化(日期 -> 文本)、解析(文本 -> 日期)和规范化
示例
获取当前系统时间
1 2 3 4 5 6 7 8
| Date date1 = new Date(); System.out.println("当前日期 = " + date1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E"); String format = sdf.format(date1); System.out.println("当前日期 = " + format);
|
把一个格式化的 String 转成对应的 Date
在把String -> Date时,使用的sdf格式需要和给定的String格式一致,否则会抛出转换异常
1 2 3 4 5
| String s = "2022年07月05日 03:49:28 星期二"; Date parse = sdf.parse(s);
System.out.println("parse = " + parse); System.out.println("format_parse = " + sdf.format(parse));
|
通过指定毫秒数得到日期时间
1 2
| Date date2 = new Date(999999999); System.out.println(date2);
|
其他
ISO 8601规定的日期和时间分隔符是T。标准格式如下:
- 日期:yyyy-MM-dd
- 时间:HH:mm:ss
- 带毫秒的时间:HH:mm:ss.SSS
- 日期和时间:yyyy-MM-dd’T’HH:mm:ss
- 带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS