java8 系列 -06 时间相关 API

本贴最后更新于 2084 天前,其中的信息可能已经时移俗易

用过旧版 java 时间类库的都清楚,其实用起来的感觉是非常糟糕的。比如 java.sql.Date 与 java.util.Date 除了包名以外类名都是一样的。(sql.Date 是继承 util.Date 重写的)这种设计其实是非常差的,很容易搞混淆。再比如,当你在并发情景下用 java.util.Date 是很容易出问题的,因为 java.util.Date 是属于线程不安全的。针对这些问题,java8 推出了一系列新的 API. PS: 新的时间相关 API 都在 java.time.* 包下

时间日期类

表示时间戳的 instant

instant 是用来表示时间戳的,等价于 System.currentTimeMillis(),instant 类被设计成单例模式,使用起来也是极其方便的。

Instant 类构建的几种方法以及他们的作用

public class InstantDemo {

    public static void main(String[] args) {
        Instant now = Instant.now(); // return Clock.systemUTC().instant(); 也就是说默认的是格林时区的时间
        System.out.println(now.toEpochMilli());

        // 相对于格林时区偏移八小时,就是中国的上海时区啦
        Instant now2 = Instant.now(Clock.offset(Clock.systemUTC(), Duration.ofHours(8)));
        System.out.println(now2.toEpochMilli());

        Instant from = Instant.from(ZonedDateTime.now()); // 从时态对象(TemporalAccessor接口)获取Instant的实例
        System.out.println(from.toEpochMilli());

        Instant milli = Instant.ofEpochMilli(System.currentTimeMillis()); // 通过毫秒数值直接构建Instant实例
        System.out.println(milli.getEpochSecond());

        Instant second = Instant.ofEpochSecond(60); // 通过传入一个标准时间的偏移值来构建Instant实例
        System.out.println(second);

        Instant second2 = Instant.ofEpochSecond(60,60); // 第二个参数:纳秒调整到秒数,正或负
        System.out.println(second2);

        System.out.println(System.currentTimeMillis());
    }
}

输出

1552128157932
1552156957932
1552128158057
1552128158
1970-01-01T00:01:00Z
1970-01-01T00:01:00.000000060Z
1552128158073

由上可知,Instant 默认是基于格林时区的,它可以通过 .toEpochMilli() 来转换成跟 System.currentTimeMillis() 一样效果的时间戳格式,当然它也可以直接通过 .getEpochSecond() 来直接转换成秒的时间戳格式

表示日期的 LocalDate

以前的 Date 类在并发情境下做处理是很容易出现许多问题的(可以开多个线程来玩一下),而 LocalDate 可以更好的处理这种情况。从源码可以看到这一点: 如 final class LocalDate,private LocalDate(){}...,有一点点并发基础的一定懂这些含义。

LocalDate 类构建的几种方法以及他们的作用

public class LocalDateDemo {
    public static void main(String[] args) {
        LocalDate now = LocalDate.now(); // 和Instance一样默认的是格林时区
        System.out.println(now);

        LocalDate now2 = LocalDate.now(Clock.offset(Clock.systemUTC(), Duration.ofHours(24))); // 偏移格林时区24小时
        System.out.println(now2);

        LocalDate now3 = LocalDate.now(ZoneId.systemDefault()); // java.time.ZoneId是原有的java.util.TimeZone的替代品
        System.out.println(now3);

        LocalDate from = LocalDate.from(ZonedDateTime.now()); // 从时态对象(TemporalAccessor接口)获取LocalDate的实例
        System.out.println(from);

        LocalDate of = LocalDate.of(2017,5,21); // 参数分别为:year,month,dayOfMonth
        System.out.println(of);

        LocalDate epochDay = LocalDate.ofEpochDay(1800); // 比1970-01-01大多少天
        System.out.println(epochDay);

        LocalDate ofY = LocalDate.ofYearDay(2018,122); // 参数分别为 year , dayOfYear
        System.out.println(ofY);

        LocalDate parse = LocalDate.parse("2018-06-09"); // 字符串转换成LocalDate对象
        System.out.println(parse);
    }
}

输出

2019-03-09
2019-03-10
2019-03-09
2019-03-09
2017-05-21
1974-12-06
2018-05-02
2018-06-09

LocalDate 类一些比较有用的方法

  • public int getYear():获取年份信息
  • public int getMonthValue():获取月份信息
  • public int getDayOfMonth():获取当前日是这个月的第几天
  • public int getDayOfYear():获取当前日是这一年的第几天
  • public boolean isLeapYear():是否是闰年
  • public int lengthOfYear():获取这一年有多少天
  • public DayOfWeek getDayOfWeek():返回星期信息
  • public String format(DateTimeFormatter formatter): 格式化 LocalDate
  • public LocalDate minusYears(long yearsToSubtract):返回此 LocalDate 对象,并减去指定的年数。
  • public LocalDate plusDays(long daysToAdd):返回此 LocalDate 对象,并添加指定的天数。

太多了,这里就不一一列出来了...

时间 LocalTime

LocalTime 其实与上面的 LocalDate 类似,只不过 LocalTime 是来表示时间,而 LocalDate 是用作日期

LocalTime 类构建

public class LocalTimeDemo {
    public static void main(String[] args) {
        LocalTime now = LocalTime.now();
        System.out.println(now); // 输出19:54:31.010
    }
}
  • static LocalTime now():在默认时区中从系统时钟获取当前时间。
  • static LocalTime now(Clock clock):从指定的时钟获得当前时间。
  • static LocalTime now(ZoneId zone):从指定时区的系统时钟获取当前时间。
  • static LocalTime ofNanoOfDay(long nanoOfDay):从一天的纳米值获得 LocalTime 的实例。
  • static LocalTime from(TemporalAccessor temporal):从 temporal 对象获取 LocalTime 的实例。
  • static LocalTime of(int hour, int minute): 从指定小时分钟获得 LocalTime 的实例。
  • static LocalTime of(int hour, int minute, int second):从指定小时,分钟和秒钟获取 LocalTime 的实例。
  • static LocalTime of(int hour, int minute, int second, int nanoOfSecond):从指定小时,分钟,秒和纳秒获得 LocalTime 的实例。
  • static LocalTime parse(CharSequence text):从文本字符串中获取 LocalTime 的实例。

localTime 类的一些方法

public class LocalTimeDemo {
    public static void main(String[] args) {
        LocalTime now = LocalTime.now();
        String minute = now.getMinute()<10?"0"+now.getMinute():String.valueOf(now.getMinute());
        String second = now.getSecond()<10?"0"+now.getSecond():String.valueOf(now.getSecond());
        System.out.println("当前时间:"+now.getHour()+":"+minute+":"+second); //当前时间:20:09:13
        // 获取纳秒字段的值。
        System.out.println(now.getNano()); // 434000000
        // 与另一个时间比较。
        System.out.println(now.compareTo(LocalTime.MAX)); // -1
        // 将日期装换成String
        System.out.println(now.toString()); // 20:09:13.434
        // 将此时间与日期相结合以创建LocalDateTime。
        System.out.println(now.atDate(LocalDate.now())); // 2019-03-09T20:09:13.434
        // 创建一个新的LocalTime,并更改日期。
        System.out.println(now.withHour(8)); // 08:09:13.434
        // 创建一个此时间的偏移时间的LocalTime
        System.out.println(now.atOffset(ZoneOffset.ofHours(8))); // 20:09:13.434+08:00
        // 创建一个此时间加上8小时的Localtime
        System.out.println(now.plusHours(8)); // 04:09:13.434
    }
}

关于 LocalTime 还有一些其他的方法,请自行研究~~

时区相关的日期时间 ZonedDateTime

上面讲的 LocalDate、LocalTime 还有未讲到的 LocalDateTime 都是与时区无关的,都只是用的默认时区,而类的本身并没有存储时区。而上面的类要用到时区的话,还需要此类来协助。

public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        ZonedDateTime zdt = ZonedDateTime.now();
        System.out.println(zdt); // 2019-03-09T23:14:48.560+08:00[Asia/Shanghai]

        ZonedDateTime zdt2 = ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.of("America/Chicago"));
        System.out.println(zdt2); // 2019-03-09T23:14:48.560-06:00[America/Chicago]

        ZonedDateTime zdt3 = ZonedDateTime.ofInstant(Instant.now(),ZoneId.of("Africa/Cairo"));
        System.out.println(zdt3); // 2019-03-09T17:14:48.591+02:00[Africa/Cairo]
    }
}

解释一下,第一个输出系统默认时区。第二个输出的是没过芝加哥时区,两个参数,第一个是 LocalDate,第二个是 LocalTime(上面说过这两个类默认是没有任何时区的,想要时区还的结合 ZonedDateTime 类)。第二个输出是非洲开罗时区,这里传入的参数是时间戳 Instant

关于时间的工具类

日期时间格式化

上面讲 LocalDate 的时候有讲到一个 format 方法,里面传入的参数是 DateTimeFormatter,那这里就讲一下这个类吧。其实也没什么很多要讲的,毕竟它用起来真的太方便啦。一起来看看

public class DateTimeFormatterDemo {

    public static void main(String[] args) {
        LocalDateTime currentTime = LocalDateTime.now();

        // DateTimeFormatter默认规范有很多,这里只列举出了三个
        System.out.println(currentTime.format(DateTimeFormatter.BASIC_ISO_DATE)); // 20190309

        System.out.println(currentTime.format(DateTimeFormatter.ISO_DATE_TIME)); // 2019-03-09T23:39:02.261

        System.out.println(currentTime.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 2019-03-09

        System.out.println(currentTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"))); // 20190309
    }
}

真的使用起来太简单了,并且你想要的格式它基本都有

时间差 Period\Duration

1. Period

Period 是以年月日来衡量一个时间段,比如几年几月几日

public class PeriodDemo {

    public static void main(String[] args) {
        Period period = Period.of(2018,8,22);
        System.out.println(period);

        System.out.println(Period.between(LocalDate.of(2018,3,5), LocalDate.now()));
    }
}

输出

P2018Y8M22D
P1Y4D
  • P:标识开头
  • Y:年
  • M:月
  • D:日

2. Duration

Duration 也是表示一个时间段。不知道各位有没有注意到,其实上面例子中有用到过这个类 Duration.ofHours(8) 向后推迟 8 小时

public class DurationDemo {
    public static void main(String[] args) {
        LocalDateTime from = LocalDateTime.of(2018,Month.DECEMBER,22,22,33);//2018-12-22T22:33
        LocalDateTime to = LocalDateTime.now(); // 2019-03-10T00:05:42.443
        Duration duration = Duration.between(from, to); // PT1849H33M20.732S

        long days = duration.toDays();              // 这段时间的总天数
        long hours = duration.toHours();            // 这段时间的小时数
        long minutes = duration.toMinutes();        // 这段时间的分钟数
        long seconds = duration.getSeconds();       // 这段时间的秒数
        long milliSeconds = duration.toMillis();    // 这段时间的毫秒数
        long nanoSeconds = duration.toNanos();      // 这段时间的纳秒数
    }
}

其实使用多了这些类你会发现,这些类都有许多的共用。这些我这里就没有总结,请多动手,习惯成自然。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    169 引用 • 506 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • ahaha

    收藏了 😄