12.3 处理不同的时区和历法

java.time.ZoneId类代替java.util.TimeZone简化处理日期和时间的时区。

将老的时区对象转换为ZoneId:

ZoneId zoneId = TimeZone.getDefault().toZoneId(); // Asia/Shanghai

每个ZoneId对象都有一个地区ID,格式为{区域}/{城市},由英特网编号分配机构(IANA)的时区数据库提供。

ZoneId romeZone = ZoneId.of("Europe/Rome"); // Europe/Rome

时区是按照规则将区域划分为标准时间相同的区间,可以获取指定时区的规则。

ZoneRules zoneRules = romeZone.getRules(); // ZoneRules[currentStandardOffset=+01:00]

LocalDate + LocalTime = LocalDateTime

LocalDateTime + ZoneId = ZonedDateTime

LocalDate date = LocalDate.of(2014, 3, 18); // 2014-03-18
ZonedDateTime zdt1 = date.atStartOfDay(romeZone); // 2014-03-18T00:00+01:00[Europe/Rome]

LocalDateTime dateTime = LocalDateTime.of(2014, 3, 18, 13, 45, 20);
ZonedDateTime zdt2 = dateTime.atZone(romeZone); // 2014-03-18T00:00+01:00[Europe/Rome]
ZonedDateTime组成

Instant转化为指定时区的LocalDateTime

Instant instant = Instant.now();
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, zoneId);

LocalDateTime带指定时区,转化为Instant

LocalDateTime now = LocalDateTime.now();
ZonedDateTime zonedDateTime = now.atZone(zoneId);
Instant instant2 = zonedDateTime.toInstant();

12.3.1 利用和UTC/格林尼治时间的固定偏差计算时区

java.time.ZoneOffset类使用当前时区和UTC/格林尼治的固定偏差表达时区,是ZoneId的子类

未考虑任何日光时的影响,因此在大多数情况下,不推荐使用。

例如纽约落后于伦敦5小时

ZoneOffset newYorkOffset = ZoneOffset.of("-05:00"); // -05:00

LocalDateTime dateTime = LocalDateTime.of(2014, 3, 18, 13, 45, 20); // 2014-03-18T13:45:20

OffsetDateTime dateTimeInNewYork = OffsetDateTime.of(dateTime, newYorkOffset);

12.3.2 使用别的日历系统

ISO-8601日历系统是世界文明日历系统的事实标准,同时提供了4种其他日历系统,分别是ThaiBuddhistDate、MinguoDate、JapaneseDate以及HijrahDate。

建议使用LocalDate,尽量避免使用ChronoLocalDate。

  1. 在不同的日历系统中,原有的有些假设(一个月天数不会超过31天/一年包括12个月)有可能不成立;
  2. 在应用中使用LocalDate进行存储、操作和解读业务规则;
  3. 程序的输入或者输出本地化,才使用ChronoLocalDate类。
LocalDate date = LocalDate.of(2014, 3, 18); // 2014-03-18
JapaneseDate japaneseDate = JapaneseDate.from(date); // Japanese Heisei 26-03-18

Chronology japanChronology = Chronology.ofLocale(Locale.JAPAN);
ChronoLocalDate japanDate = japanChronology.dateNow();

伊斯兰教日历

在ISO日历中计算当前伊斯兰年中斋月的起始和终止日期:真复杂!

// Hijrah-umalqura AH 1444-09-01
HijrahDate ramadanDate = HijrahDate.now()
        .with(ChronoField.DAY_OF_MONTH, 1)
        .with(ChronoField.MONTH_OF_YEAR, 9);
        

// Ramadan starts on 2023-03-23 and ends on 2023-04-20
System.out.println("Ramadan starts on " +
    IsoChronology.INSTANCE.date(ramadanDate) +
    " and ends on " +
    IsoChronology.INSTANCE.date(ramadanDate.with(
            TemporalAdjusters.lastDayOfMonth())));
posted @ 2023-06-03 22:27  蒋智  阅读(70)  评论(0)    收藏  举报