JDK 时间日期新特性

1. LocalDate vs LocalTime

image-20211221180925877

image-20211221180943983

LocalDateLocalDateTime
当前时间now()now()
自定义时间of()of()
修改时间with[Day Month Year]()with[Nano Second Minute Hour]()
获取时间属性get[Day Month Year]()get[Nano Second Minute Hour]()
转换时间toEpochDay() / toEpochSecond()to[EpochSecond Nano Second]OfDay()
数学运算[plus minus][Days Weeks Months Years]()[plus minus][Nano Second Minute Hour]()
时间比较isBefore() / isAfter()isBefore() / isAfter()
差值计算until()until()
闰年判断isLeapYear()-

LocalDateTime 这是对两者的一个参数整合,方法形式上大同小异

public class MyTimeTest {
    @Test
    public void test01(){
        LocalDate now = LocalDate.now();
        LocalDate date = LocalDate.of(2021, 10, 21);
        System.out.println(date.toEpochDay());
        LocalDate date2 = LocalDate.of(2021, Month.DECEMBER, 21);
        LocalDate localDate1 = now.withMonth(12);
        now.plusWeeks(1);
        now.minusDays(1);
        System.out.println(now.getDayOfMonth());
        System.out.println(now.getDayOfWeek());
        System.out.println(now.getDayOfYear());
        System.out.println(now.getMonth());
        System.out.println(now.getMonthValue());
        System.out.println(now.getYear());
        System.out.println(now.isBefore(LocalDate.now()));
        Period period = now.until(LocalDate.now());
        System.out.println(now.isLeapYear());

        LocalTime localTime = LocalTime.now();
        LocalTime time = LocalTime.of(1,1,1);
        LocalTime time1 = LocalTime.of(1,1);
        LocalTime localTime1 = time.withHour(12);
        time.plusNanos(1);
        time.minusSeconds(1);
        System.out.println(time.getNano());
        System.out.println(time.getSecond());
        System.out.println(time.getMinute());
        System.out.println(time.getHour());
        System.out.println(time.toSecondOfDay());
        System.out.println(time.toNanoOfDay());
        System.out.println(time.isBefore(LocalTime.now()));
    }
}

2. Duration vs Period

Duration 描述时间上LocalTime的差距;Period 描述时间上LocalDate的差距

DurationPeriod
获取两个时间之间的差距between()between()
创建时间of[Nanos Mills Seconds Minutes Days Hours]()of[Days Weeks Months Years]()
修改时间with[Seconds Nanos]with[Days Months Years]()
转换时间to[Nanos Millis Minutes Hours Days]()toTotalMonths()
get[Nacos Seconds]()get[Days Months Years]()
获得对应部分数值to[Nanos Mills Seconds Minutes Days Hours]Part()
数学运算[plus minus][Nanos Mills Seconds Minutes Days Hours]()[plus minus][Days Months Years]()
乘法multipliedBy()multipliedBy()
除法dividedBy()dividedBy()
变为无效时间negated()negated()
是否是0isZero()isZero()
时间是否有效isNegative()isNegative()
public class MyTimeTest {
    @Test
    public void test02(){
        // Duration
        Duration duration = Duration.between(Instant.now(), Instant.now());
        duration.withSeconds(1);
        System.out.println(duration.plusSeconds(10));
        System.out.println(duration.minusHours(1));
        System.out.println(duration.multipliedBy(2));
        System.out.println(duration.dividedBy(3));
        System.out.println(duration.negated());
        System.out.println(duration.isZero());
        System.out.println(duration.isNegative());
		// Period
        Period of = Period.of(1, 1, 1);
        System.out.println(of.getDays());
        System.out.println(of.getMonths());
        System.out.println(of.getYears());
        of.plusDays(1);
        of.minusMonths(2);
    }
}

3. Instant

本质上等价于传统时间API中的Date属性,内部保存了从1970年1月1日 00:00:00以来的秒和纳秒。

方法
当前时间now()
从秒中创建时间ofEpochSecond()
数学运算[plus minus][Seconds Nanos Millis]()
时间转换toEpochMilli()
获取时间参数getNanos() getEpochSecond()
时间大小判断isBefore() | isAfter()
public class MyTimeTest {
        @Test
    public void test03(){
        Instant instant = Instant.now();
        Instant instant1 = Instant.ofEpochSecond(1000);
        instant.plus(Duration.ofSeconds(10));
        instant.plus(10, ChronoUnit.SECONDS);
        instant.plusSeconds(10);
        instant.plusNanos(10);
        instant.minus(Duration.ofSeconds(10));
        instant.minus(10, ChronoUnit.SECONDS);
        instant.minusSeconds(10);

        System.out.println(instant.toEpochMilli());
        System.out.println(instant.getEpochSecond());
        System.out.println(instant.getNano());
        System.out.println(instant.isBefore(Instant.now()));
    }
}

4. 时区设置

时区时间 ZonedDateTime 方法大体上和DateTime相同,LocalDate、LocalTime、LocalDateTime是不带时区的,带时区的日期时间类分为:ZonedDate、ZonedTime、ZonedDateTime。其中每个时区都对应着 ID,ID的格式为 “区域/城市” 。例如 :Asia/Shanghai 等。
ZoneId:该类中包含了所有的时区信息。

相关方法类似于LocalDateTime中的相关方法。

ZonedDateTime方法
获取偏移getOffset()
类型转换toLocalDate()
toLocalTime()
toLocalDateTime()
toInstant()
ZoneId方法
获取实例of("America/Vancouver")
获得有效的时区参数getAvailableZoneIds()
public class MyTimeTest {
    @Test
    public void test06(){
        ZonedDateTime now = ZonedDateTime.now();
        ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("America/Vancouver"));
        ZonedDateTime now1 = ZonedDateTime.now(ZoneId.of("America/Vancouver"));
        ZoneOffset offset = now.getOffset();
        LocalDate localDate = now.toLocalDate();
        LocalTime localTime = now.toLocalTime();
        LocalDateTime localDateTime = now.toLocalDateTime();
        Instant instant = now.toInstant();

        ZoneId.getAvailableZoneIds().forEach(System.out::println);
    }
}

5. 时间调整器

使用TemporalAdjusters实现工具类完成调整
可以使用TemporalAdjusters.ofDateAdjuster 实现自定义工具类的创建

public class MyTimeTest {
        @Test
    public void test04(){
        LocalDate localDate = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());
        LocalDate localDate1 = LocalDate.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY));
        // 自定义TemporalAdjusters
        TemporalAdjuster adjuster = TemporalAdjusters.ofDateAdjuster(w -> {
            LocalDate result = w;
            do {
                result = result.plusDays(1);
            } while (result.getDayOfWeek().getValue() >= 6);
            return result;
        });
        localDate.with(adjuster);
        // 另外一种表示形式
        TemporalAdjuster adjuster2 = w -> {
            LocalDate result = (LocalDate) w;
            do {
                result = result.plusDays(1);
            } while (result.getDayOfWeek().getValue() >= 6);
            return result;
        };
        localDate.with(adjuster);
    }
}

6. 时间格式化

预定义的格式化器

这种形式的格式化器主要是为了机器可读而设计的,如果是前端可视化更推荐使用Locale的表示形式

格式器描述示例
BASIC_ISO_DATE年、月、日、时区偏移量,中间没有分隔符19690716-0500
ISO_LOCAL_DATE,ISO_L0CAL_TIME,ISO_LOCAL DATE TINE分隔符为·、:、T1969-07-16,
09:32:00,
1969-07-16T09:32:00
ISO_OFFSET_DATE,
ISO OFFSETTIME, ISO_OFFSET_DATETIME
类似ISO_L0CAL_XXX, 但是有时区偏移量1969-07-16-05:00,
09:32:00-05:00,
1969-07-16T09:32:00-05:00
ISO_ZONED_DATETIME有时区偏移量和时区ID1969-07-16T 09:32:00-05:00
[America/NewYork]
ISO_INSTANT在UTC中, 用Z时区ID来表示1969-07-16T14:32:00Z
ISO_DATE, ISO_TIME, ISODATETIME类似ISO_OFFSET_DATE、ISO_OFFSET_TIME和ISO ZONEDDATE_TIME, 但是时区信息是可选的1969-07-16-05:00,09:32:00-05:00,1969-07-16T 09:32:00-05:00[America/NewYork]
ISO_ORDINAL DATELocal Date的年和年日期1969-197
ISO_WEEK DATELocal Date的年、星期和星期日期1969-W29-3
RFC1123DATETINE用于邮件时间戳的标准, 编纂于RFC 822,并在RFC 1123中将年份更新到4位Wed,16Jul 1969 09:32:00-0500

locale相关的格式化风格

风格日期时间
SHORT7/16/699:32 AM
MEDIUMJul 16,19699:32:00 AM
LONGJuly 16,19699:32 AM EDT
FULLWednesday,July 16,19699:32 AM EDT

常用日期格式化符号

时间域或目的示例
ERAG:AD, GGGG:An no Domini, G GGGG:A
YEAR_OF_ERAyy:69,yyyy:1969
MONTH OF YEARM:7, MM:07, MMM:Jul, MMMM:JuLy, M MMMM:J
DAY_OF MONTHd:6,dd:06
DAYOFWEEKe:3, E:Wed, EEEE:Wednesday, E EEEE:W
HOUR OF DAYH:9,HH:09
CLOCK HOUR_OF_AM PMK:9,KK:09
AM PM OF DAYa:AM
MINUTE_OF HOURmm:02
SECOND OF MINUTEss:00
NANO OF SECONDnnnnnn:000000
时区IDW:America/New_York
时区名Z:EDI, zzzz:Eastern DayLight Time V:ET, WV V:Eastern time
时区偏移量x:-04,xx:-0400,X:-0400,xxx:-04:00,XXX:与xxx相同,但是Z表示0
本地化的时区偏移量0:GMT-4, 0000:GMT-04: 00
修改后的儒略日g:58243
DateTimeFormatter方法
格式化方法format()
格式化风格ofLocalizedDateTime()
切换LocalewithLocale()
自定义格式化器ofPattern()
LocalDate解析parse()
LocalDate格式化format()
ZonedDateTime解析parse()

注意:withLocale():修改格式化解析形式,例如星期格式化中,Locale.English vs Locale.China 对应就是Tue星期二

public class MyTimeTest {
    @Test
    public void test05(){
        // 使用标准格式化器
        String format = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now());
        String format1 = LocalTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
        // 使用Locale的格式化风格
        DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        DateTimeFormatter locale = formatter.withLocale(Locale.CANADA);// 切换不同时区的格式化器
        System.out.println(locale.format(ZonedDateTime.now()));
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime.parse("星期二 2021-12-21 11:11:11", pattern);
        LocalDateTime.parse("Tue 2021-12-21 11:11:11", pattern.withLocale(Locale.ENGLISH));
    }
}

7. 遗留类的转换

Instant 类似于 Date, ZonedDateTime 类似于GregorianCalendar

时间类转换关系

转换到遗留类转换自遗留类
Instant ◇java.util.DateDate.from(instant)date.toInstant()
ZonedDateTime◇java.util.GregorianCalendarGregorianCalendar.from(zoned DateTime)cal.toZonedDateTime()
Instant◇java.sql.TimestampTimeStamp.from(instant)timestamp.toInstant()
LocalDateTime◇java.sqL.TimestampTimestamp.valueOf(Local DateTime)timeStamp.toLocal DateTime()
LocalDate◇java.sql.DateDate. valueOf(local Date)date.toLocalDate()
LocalTime◇java.sql.TimeTime.valueOf(Local T me)time.toLocalTime()
DateTime Formatter◇java.text.DateFormatformatter.toFormat()
java.util.TimeZoneZoneIdTimezone.getTimeZone(id)timeZone.toZoneId()
java.nio.file.attribute.FileTimeInstantFileTime.from(instant)fileTime.toInstant()
public class MyTimeTest {
    @Test
    public void test07(){
        // Instant <-> Date
        Date.from(Instant.now());
        new Date().toInstant();
        // ZonedDateTime <-> GregorianCalendar
        GregorianCalendar.from(ZonedDateTime.now());
        (new GregorianCalendar()).toZonedDateTime();
        // Instant <-> TimeStamp
        Timestamp.from(Instant.now());
        (new Timestamp()).toInstant();
        // LocalDateTime <-> TimeStamp
        Timestamp.valueOf(LocalDateTime.now());
        (new Timestamp()).toLocalDateTime();
        // LocalDate <-> Date
        java.sql.Date.valueOf(LocalDate.now());
        (new java.sql.Date()).toLocalDate();
        // LocalTime <-> Time
        Time.valueOf(LocalTime.now());
        (new Time()).toLocalTime();
        // TimeZone <-> ZoneId
        TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai"));
        (new TimeZone()).toZoneId();
    }
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://quguai.cn/archives/jdkshi-jian-ri-qi-xin-te-xing