java8日期时间

时间:2021-08-06 16:48:42

###与时间有关的5个包
* java.time
* java.time.chrono
* java.time.format
* java.time.temporal
* java.time.zone
###java.time下的类
* Clock
* Duration
* Instant
* LocalDate
* LocalDateTime
* LocalTime
* MonthDay
* OffsetDateTime
* OffsetTime
* Period
* Year
* YearMonth
* ZonedDateTime
* ZoneId
* ZoneOffset

下面对以上类进行分类:

LocalDate包含年月日,以为与时区有关系,所以加上local这个前缀.

LocalTime包含时分秒毫秒纳秒,与时区有关系.

LocalDateTime包含LocalDate和LocalTime中的全部属性,与时区有关系.

MonthDay表示月日,Year表示年,YearMonth表示年月,三者与时区无关.

Duration和Period都表示一段时间,Duration表示时分秒上的差异,Period表示两个LocalDate之间的差异.

此外,java.time还包括两个枚举DayOfWeek和Month,一个异常DateTimeException.

其它四个包并不重要,很少用到.学习库函数无需求全责备.
###通用特征
* 值类型,不可变类型
一旦更改对象,就变成了另外一个对象,而无法在原对象上进行操作.就像java中的String,Integer等不可变类型一样.
* 大量使用静态方法来生成对象,而不用构造函数
* 分工明确,例如Year,YearMonth等
* 日期和时间明显分为两大阵营
Period用于两个日期之间做差,Duration用于两个时间之间做差.
* 对给人用的和给机器用的分工明确,Instant和Clock是给机器用的
* 时区支持完好
###LocalDate
LocalDate和LocalTime都实现了多个接口,其中两个主要接口是相同的:Temporal, TemporalAdjuster.
LocalDate d=LocalDate.ofEpochDay(365);
LocalDate d = LocalDate.ofYearDay(2014, 100)
EpochDay意思是从1970年1月1日到现在过去的天数.
with类函数意思是替换某个时间属性.
System.out.println(LocalDate.now().with(MonthDay.of(9, 7)));
这里的with(TemporalAdjuster adjuster)中,TemporalAdjuster是MonthDay,LocalDate等类的基类.
TemporalAdjuster子孙繁盛:DayOfWeek, HijrahDate, HijrahEra, Instant, IsoEra, JapaneseDate, JapaneseEra, LocalDate, LocalDateTime, LocalTime, MinguoDate, MinguoEra, Month, MonthDay, OffsetDateTime, OffsetTime, ThaiBuddhistDate, ThaiBuddhistEra, Year, YearMonth, ZoneOffset
###与java.util.Date的互相转换

System.out.println(Date.from(Instant.now()));
System.out.println(new Date(System.currentTimeMillis()).toInstant());

###打印当前各个时区的名称,时间

ZoneId.getAvailableZoneIds().forEach(x -> {
  System.out.println(x+" "+ZonedDateTime.now(ZoneId.of(x)));
});

###格式化输出

System.out.println(DateTimeFormatter.ofPattern("uuuuMMdd").format(LocalDate.now()));
System.out.println(DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now()));
System.out.println(LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(DateTimeFormatter.BASIC_ISO_DATE.format(LocalDate.now());

输出为20160909
对于格式化输出,主要在java.time.format.DateTimeFormater类中进行,这个类规定了如下占位符:

//公元
FIELD_MAP.put('G', ChronoField.ERA); // SDF, LDML (different to both for 1/2 chars)
FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // SDF, LDML
FIELD_MAP.put('u', ChronoField.YEAR); // LDML (different in SDF)
//Q和q都表示季度
FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR); // LDML (removed quarter from 310)
FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR); // LDML (stand-alone)
//M和L都表示月份
FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // SDF, LDML
FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR); // SDF, LDML (stand-alone)

FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // SDF, LDML
FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // SDF, LDML
FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH); // SDF, LDML
//E和e和c都表示周几
FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // SDF, LDML (different to both for 1/2 chars)
FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK); // LDML (stand-alone)
FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK); // LDML (needs localized week number)

FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // SDF, LDML
FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // SDF, LDML
FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // SDF, LDML
FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // SDF, LDML
FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // SDF, LDML
FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // SDF, LDML
FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // SDF, LDML
FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // LDML (SDF uses milli-of-second number)
FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // LDML
FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 (proposed for LDML)
FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); 

占位符的意义已经很明确了,占位符的个数不同表达的含义也不相同,如果只出现一个占位符,那么只输出一次.如果有多个连续相同占位符,则在前面补0来凑够位数.这一部分主要在DateTimeFormatter#parseField()函数中描述,这个函数比较混乱,并且没啥意义,无需研读.
###计算日期差和时间差
对于日期类型,使用Period.between(LocalDate,LocalDate)函数;对于时间类型,使用Duration.between(Temporal,Temporal)函数.

###其它

    public static void testClock() throws InterruptedException {
        // 时钟提供给我们用于访问某个特定 时区的 瞬时时间、日期 和 时间的。
        Clock c1 = Clock.systemUTC(); // 系统默认UTC时钟(当前瞬时时间
                                        // System.currentTimeMillis())
        System.out.println(c1.millis()); // 每次调用将返回当前瞬时时间(UTC)
        Clock c2 = Clock.systemDefaultZone(); // 系统默认时区时钟(当前瞬时时间)
        System.out.println(c2.millis());
        Clock c31 = Clock.system(ZoneId.of("Europe/Paris")); // 巴黎时区
        System.out.println(c31.millis()); // 每次调用将返回当前瞬时时间(UTC)
        Clock c32 = Clock.system(ZoneId.of("Asia/Shanghai"));// 上海时区
        System.out.println(c32.millis());// 每次调用将返回当前瞬时时间(UTC)
        Clock c4 = Clock.fixed(Instant.now(), ZoneId.of("Asia/Shanghai"));// 固定上海时区时钟
        System.out.println(c4.millis());
        Thread.sleep(1000);
        System.out.println(c4.millis()); // 不变 即时钟时钟在那一个点不动
        Clock c5 = Clock.offset(c1, Duration.ofSeconds(2)); // 相对于系统默认时钟两秒的时钟
        System.out.println(c1.millis());
        System.out.println(c5.millis());
    }
    public static void testInstant() {
        // 瞬时时间 相当于以前的System.currentTimeMillis()
        Instant instant1 = Instant.now();
        System.out.println(instant1.getEpochSecond());// 精确到秒 得到相对于1970-01-01
                                                        // 00:00:00 UTC的一个时间
        System.out.println(instant1.toEpochMilli()); // 精确到毫秒
        Clock clock1 = Clock.systemUTC(); // 获取系统UTC默认时钟
        Instant instant2 = Instant.now(clock1);// 得到时钟的瞬时时间
        System.out.println(instant2.toEpochMilli());
        Clock clock2 = Clock.fixed(instant1, ZoneId.systemDefault()); // 固定瞬时时间时钟
        Instant instant3 = Instant.now(clock2);// 得到时钟的瞬时时间
        System.out.println(instant3.toEpochMilli());// equals instant1
    }
    public static void testLocalDateTime() {
        // 使用默认时区时钟瞬时时间创建 Clock.systemDefaultZone() -->即相对于
        // ZoneId.systemDefault()默认时区
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        // 自定义时区
        LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.println(now2);// 会以相应的时区显示日期
        // 自定义时钟
        Clock clock = Clock.system(ZoneId.of("Asia/Dhaka"));
        LocalDateTime now3 = LocalDateTime.now(clock);
        System.out.println(now3);// 会以相应的时区显示日期
        // 不需要写什么相对时间 如java.util.Date 年是相对于1900 月是从0开始
        // 2013-12-31 23:59
        LocalDateTime d1 = LocalDateTime.of(2013, 12, 31, 23, 59);
        // 年月日 时分秒 纳秒
        LocalDateTime d2 = LocalDateTime.of(2013, 12, 31, 23, 59, 59, 11);
        // 使用瞬时时间 + 时区
        Instant instant = Instant.now();
        LocalDateTime d3 = LocalDateTime.ofInstant(Instant.now(),
                ZoneId.systemDefault());
        System.out.println(d3);
        // 解析String--->LocalDateTime
        LocalDateTime d4 = LocalDateTime.parse("2013-12-31T23:59");
        System.out.println(d4);
        LocalDateTime d5 = LocalDateTime.parse("2013-12-31T23:59:59.999");// 999毫秒
                                                                            // 等价于999000000纳秒
        System.out.println(d5);
        // 使用DateTimeFormatter API 解析 和 格式化
        DateTimeFormatter formatter = DateTimeFormatter
                .ofPattern("yyyy/MM/dd HH:mm:ss");
        LocalDateTime d6 = LocalDateTime.parse("2013/12/31 23:59:59",
                formatter);
        System.out.println(formatter.format(d6));
        // 时间获取
        System.out.println(d6.getYear());
        System.out.println(d6.getMonth());
        System.out.println(d6.getDayOfYear());
        System.out.println(d6.getDayOfMonth());
        System.out.println(d6.getDayOfWeek());
        System.out.println(d6.getHour());
        System.out.println(d6.getMinute());
        System.out.println(d6.getSecond());
        System.out.println(d6.getNano());
        // 时间增减
        LocalDateTime d7 = d6.minusDays(1);
        LocalDateTime d8 = d7.plus(1, IsoFields.QUARTER_YEARS);
        // LocalDate 即年月日 无时分秒
        // LocalTime即时分秒 无年月日
        // API和LocalDateTime类似就不演示了
    }
    public static void testZonedDateTime() {
        // 即带有时区的date-time 存储纳秒、时区和时差(避免与本地date-time歧义)。
        // API和LocalDateTime类似,只是多了时差(如2013-12-20T10:35:50.711+08:00[Asia/Shanghai])
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
        ZonedDateTime now2 = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.println(now2);
        // 其他的用法也是类似的 就不介绍了
        ZonedDateTime z1 = ZonedDateTime
                .parse("2013-12-31T23:59:59Z[Europe/Paris]");
        System.out.println(z1);
    }
    public static void testDuration() {
        // 表示两个瞬时时间的时间段
        Duration d1 = Duration.between(
                Instant.ofEpochMilli(System.currentTimeMillis() - 12323123),
                Instant.now());
        // 得到相应的时差
        System.out.println(d1.toDays());
        System.out.println(d1.toHours());
        System.out.println(d1.toMinutes());
        System.out.println(d1.toMillis());
        System.out.println(d1.toNanos());
        // 1天时差 类似的还有如ofHours()
        Duration d2 = Duration.ofDays(1);
        System.out.println(d2.toDays());
    }
    public static void testChronology() {
        // 提供对java.util.Calendar的替换,提供对年历系统的支持
        Chronology c = HijrahChronology.INSTANCE;
        ChronoLocalDateTime d = c.localDateTime(LocalDateTime.now());
        System.out.println(d);
    }
    /**
     * 新旧日期转换
     */
    public static void testNewOldDateConversion() {
        Instant instant = new Date().toInstant();
        Date date = Date.from(instant);
        System.out.println(instant);
        System.out.println(date);
    }
    public static void main(String[] args) throws InterruptedException {
        testClock();
        testInstant();
        testLocalDateTime();
        testZonedDateTime();
        testDuration();
        testChronology();
        testNewOldDateConversion();
    }