共计 17420 个字符,预计需要花费 44 分钟才能阅读完成。
前言
在 Java 8 中,整合了许多 Joda-Time
的个性而开发的 java.time
反对全新的日期和工夫 API。Date-Time API 由主包 java.time
和四个子包组成:
包名 | 形容 |
---|---|
java.time | 日期,工夫,霎时和持续时间的次要 API。基于 ISO-8601 中定义的日历零碎,并且不可变且线程平安 |
java.time.chrono | 除默认 ISO 之外的日历零碎的 API |
java.time.format | 格式化和解析日期和工夫的类 |
java.time.temporal | 扩大 API,容许日期和工夫类之间互操作,查问和调整 |
java.time.zone | 反对时区、时区的偏移以及时区规定 |
上面咱们一起摸索新的日期和工夫 API 所提供的新个性。
日期工夫类
日期工夫 API 提供四个专门解决日期信息的类,不思考工夫或时区。
LocalDate
从 LocalDate
类的申明中能够看出:
public final class LocalDate | |
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable |
LocalDate
被 final
润饰,是一个不可变的日期对象。它是 ISO-8601
日历零碎的实现。LocalDate
类提供简略的日期,并不蕴含时区与工夫信息。
LocalDate
能够应用 now()
、now(ZoneId zone)
和 now(Clock clock)
三个静态方法来获取以后日期:
public static void main(String[] args) { | |
// 获取的是零碎默认时区的日期 | |
LocalDate now = LocalDate.now(); | |
System.out.println(now); | |
// 传入的是亚洲 / 上海的时区 | |
LocalDate nowWithZoneId = LocalDate.now(ZoneId.of("Asia/Shanghai")); | |
System.out.println(nowWithZoneId); | |
// 传入的时钟对象的时区为 UTC | |
LocalDate nowWithClock = LocalDate.now(Clock.systemUTC()); | |
System.out.println(nowWithClock); | |
} | |
/** | |
* 输入后果:* 2020-07-15 | |
* 2020-07-15 | |
* 2020-07-14 | |
*/ |
由此可见,咱们设置了时区后的输入是以后时区的日期,然而不显示时区等信息。除了以后日期,还能够应用静态方法 of()
创立 LocalDate
实例:
public static void main(String[] args) { | |
// 依据传入的年月日获取 LocalDate 实例(月份是 Java 封装的枚举类)LocalDate date1 = LocalDate.of(1997, Month.MAY, 31); | |
System.out.println(date1); | |
// 依据传入的年月日获取 LocalDate 实例(月份是本人输出的数字)LocalDate date2 = LocalDate.of(1997, 5, 31); | |
System.out.println(date2); | |
} | |
/** | |
* 输入后果:* 1997-05-31 | |
* 1997-05-31 | |
*/ |
输入后果一样,然而参数一个是枚举,一个是数字,这是因为 of(int year, Month month, int dayOfMonth)
实现中,还是会把 Month
枚举转换为月份的数字。
创立了 LocalDate
实例后,咱们能够依据该实例获取年份、月份、星期等日期信息。
// 依据传入的工夫字段获取年月日等信息 | |
public int get(TemporalField field); -> 例子:date.get(ChronoField.YEAR); | |
// 获取年份 | |
public int getYear(); | |
// 获取月份 | |
public int getMonthValue(); | |
// 获取以后月份的第几天 | |
public int getDayOfMonth(); | |
// 获取星期 | |
public DayOfWeek getDayOfWeek(); | |
// 判断是否为平年 | |
public boolean isLeapYear(); |
LocalDate
类还有很多办法,就不一一列举了。
LocalTIme
从 LocalTime
的申明:
public final class LocalTime | |
implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable |
也能够看出,LocalTime
也是被 final
润饰的不可变的工夫对象,LocalTime
能够示意 hh:mm:ss.SSSZ
。工夫精度能够示意到纳秒。
LocalTime
也有获取以后工夫的静态方法:
public static void main(String[] args) { | |
// 应用时钟的默认时区获取以后 LocalTime 实例 | |
LocalTime timeOfTime = LocalTime.now(); | |
System.out.println(timeOfTime); | |
// 获取指定时区的以后 LocalTime 实例 | |
LocalTime timeOfZone = LocalTime.now(ZoneId.of("Asia/Shanghai")); | |
System.out.println(timeOfZone); | |
// 获取指定时钟的以后 LocalTime 实例 | |
LocalTime timeOfClock = LocalTime.now(Clock.systemUTC()); | |
System.out.println(timeOfClock); | |
} | |
/** | |
* 输入后果:* 23:52:00.842133400 | |
* 23:52:00.843155500 | |
* 15:52:00.843155500 | |
*/ |
除了指定以后工夫,还能够应用 of()
指定以后小时、分钟、秒、纳秒来实例化:
public static LocalTime of(int hour, int minute) {...} | |
public static LocalTime of(int hour, int minute, int second) {...} | |
public static LocalTime of(int hour, int minute, int second, int nanoOfSecond) {...} |
还有指定秒数与纳秒数来实例化的静态方法:
public static LocalTime ofSecondOfDay(long secondOfDay) {...} | |
public static LocalTime ofNanoOfDay(long nanoOfDay) {...} |
创立了 LocalTime
实例后,咱们也能够获取该实例小时、分钟、形容和纳秒等信息。
// 依据传入的工夫字段获取小时、分钟、秒等信息 | |
public int get(ChronoField field); -> 例子;time.get(ChronoField.HOUR_OF_DAY) | |
// 获取小时 | |
public int getHour(); | |
// 获取分钟 | |
public int getMinute(); | |
// 获取秒数 | |
public int getSecond(); | |
// 获取纳秒数 | |
public int getNano(); |
LocalTime
类还有很多办法,就不一一列举了。
LocalDateTime
查看 LocalDateTime
的申明:
public final class LocalDateTime | |
implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable |
就晓得 LocalDateTime
以上两个示意日期与工夫的类都是被 final
润饰的不可变的工夫对象。它同时示意日期和工夫,但不带有时区信息,你能够通过 now()
与指定时区、时钟来创立以后日期工夫:
public static void main(String[] args) { | |
// 应用时钟的默认时区获取 LocalDateTime 实例 | |
LocalDateTime dateTimeOfNow = LocalDateTime.now(); | |
System.out.println(dateTimeOfNow); | |
// 获取指定时区的以后 LocalDateTime 实例 | |
LocalDateTime dateTimeOfZone = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); | |
System.out.println(dateTimeOfZone); | |
// 获取指定时钟的以后 LocalDateTime 实例 | |
LocalDateTime dateTimeOfClock = LocalDateTime.now(Clock.systemUTC()); | |
System.out.println(dateTimeOfClock); | |
} | |
/** | |
* 输入后果:* 2020-07-16T18:16:13.773716400 | |
* 2020-07-16T18:16:13.774713600 | |
* 2020-07-16T10:16:13.774713600 | |
*/ |
LocalDateTime
也能够指定年月日时分秒来实现实例化:
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) {...} | |
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) {...} | |
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {...} | |
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {...} | |
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) {...} | |
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {...} |
例子:
public static void main(String[] args) {LocalDateTime dateTimeOfYearMonthDay = LocalDateTime.of(2000, Month.AUGUST, 27, 18, 50, 52, 999999999); | |
System.out.println(dateTimeOfYearMonthDay); | |
} | |
/** | |
* 输入后果:* 2000-08-27T18:50:52.999999999 | |
*/ |
LocalDateTime
也能够应用 Instant
或 Epoch
新纪元进行实例化:
// 基于 Instant 刹时与时区实例化 | |
public static LocalDateTime ofInstant(Instant instant, ZoneId zone) {...} | |
// 基于新纪元偏移秒数、纳秒数和工夫偏移量获取 LocalDateTime 实例 | |
public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {...} |
例子:
public static void main(String[] args) {LocalDateTime dateTimeOfInstant = LocalDateTime.ofInstant(Instant.now(), ZoneId.of("UTC")); | |
System.out.println(dateTimeOfInstant); | |
LocalDateTime dateTimeOfEpoch = LocalDateTime.ofEpochSecond(2000, 999999, ZoneOffset.UTC); | |
System.out.println(dateTimeOfEpoch); | |
} | |
/** | |
* 输入后果:* 2020-07-16T11:08:56.669023800 | |
* 1970-01-01T00:33:20.000999999 | |
*/ |
同时,LocalDateTime
也能够接管一个实现了 TemporalAccessor
接口的工夫拜访器:
public static LocalDateTime from(TemporalAccessor temporal) {...}
例子:
public static void main(String[] args) {LocalDateTime dateTime = LocalDateTime.from(ZonedDateTime.now()); | |
System.out.println(dateTime); | |
} | |
/** | |
* 输入后果:* 2020-07-16T20:37:41.897717700 | |
*/ |
上述的实例化与 LocalDate
和 LocalTime
没有什么不同,然而 LocalDateTime
算是 LocalDate
与 LocalTime
的合体,同时示意日期工夫,因而能够应用 LocalDate
和 LocalTime
参数来获取 LocalDateTime
实例:
public static LocalDateTime of(LocalDate date, LocalTime time) {...}
例子:
public static void main(String[] args) {LocalDateTime dateTimeOfDateAndTime = LocalDateTime.of(LocalDate.of(2012, 10, 1), LocalTime.of(10, 10, 10, 921710211)); | |
System.out.println(dateTimeOfDateAndTime); | |
} | |
/** | |
* 输入后果:* 2012-10-01T10:10:10.921710211 | |
*/ |
也能够通过合并日期和工夫获取 LocalDateTime
实例:
public static void main(String[] args) {LocalDate date = LocalDate.of(2019, 11, 2); | |
LocalTime time = LocalTime.of(20, 10, 41, 123984321); | |
LocalDateTime dateTimeOfMerge = date.atTime(21, 55); | |
System.out.println(dateTimeOfMerge); | |
dateTimeOfMerge = time.atDate(date); | |
System.out.println(dateTimeOfMerge); | |
} | |
/** | |
* 输入后果:* 2019-11-02T21:55 | |
* 2019-11-02T20:10:41.123984321 | |
*/ |
Instant
java.time.Instant
类是对计算机工夫建模的形式,以 Unix
元年工夫(传统的设定为 UTC 时区1970-01-01T00:00:00Z
)开始所经验的秒数进行计算。它可测量的工夫线被限度在 long
类型的存储大小中。它存储的单位为纳秒(nanos,nanos 的取值范畴是[0,999_999_999])。如果早于该工夫,秒数为负值,晚于该工夫,秒数为负数。
Instant
能够通过静态方法 ofEpochSecond
创立该类的实例:
// 创立基于新纪元 epochSecond 秒后的刹时工夫点 | |
public static Instant ofEpochSecond(long epochSecond) {...} | |
// 创立基于新纪元 epochSecond 秒加上 nanoAdjustment 纳秒之后的刹时工夫点 | |
public static Instant ofEpochSecond(long epochSecond, long nanoAdjustment) {...} | |
// 创立基于新纪元 epochMilli 毫秒后的刹时工夫点 | |
public static Instant ofEpochMilli(long epochMilli) {...} |
例子:
public static void main(String[] args) { | |
// 从第三秒开始的工夫点 | |
Instant instant1 = Instant.ofEpochSecond(3); | |
System.out.println(instant1); | |
// 从第三秒 100211321 纳秒开始的工夫点 | |
Instant instant2 = Instant.ofEpochSecond(3, 100_211_321); | |
System.out.println(instant2); | |
// 从第三毫秒开始的工夫点 | |
Instant instant3 = Instant.ofEpochMilli(3); | |
System.out.println(instant3); | |
} | |
/** | |
* 输入后果:* 1970-01-01T00:00:03Z | |
* 1970-01-01T00:00:03.100211321Z | |
* 1970-01-01T00:00:00.003Z | |
*/ |
Instant
也反对应用跟 LocalDateTime
等类似的静态方法创立实例:
public static Instant now() {...} | |
public static Instant now(Clock clock) {...} | |
public static Instant from(TemporalAccessor temporal) {...} | |
public static Instant parse(CharSequence text) {...} |
Duration
上述的类都实现了 Temporal
接口,Temporal
接口定义了如何读取和操纵为工夫建模的对象的值。如果咱们须要两个 Temporal
对象之间的时间段,咱们就须要应用 Duration
来示意。Duration
类中有 seconds
与 nanos
两个字段,因而示意秒或纳秒的工夫距离。
// 获取两个工夫对象之间的持续时间 | |
public static Duration between(Temporal startInclusive, Temporal endExclusive) {...} |
例子:
public static void main(String[] args) {Duration duration1 = Duration.between(LocalDateTime.of(1992, 1, 1, 21, 21, 21), LocalDateTime.of(1992, 1, 2, 21, 21, 21)); | |
System.out.println("两个日期工夫相差的持续时间(单位:秒):" + duration1.toSeconds()); | |
Duration duration2 = Duration.between(LocalTime.of(2, 2, 2, 2), LocalTime.of(2, 2, 2, 543)); | |
System.out.println("两个工夫相差的持续时间(单位:纳秒):" + duration2.toNanos()); | |
Duration duration3 = Duration.between(Instant.ofEpochSecond(2, 333), Instant.ofEpochSecond(2, 336)); | |
System.out.println("两个刹时相差的持续时间(单位:纳秒):" + duration3.toNanos()); | |
} | |
/** | |
* 输入后果:* 两个日期工夫相差的持续时间(单位:秒):86400 | |
* 两个工夫相差的持续时间(单位:纳秒):541 | |
* 两个刹时相差的持续时间(单位:纳秒):3 | |
*/ |
但因为 LocalDateTime
和 Instant
是为不同的目标而设计的,所以不能混用,否则会触发 DateTimeException
异样:
// 该例子会报异样 DateTimeException | |
Duration duration = Duration.between(LocalDateTime.of(1992, 1, 1, 21, 21, 21), Instant.ofEpochSecond(333)); |
也不能应用 LocalDate
对象做参数,因为 Duration
次要用于秒和纳秒的时间段距离:
Duration duration = Duration.between(LocalDate.of(1992, 1, 1), LocalDate.of(1992, 1, 1));
上述例子会报异样 java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
反对单位为秒。
Period
Period
在概念上和 Duration
相似,区别在于 Period
是以年、月或者日的形式对多个工夫单位建模。
// 获取两个 LocalDate 日期之间的时长 | |
public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) {...} |
例子:
Period period1 = Period.between(LocalDate.of(1990, 3, 5), LocalDate.of(1990, 5, 2));
截止目前,咱们介绍的这些日期——工夫对象都是不可批改的,这是为了更好地反对函数式编程。确保线程平安,放弃畛域模式一致性二做出的重大设计决定。
日期操作
Java8 中的日期工夫类都是不可变的,因而咱们创立的 LocalDate
对象想要批改,就得应用 withAttribute
办法:
public static void main(String[] args) {LocalDate date1 = LocalDate.of(2000, 12, 12); | |
System.out.println(date1); | |
LocalDate date2 = date1.withYear(2002); | |
System.out.println(date2); | |
LocalDate date3 = date1.withMonth(5); | |
System.out.println(date3); | |
LocalDate date4 = date1.withDayOfMonth(25); | |
System.out.println(date4); | |
LocalDate date5 = date1.with(LocalDate.now()); | |
System.out.println(date5); | |
LocalDate date6 = date1.with(ChronoField.MONTH_OF_YEAR, 9); | |
System.out.println(date6); | |
} | |
/** | |
* 输入后果:* 2000-12-12 | |
* 2002-12-12 | |
* 2000-05-12 | |
* 2000-12-25 | |
* 2020-07-17 | |
* 2000-09-12 | |
*/ |
除了批改原始日期,还能够对原有日期进行减少或者批改:
public static void main(String[] args) { | |
// 实例化一个 LocalDate | |
LocalDate date1 = LocalDate.of(2010, 6, 1); | |
System.out.println(date1); | |
// 对 LocalDate 日期增加两周并返回新正本 | |
LocalDate date2 = date1.plusWeeks(2); | |
System.out.println(date2); | |
// 对 LocalDate 日期缩小 2 个月并返回新正本 | |
LocalDate date3 = date1.minus(Period.ofMonths(2)); | |
System.out.println(date3); | |
// 对 LocalDate 日期增加 6 个月并返回新正本 | |
LocalDate date10 = date1.plus(6, ChronoUnit.MONTHS); | |
System.out.println(date10); | |
} | |
/** | |
* 输入后果:* 2010-06-01 | |
* 2010-06-15 | |
* 2010-04-01 | |
* 2010-12-01 | |
*/ |
TemporalAdjuster
当须要进行更加简单的操作的时候,咱们能够应用 with
办法,向其传递一个提供了更多定制化抉择的 TemporalAdjuster
对象,更加灵便地解决日期。对于最常见的用例,Date-Time API 曾经提供了大量预约义的 TemporalAdjuster
。你能够通过 TemporalAdjusters
类的动态工厂办法拜访它们。
public static void main(String[] args) {LocalDate date = LocalDate.of(2019, 03, 05); | |
DayOfWeek dotw = date.getDayOfWeek(); // 获取当天是周几 | |
System.out.println("以后年月日:" + date + ",周:" + dotw); | |
// 获取当月第一天 | |
LocalDate date1 = date.with(TemporalAdjusters.firstDayOfMonth()); | |
System.out.println("当月第一天:" + date1); | |
// 获取当月最初一天 | |
LocalDate date2 = date.with(TemporalAdjusters.lastDayOfMonth()); | |
System.out.println("当月最初一天:" + date2); | |
// 获取下个月第一天 | |
LocalDate date3 = date.with(TemporalAdjusters.firstDayOfNextMonth()); | |
System.out.println("下个月第一天:" + date3); | |
// 获取以后年份第一天 | |
LocalDate date4 = date.with(TemporalAdjusters.firstDayOfYear()); | |
System.out.println("以后年份第一天:" + date4); | |
// 获取以后年份最初一天 | |
LocalDate date5 = date.with(TemporalAdjusters.lastDayOfYear()); | |
System.out.println("以后年份最初一天:" + date5); | |
// 获取下一年第一天 | |
LocalDate date6 = date.with(TemporalAdjusters.firstDayOfNextYear()); | |
System.out.println("下一年第一天:" + date6); | |
// 获取当月的第一个星期一(DayOfWeek.MONDAY 枚举是星期一)LocalDate date7 = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); | |
System.out.println("当月第一个星期一:" + date7); | |
// 获取当月的最初一个星期一 | |
LocalDate date8 = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); | |
System.out.println("当月最初一个星期一:" + date8); | |
// 对该当月的第 ordinal 个星期一 | |
LocalDate date9 = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY)); | |
System.out.println("当月第二个星期一:" + date9); | |
// 下一个星期一(绝对一以后工夫的下一个星期一)LocalDate date10 = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); | |
System.out.println("下一个星期一:" + date10); | |
// 对应下一个星期二,如果以后日期工夫对象满足 dayOfWeek,则返回本身 | |
LocalDate date11 = date.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY)); | |
System.out.println("下一个星期二,如果以后日期满足,则返回本身:" + date11); | |
// 对应上一个星期一 | |
LocalDate date12 = date.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); | |
System.out.println("上一个星期一:" + date12); | |
// 对应上一个星期一,如果以后日期工夫满足对象 dayOfWeek,则返回本身 | |
LocalDate date13 = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); | |
System.out.println("上一个星期一,如果以后日期满足,则返回本身:" + date13); | |
} | |
/** | |
* 输入后果:* 以后年月日:2019-03-05,周:TUESDAY | |
* 当月第一天:2019-03-01 | |
* 当月最初一天:2019-03-31 | |
* 下个月第一天:2019-04-01 | |
* 以后年份第一天:2019-01-01 | |
* 以后年份最初一天:2019-12-31 | |
* 下一年第一天:2020-01-01 | |
* 当月第一个星期一:2019-03-04 | |
* 当月最初一个星期一:2019-03-25 | |
* 当月第二个星期一:2019-03-11 | |
* 下一个星期一:2019-03-11 | |
* 下一个星期二,如果以后日期满足,则返回本身:2019-03-05 | |
* 上一个星期一:2019-03-04 | |
* 上一个星期一,如果以后日期满足,则返回本身:2019-03-04 | |
*/ |
办法十分直观。如果没有合乎你要求的预约义的 TemporalAdjuster
,则本人实现 TemporalAdjuster
接口。实际上,TemporalAdjuster
接口只申明了繁多的一个办法,定义如下:
@FunctionalInterface | |
public interface TemporalAdjuster {Temporal adjustInto(Temporal temporal); | |
} |
因而,咱们实现一个计算下一个工作日(不包含周末)的 TemporalAdjuster
类:
public class NextWorkingDay implements TemporalAdjuster { | |
@Override | |
public Temporal adjustInto(Temporal temporal) {DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); | |
int dayToAdd = 1; | |
if (dow == DayOfWeek.FRIDAY) { | |
// 如果当天是周五,则减少三天 | |
dayToAdd = 3; | |
} else if (dow == DayOfWeek.SATURDAY) { | |
// 如果当天是周六,则减少两天 | |
dayToAdd = 2; | |
} | |
// 减少失当的天数后,返回批改的日期 | |
return temporal.plus(dayToAdd, ChronoUnit.DAYS); | |
} | |
} | |
// 办法调用 | |
public static void main(String[] args) {LocalDate date = LocalDate.of(2019, 03, 05); | |
DayOfWeek dotw = date.getDayOfWeek(); // 获取当天是周几 | |
System.out.println("以后年月日:" + date + ",周:" + dotw); | |
LocalDate date14 = date.with(new NextWorkingDay()); | |
System.out.println("下一个工作日:" + date14); | |
} | |
/** | |
* 输入后果:* 以后年月日:2019-03-05,周:TUESDAY | |
* 下一个工作日:2020-07-20 | |
*/ |
你也能够应用 Lambda 表达式定义 TemporalAdjuster
对象:
date.with(TemporalAdjusters.ofDateAdjuster(temporal -> {DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); | |
int dayToAdd = 1; | |
if (dow == DayOfWeek.FRIDAY) {dayToAdd = 3;} else if (dow == DayOfWeek.SATURDAY) {dayToAdd = 2;} | |
return temporal.plus(dayToAdd, ChronoUnit.DAYS); | |
})); |
解析与格式化
新的日期 API 提供了 java.time.format
包来进行格式化以及解析日期工夫对象。包中最罕用的就是 DateTimeFormatter
。该类是不可变了:
public final class DateTimeFormatter
构建日期解析能够应用该类提供的静态方法与常量:
public static void main(String[] args) {LocalDateTime dateTime = LocalDateTime.of(2000, 10, 1, 05, 30, 30, 345_431_555); | |
String s1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE); | |
System.out.println(s1); | |
String s2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); | |
System.out.println(s2); | |
} | |
/** | |
* 输入后果:* 20001001 | |
* 2000-10-01T05:30:30.345431555 | |
*/ |
也能够通过解析日期或工夫字符串从新创立日期对象。所有的日期和工夫 API 都提供了示意工夫点或者时间段的工厂办法,你能够应用 parse
达到从新创立该日期对象的目标:
public static void main(String[] args) {LocalDateTime dateTimeOfParse = LocalDateTime.parse("2017-03-22T23:52:10.999999999"); | |
System.out.println(dateTimeOfParse); | |
} | |
/** | |
* 输入后果:* 2017-03-22T23:52:10.999999999 | |
*/ |
如果上述静态方法不能满足,能够思考应用 DateTimeFormatterBuilder
结构 DateTimeFormatter
实例。如下:
public static DateFormatter ofPattern(String pattern) {...} | |
public static DateFormatter ofPattern(String pattern, Locale locale) {...} |
例子:
public static void main(String[] args) {DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss.SSSSSSSSS", Locale.ENGLISH); | |
LocalDateTime dateTimeOfFormatParse = LocalDateTime.parse("03 Aug 2019 23:21:42.999213988", dateTimeFormatter); | |
System.out.println(dateTimeOfFormatParse); | |
} | |
/** | |
* 输入后果:* 2019-08-03T23:21:42.999213988 | |
*/ |
时区
时区的解决是新版日期和工夫 API 新减少的重要性能,每个时区都有一个标识符来形容,并通常具备地区 / 城市(亚洲 / 上海)和格林尼治 /UTC 工夫的偏移量。
在 Date-Time API 中解决时区和偏移量的是 Zoneid
和 ZoneOffset
。
ZoneId
java.time.ZoneId
是 Java8 新增的解决时区的类,是老版 java.util.TimeZone
的替代品。
时区是依照肯定的规定将区域划分成的规范工夫雷同的区间。
应用 ZoneId
的静态方法 getAvailableZoneIds()
能够获取所有可用的时区。也能够应用 of()
指定一个时区:
ZoneId romeZone = ZoneId.of("Asia/Shanghai");
也能够通过 Java8 在 TimeZone
重新加入的办法 toZoneId
来将老的时区对象转换为 ZoneId
:
ZoneId zoneId = TimeZone.getDefault().toZoneId();
ZoneOffset
另一种比拟通用的示意时区的形式是应用 ZoneOffset
,它是指定 UTC/ 格林尼治工夫的时区偏移量。
// 设置偏移量 | |
ZoneOffset offset = ZoneOffset.of("+08:00"); | |
System.out.println(offset); | |
/** | |
* 输入后果:* +08:00 | |
*/ |
日期 - 工夫类
Date-Time API 也提供了带有时区或偏移量的日期工夫类来配合 ZoneId
与 ZoneOffset
工作:
ZoneDateTime
:带有 UTC 的时区偏移量与相应时区的日期和工夫。OffsetDateTime
:带有 UTC 的时区偏移量的日期和工夫,不蕴含时区 ID。OffsetTime
:带有 UTC 的时区偏移量的工夫,不蕴含时区 ID。
ZonedDateTime
ZonedDateTime
能够了解为是 LocalDateTime
、ZoneOffset
和 ZoneId
的联合。用于示意具体时区的残缺日期和工夫。
public static void main(String[] args) {LocalDate date = LocalDate.of(2012, 12, 15); | |
ZonedDateTime zdt1 = date.atStartOfDay(ZoneId.of("Asia/Shanghai")); | |
System.out.println("LocalDate:" + date + ", 比照 ZoneDateTime:" + zdt1); | |
LocalDateTime dateTime = LocalDateTime.now(); | |
ZonedDateTime zdt2 = dateTime.atZone(ZoneId.of("Asia/Shanghai")); | |
System.out.println("LocalDateTime:" + dateTime + ", 比照 ZoneDateTime:" + zdt2); | |
Instant instant = Instant.now(); | |
ZonedDateTime zdt3 = instant.atZone(ZoneId.of("Asia/Shanghai")); | |
System.out.println("Instant:" + instant + ", 比照 ZoneDateTime:" + zdt3); | |
} | |
/** | |
* 输入后果:* LocalDate:2012-12-15, 比照 ZoneDateTime:2012-12-15T00:00+08:00[Asia/Shanghai] | |
* LocalDateTime:2020-07-17T15:44:32.554980500 , 比照 ZoneDateTime:2020-07-17T15:44:32.554980500+08:00[Asia/Shanghai] | |
* Instant:2020-07-17T07:44:32.555978200Z , 比照 ZoneDateTime:2020-07-17T15:44:32.555978200+08:00[Asia/Shanghai] | |
*/ |
OffsetDateTime
OffsetDateTime
能够了解为是 LocalDateTime
、ZoneOffset
的联合。用于示意 UTC 工夫的偏移量的整个日期和工夫。
// 设置偏移量 | |
ZoneOffset offset = ZoneOffset.of("+08:00"); | |
// 获取本地以后日期工夫 | |
LocalDateTime dateTime = LocalDateTime.now(); | |
// LocalDateTime 类中存在 `atOffset` 设置偏移量,能够返回一个 OffsetDateTime 带偏移量的日期工夫 | |
OffsetDateTime offsetDateTime = dateTime.atOffset(offset); | |
// 也能够应用 OffsetDateTime 的静态方法 of() 来实例化 | |
OffsetDateTime offsetDateTime1 = OffsetDateTime.of(dateTime, offset); | |
/** | |
* LocalDateTime 的格局:2020-07-17T16:59:37.209263500 | |
* 当设置偏移量后 | |
* OffsetDateTime 的格局:2020-07-17T16:59:37.209263500+08:00 | |
*/ |
OffsetTime
OffsetTime
能够了解为是 LocalTime
、ZoneOffset
的联合。用于示意 UTC 工夫的偏移量的整个工夫。
OffsetTime offsetTime = OffsetTime.of(LocalTime.now(), ZoneOffset.of("+08:00")); | |
System.out.println(offsetTime); | |
offsetTime = OffsetTime.ofInstant(Instant.now(), ZoneOffset.UTC); | |
System.out.println(offsetTime); | |
/** | |
* 输入后果:* 02:14:59.432481800+08:00 | |
* 18:14:59.433480700Z | |
*/ |
学习完时区后,咱们再返回去看 Date-Time API,能够了解它们之间的关系:
总结
Java8 的新日期工夫类库 java.time
的设计相比旧的日期工夫类库而言,有很大的益处:
- 新版日期类库都是不可变类且是线程平安的;
- 新的 API 提供了两种不同的工夫示意形式,无效地区分了运行时人和机器的不同需要;
- 类的职责更加明确且易扩大;
其它非 ISO 日历零碎能够应用 java.time.chrono
包来示意。Java8 给提供了几套历法如 MinguoDate
等,如有趣味能够拜访官网文档。