Java8日期与时间API(LocalDate、LocalDateTime、Instant等)
代码来源:《Java8实战》
后续有更好的实例实时补充。
旧API的问题
Date与Calendar的问题:
- 同时存在Date和Calendar这两个类,增加调用时选择的困惑
- DateFormat只在Date中存在,但是非线程安全,多线程下会出问题。
- Date与Calendar类非final。final本质上是线程安全的,有利于各种函数式的方法调用。
新API各自职能
所有类都是不可变类型而且线程安全
LocalDate:提供日期信息,不含时间信息。不附带任何与时区相关的信息。
LocalTime:提供时间信息,不含日期信息。不附带任何与时区相关的信息。
LocalDateTime:LocalDate和LocalTime的合体。同时表示了日期和时间,但不带有时区信息。
Instant:面向机器,包含的是由秒及纳秒所构成的数字。
以Unix元年时间(传统设定为UTC时区1970年1月1日午夜时分)开始所经历的秒数进行计算。
Duration:以秒和纳秒表示某两个时间之间/时间段的长短
Period:以年、月或者日的方式表示某两个时间之间/时间段的长短
DateTimeFormatter:线程安全,时间格式,预先定义了许多实例,比如BASIC_ISO_DATE、ISO_LOCAL_DATE
ZoneId:时区。ZoneRules类中定义了40个时区实例可以直接使用。
ZonedDateTime:参见下图,可以理解为有时区信息的LocalDateTime。
MonthDay:这个类组合了月份和日,去掉 了年,这意味着你可以用它判断每年都会发生事件。
YearMonth:另一个组合类,用于表示信用卡到期日、FD到期日、期货期权到期日等。
可以用这个类得到 当月共有多少天
Clock时钟类:获取当时的时间戳,或当前时区下的日期时间信息。
以前用到System.currentTimeMillis()和TimeZone.getDefault()的地方都可用Clock替换。
LocalDate、LocalTime、LocalDateTime、Instant、 Duration & Period の API
通用方法列表:
预定义的TemporalAdjuster,将日期调整到下个周日、下个工作日,或者是本月的最后一天。
LocalDate
// 创建
LocalDate today = LocalDate.now();
LocalDate date = LocalDate.of(2014, 3, 18);
LocalDate date = LocalDate.parse("2014-03-18");
// 获取各个日期
int year = date.getYear();
Month month = date.getMonth();
int day = date.getDayOfMonth();
DayOfWeek dow = date.getDayOfWeek();
int len = date.lengthOfMonth();
boolean leap = date.isLeapYear();
int year = date.get(ChronoField.YEAR);
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);
// withAttribute方法会创建对象的一个副本,并按照需要修改它的属性
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.withYear(2011); // 2011-03-18
LocalDate date3 = date2.withDayOfMonth(25); // 2011-03-25
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9); // 2011-09-25
// 以相对方式修改LocalDate对象的属性
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.plusWeeks(1);
LocalDate date3 = date2.minusYears(3);
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS);
// 使用预定义的TemporalAdjuster,将日期调整到下个周日、下个工作日,或者是本月的最后一天
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
LocalDate date3 = date2.with(lastDayOfMonth());
// 打印输出几解析日期-时间对象
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
LocalDate date1 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
// 判断日期先后
LocalDate tomorrow = LocalDate.of(2014, 1, 15);
if(tommorow.isAfter(today)){
System.out.println("Tomorrow comes after today");
}
LocalDate yesterday = today.minus(1, DAYS);
if(yesterday.isBefore(today)){
System.out.println("Yesterday is day before today");
}
Output:
Tomorrow comes after today
Yesterday is day before today
// isLeapYear()判断该实例是否是一个闰年
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2014 is not a Leap year");
}
LocalTime
// 创建
LocalTime time = LocalTime.of(13, 45, 20);
LocalTime time = LocalTime.parse("13:45:20");
// 获取各个时间
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
// 操纵时间
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Today is : " + today);
System.out.println("Date after 1 week : " + nextWeek);
LocalDateTime
// 创建 2014-03-18T13:45:20
LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(date, time); // 根据LocalDate与LocalTime
LocalDateTime dt3 = date.atTime(13, 45, 20);
LocalDateTime dt4 = date.atTime(time);
LocalDateTime dt5 = time.atDate(date);
// 转化为LocalDate与LocalTime
LocalDate date1 = dt1.toLocalDate();
LocalTime time1 = dt1.toLocalTime();
// 将LocalDateTime转换为Instant
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
Instant instantFromDateTime = dateTime.toInstant(romeZone);
// 得到LocalDateTime对象
Instant instant = Instant.now();
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);
Instant
Instant.ofEpochSecond(3);
Instant.ofEpochSecond(3, 0); // 3秒之后的0纳秒
Instant.ofEpochSecond(2, 1_000_000_000); // 2秒之后再加上100万纳秒( 1秒)
Instant.ofEpochSecond(4, -1_000_000_000); //4秒之前的100万纳秒( 1秒)
// 将LocalDateTime转换为Instant
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
Instant instantFromDateTime = dateTime.toInstant(romeZone);
// 得到LocalDateTime对象
Instant instant = Instant.now();
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp);
Output :
What is value of this instant 2014-01-14T08:33:33.379Z
Duration与Period
// 创建Duration
Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
Duration d2 = Duration.between(instant1, instant2);
Duration threeMinutes = Duration.ofMinutes(3);
Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES);
// 创建Period
Period tenDays = Period.between(LocalDate.of(2014, 3, 8), LocalDate.of(2014, 3, 18));
Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
DateTimeFormatter
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); //20140318
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); //2014-03-18
LocalDate date1 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
// 按照某个模式创建DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
// 创建一个本地化的DateTimeFormatter
DateTimeFormatter italianFormatter =
DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.ITALIAN);
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date.format(italianFormatter); // 18. marzo 2014
LocalDate date2 = LocalDate.parse(formattedDate, italianFormatter);
// 日期格式“MMM d yyyy”和“MMM dd yyyy”有一些微妙的不同
// 第一个格式可以解析“Jan 2 2014”和“Jan 14 2014”,而第二个在解析“Jan 2 2014”就会抛异常。
// 第二个格式里要求日必须是两位的。
// 如果想修正,你必须在日期只有个位数时在前面补零,就是说“Jan 2 2014”应该写成 “Jan 02 2014”。
// 构造一个DateTimeFormatter
DateTimeFormatter italianFormatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.DAY_OF_MONTH)
.appendLiteral(". ")
.appendText(ChronoField.MONTH_OF_YEAR)
.appendLiteral(" ")
.appendText(ChronoField.YEAR)
.parseCaseInsensitive()
.toFormatter(Locale.ITALIAN);
时区
ZoneId romeZone = ZoneId.of("Europe/Rome");
// TimeZone的转换
ZoneId zoneId = TimeZone.getDefault().toZoneId();
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(date , romeZone );
Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);
// 将LocalDateTime转换为Instant
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
Instant instantFromDateTime = dateTime.toInstant(romeZone);
// 得到LocalDateTime对象
Instant instant = Instant.now();
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);
// 比较通用的表达时区的方式是利用当前时区和UTC/格林尼治的固定偏差
// 纽约时区落后于伦敦5小时
ZoneOffset newYorkOffset = ZoneOffset.of("-05:00");
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
OffsetDateTime dateTimeInNewYork = OffsetDateTime.of(date, newYorkOffset);