处理日期和时间对象时,格式化以及解析日期-时间对象是另一个非常重要的功能。新的java.time.format包就是为了这个目的而设计的。这个包中最重要的类是DateTimeFormatter,创建格式器最简单的方式是通过他的静态工厂方法及常量。
String s1 = next.format(DateTimeFormatter.BASIC_ISO_DATE); //20180824
String s2 = next.format(DateTimeFormatter.ISO_LOCAL_DATE); //2018-08-24
除了解析为字符串外,还可以通过解析代表日期或时间的字符串重新创建该日期对象。
LocalDate date1 = LocalDate.parse("20180901",DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2018-09-02",DateTimeFormatter.ISO_LOCAL_DATE);
与老的java.util.DateFormat想比较,所有的DateTimeFormatter实例都是线程安全的。DateTimeFormatter类还支持一个静态工厂方法,它按照某个特定的模式创建格式器。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate now = LocalDate.now();
String formatterDate = now.format(formatter);
LocalDate nowparse = LocalDate.parse(formatterDate,formatter);
ofPattern可以按照指定的格式进行解析成字符串,然后又调用了parse方法的重载 将该格式的字符串转换成了 LocalDate对象。
ofPattern也提供了重载版本,使用它可以创建某个Locale的格式器:
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MMMMd号", Locale.CHINA);
LocalDate chinaDate = LocalDate.parse("2018-08-21");
String formatterDate2 = chinaDate.format(formatter2); //2018年八月21号
LocalDate chinaDate2 = LocalDate.parse(formatterDate2,formatter2);
DateFormatterBuilder类还提供了更复杂的格式器和更强大的解析功能:
DateTimeFormatter chinaFormatter = new DateTimeFormatterBuilder().appendText(ChronoField.YEAR)
.appendLiteral("年")
.appendText(ChronoField.MONTH_OF_YEAR)
.appendText(ChronoField.DAY_OF_MONTH)
.appendLiteral("号")
.parseCaseInsensitive().toFormatter(Locale.CHINA);
处理不同的时区和历法
之前所看到的日期和时间种类都不包含时区信息。时区的处理是新版日期和时间API新增加的重要功能,新的 java.time.ZoneId 类是老版 java.util.TimeZone 的替代品。
时区是按照一定的规则将区域划分成的标准时间相同的区间。在ZoneRules这个类中包含了40个这样的实例。你可以使用ZoneId的getRules()得到指定时区的规则。每个特定的ZoneId对象都由一个地区标识:
ZoneId romeZone = ZoneId.of("Europe/Rome"); //格式 欧洲/罗马
地区ID都为 “{区域}/{城市}”的格式,这些地区集合的设定都由英特网编号分配机构(IANA)的时区数据库提供。你可以通过java 8的新方法toZoneId将一个老的时区对象转换为ZoneId
ZoneId zoneId = TimeZone.getDefault().toZoneId();
一旦得到一个ZoneId对象,就可以将它与LocalDate、LocalDateTIme或者是Instant对象整合起来,构造为一个ZonedDateTime实例,它代表了相对于指定时区的时间点,
LocalDate date = LocalDate.of(2018,8,22);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
LocalDateTime dateTime = LocalDateTime.of(2018,8,23,13,48,00);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);
Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);
ZonedDateTime = LocalDateTime(LocalDate + LocalTime) + ZoneId
通过ZoneId,你还可以将LocalDateTime转换为Instant
LocalDateTime dateTime = LocalDateTime.of(2018,8,23,13,48,00);
Instant instantFromDateTime = dateTime.toInstant(romeZone);
Instant instant1 = Instant.now();
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(romeZone);
利用和 UTC/格林尼治时间的固定偏差计算时区
另一种比较常用的表达时区的方式就是利用当前时区和 UTC/格林尼治 的固定偏差,比如,纽约落后伦敦5小时。这种情况下,你可以使用ZoneOffset类,它是ZoneId的一个子类,表示的是当前时间和伦敦格林尼治子午时间的差异:
ZoneOffset newYorkOffset = ZoneOffset.of("-05:00");
这种方式不推荐使用,因为 -05:00 的偏差实际上是对应的美国东部标准时间,并未考虑任何日光时的影响。
LocalDateTime dateTime1 = LocalDateTime.now();
OffsetDateTime dateTimeInNewYork1 = OffsetDateTime.of(dateTime1,newYorkOffset);
它使用ISO-8601的历法系统,以相对于UTC时间的偏差方式表示日期时间。
使用别的日历系统