一、时间数据的并发处理
java.text.SimpleDateFormat 的实例对象在多线程共享使用的时候会抛出转换异常,可以使用ThreadLocal,但是也会导致其它问题。在JDK8以前,大多是使用Joda-Time
作为时间的解决方案。但是,从 Java SE 8 开始,Joda-Time的官方就要求用户迁移到java.time
(JSR-310) - 替代该项目的 JDK core部分。
在JDK8中,提供了许多线程安全的时间类,例如:
- 本地日期和时间:
LocalDateTime
,LocalDate
,LocalTime
; - 带时区的日期和时间:
ZonedDateTime
; - 时刻:
Instant
; - 时区:
ZoneId
,ZoneOffset
; - 时间间隔:
Duration
。 - 格式化:
DateTimeFormatter
其中,DateTimeFormatter
是SimpleFormatter的替代方案。
二、ISO 8601
国际标准ISO 8601,是国际标准化组织的日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。目前是2004年12月1日发行的第三版“ISO8601:2004”以替代1998年的第一版“ISO8601:1998”与2000年的第二版“ISO8601:2000”。
常用的表示法
- 日历日期表示法
- 年为4位数,月为2位数,月中的日为2位数,例如,日期(2021年12月16日)可表示为2021-12-16,或20211216。
- 顺序日期表示法
- 可以将一年内的天的序数用3位数字表示,平年365天,闰年366天。如2021年12月16日可以表示为2021-350或2021350
- 星期日历表示法
- 年为4位数,用两位表示年内的第几个星期(星期前要加上一个大写字母W),用一位表示星期内的第几天。如
2021年12月16日
可以表示为2021-W50-4
。
- 年为4位数,用两位表示年内的第几个星期(星期前要加上一个大写字母W),用一位表示星期内的第几天。如
- 日历星期表示法
- 与
星期日历表示法
类似,只是少了一位数用于表示第几天
- 与
- 日历月表示法
- 用2位数表示本年内第几个日历月。例如,日期(2021年12月16日)可表示为2021-12
- 日历年表示法
- 例如,如2021年可写成:2021
- 时间表示法
- 使用冒号":"间隔开小时、分、秒的为扩展格式。小时、分和秒都用2位数表示。如果时间在零时区,并恰好与协调世界时相同,那么还需要在最后添加一个大写的
Z
。例如15:30:53Z
; - 其他时区用实际时间加时差表示,当时的UTC+8时间表示为15:30:53+08:00或153053+0800,也可以简化成153053+08.
- 使用冒号":"间隔开小时、分、秒的为扩展格式。小时、分和秒都用2位数表示。如果时间在零时区,并恰好与协调世界时相同,那么还需要在最后添加一个大写的
协调世界时(Coordinated Universal Time)是世界上调节时钟和时间的主要时间标准,它与0度经线的平太阳时相差不超过1秒。如果本地时间比UTC时间快,例如中国大陆[注 1]、香港、澳门、台湾、蒙古国、菲律宾、新加坡、马来西亚、澳大利亚西部的时间比UTC快8小时,就会写作UTC+8,俗称东八区。相反,如果本地时间比UTC时间慢,例如夏威夷的时间比UTC时间慢10小时,就会写作UTC-10,俗称西十区。
三、DateTimeFormatter 的使用
DateTimeFormatter用于打印和解析日期时间对象的格式化程序,而更复杂的格式可以由DateTimeFormatterBuilder
进行处理。
预定义变量
为时间对象提供了预设格式,如下所示:
常量 | 描述 | 实例 |
---|---|---|
ISO_DATE | ISO日期,可带偏移量 |
2021-12-07 或 2021-12-07+01:00 |
ISO_DATE_TIME | 带 ZoneId 的日期和时间 | 2021-12-07T09:50:46、2021-12-07T09:50:46+01:00、2021-12-07T09:50:46+01:00[Europe/Paris] |
ISO_TIME | ISO时间,可带偏移量 |
15:30、15:30+01:00 |
ISO_INSTANT | 通过 UTC 格式进行格式化或解析的即时ISO日期 | 2021-12-07T09:50:46Z |
ISO_LOCAL_DATE | ISO 本地日期 | 2021-12-07 |
ISO_LOCAL_DATE_TIME | ISO 本地日期和时间 | 2021-12-07T09:50:46 |
ISO_LOCAL_TIME | ISO 本地时间 | 09:50:46 |
ISO_OFFSET_DATE | 带偏移量 的 ISO 日期 |
2021-12-07+01:00 |
ISO_OFFSET_DATE_TIME | 带偏移量的 ISO 日期与时间 | 2021-12-07T09:50:46+01:00 |
ISO_OFFSET_TIME | 带偏移量的 ISO 时间 | 09:50:46+01:00 |
ISO_ORDINAL_DATE | 用于表示年 与年内的第几天 |
2021-341 |
ISO_WEEK_DATE | 年和周 | 2021-W49-2 |
ISO_ZONED_DATE_TIME | 分区日期时间 | 2021-12-07T09:50:46+01:00[Europe/Paris] |
实例
查询日期与时间:
LocalDate d = LocalDate.now(); // 当前日期
LocalTime t = LocalTime.now(); // 当前时间
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
复制代码
Date 转换为 LocalDateTime:
public static void main(String[] args) {
System.out.println(Instant.ofEpochMilli(new Date().getTime())
.atZone(ZoneId.systemDefault())
.toLocalDateTime());
}
复制代码
Date 转换为 LocalDate、LocalTime:
public static void main(String[] args) {
System.out.println(Instant.ofEpochMilli(new Date().getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate());
System.out.println(Instant.ofEpochMilli(new Date().getTime())
.atZone(ZoneId.systemDefault())
.toLocalTime()
);
}
复制代码
LocalDate转换为Date:
public Date convertLocalDateToDate(LocalDate localDate) {
return java.sql.Date.valueOf(localDate);
}
复制代码
localDateTime转换为Date
public Date convertLocalDateTimeToDate(LocalDateTime localDateTime) {
return java.sql.Timestamp.valueOf(localDateTime);
}
复制代码
获取当前时间(秒)的时间戳:
public static long getNowSecond() {
return LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
}
复制代码