Java8中的时间和日期(下)

6 篇文章 1 订阅

在上篇文章Java中的时间和日期(上)里面,简单介绍了Java中的Date类,Calendar类以及用于格式化的SimpleDateFormater类。使用这些的时候我们会明显地感受到其中的不便之处,比如,Calendar类的月份是从0开始计数的;日期格式输出不够友好,很多情况下都需要使用SimpleDateFormater类来格式化;一些简单得日期计算也比较麻烦等等。所以就有了joda-time这种第三方库来简化java对于时间和日期的操作。为了改变这种情况,java 8中对时间和日期对处理就吸收了joda-time库的特性。那么新的时间日期处理会带来怎样的便捷呢?这便是本篇文章所要聊的内容。

Java8中,新的时间及日期API位于java.time包中,java.time包中的是类是不可变且线程安全的,主要类如下:

  • Instant——它代表的是时间戳
  • LocalDate——不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。
  • LocalTime——它代表的是不含日期的时间
  • LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。
  • ZonedDateTime——这是一个包含时区的完整的日期时间还有时区,偏移量是以UTC/格林威治时间为基准的。
  • Timezones——时区。在新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。
  •        时区定义了到格林威治时间(GMT)/UTC的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。

Java8中日期、时间API结构:

Java8常用的类介绍

1.月份的枚举类Month

java.time.Month枚举类:表示月份

在以前使用Java的时候,你一定痛恨了月份的表示和计算,最主要的原因就是因为一月份是从0开始计数的。

在Java 8中为了改变这一现状,增加了一个Month枚举类来表示月份。使用这个枚举类甚至还可以直接进行月份的加减运算

  • of(int month) 
    这是一个静态方法,用于创建一个Month对象。传入的参数当然是从1开始计数啦,1表示一月,12表示十二月。当传入的参数小于1或者大于12时,就会抛出异常。

  • getValue() 
    返回该Month对象当前的值。一月份返回1,二月份返回2,依次类推。

  • minus(long months) 
    这个是用来做月份的减法计算的。传入的参数表示你想在该Month对象的基础上减去几个月。如果是1月份减去2个月,返回的当然是11月份。

  • plus(long months) 
    用来计算月份的加法。传入的参数表示你想在该Month对象的基础上增加几个月。比如12月加2个月就变成了二月份。

  • maxLength(), minLength()和length(boolean leapYear) 
    用来获取Month对象表示的该月的日期数。其中,length(boolean leapYear)中的参数表示是否为闰年。其实这三个方法返回的结果在很多情况下都是一样的,返回的都是当月的日期数,30或者31。只有二月份除外,Month对象表示二月份时,maxLength()length(true)回29,minLength()length(false)返回28。

下面用代码来说明上述方法的使用:

public static void main(String[] args) {
    System.out.println(Month.DECEMBER);         // DECEMBER
    System.out.println(Month.of(2));            // FEBRUARY

    Month month = Month.FEBRUARY;        
    System.out.println(month.getValue());       // 2
    System.out.println(month.minus(3));         // NOVEMBER
    System.out.println(month.plus(2));          // APRIL

    System.out.println(month.length(false));    // 28
    System.out.println(month.length(true));     // 29
    System.out.println(month.maxLength());	//29
    System.out.println(month.minLength());	//28
}

有时候希望返回月份是中文,而不是英文。毕竟程序员大多都比较懒,能少转化一次自然是很好的。又或者你需要显示的是月份的英文缩写?Java 8都为你想到了。

只要调用 month.getDisplayName(TextStyle, Locale)方法就行:

第一个参数是文本类型,也就是说你想显示完整的名称还是缩写;

第二个参数表示地区,如果没有特殊要求,传入Locale.getDefault()就行。就像下面的代码演示的那样:

 

2.星期的枚举类DayOfWeek

java.time.DayOfWeek枚举类:用来表示一个周的七天。常用的方法和 Month枚举类的几乎一致,包括

of(int dayOfWeek)静态方法用于创建DayOfWeek对象;

getValue()方法用来获取该对象的值;

plus(long days)minus(long days)方法用来进行加减法计算。

getDisplayName(TextStyle style, Locale locale)来格式化输出。代码演示如下:

public static void main(String[] args) {
    System.out.println(DayOfWeek.FRIDAY);           // FRIDAY
    System.out.println(DayOfWeek.of(7));            // SUNDAY

    DayOfWeek dayOfWeek = DayOfWeek.TUESDAY;
    System.out.println(dayOfWeek.getValue());       // 2
    System.out.println(dayOfWeek.plus(3));          // FRIDAY
    System.out.println(dayOfWeek.minus(2));         // SUNDAY

    Locale defaultLocal = Locale.getDefault();
    System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL, defaultLocal));     // 星期二
    System.out.println(dayOfWeek.getDisplayName(TextStyle.SHORT, defaultLocal));    // 星期二
    System.out.println(dayOfWeek.getDisplayName(TextStyle.NARROW, defaultLocal));   // 二

    Locale locale = Locale.ENGLISH;
    System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL, locale));           // Tuesday
    System.out.println(dayOfWeek.getDisplayName(TextStyle.SHORT, locale));          // Tue
    System.out.println(dayOfWeek.getDisplayName(TextStyle.NARROW, locale));         // T
}

但是,在DayOfWeek枚举类中,是没有maxLength(), minLength()和length(boolean leapYear)这三个方法的,相信你们也知道是为什么。

最后说一句,由于MonthDayOfWeek只是枚举类,它们并不持有当前时间信息,所以就别妄想使用这两个枚举类来解决”今天是星期几”,”明天是几号”等问题了。

源码中的加减法计算

刚开始学Java的时候,计算月份/星期几乎是必备作业,不过当时用的是Date/Calendar类来计算,相当麻烦,

Java 8使用枚举来表示月份和星期之后,进行相应的加减法计算就变的相对简单了。

由于月份的计算和星期的计算原理是一样的,我们就只看Month的加减法计算。

private static final Month[] ENUMS = Month.values();

public Month plus(long months) {
    int amount = (int) (months % 12);
    return ENUMS[(ordinal() + (amount + 12)) % 12];
}

 public Month minus(long months) {
    return plus(-(months % 12));
}

这里的处理方法很巧妙,减法直接调用加法的处理逻辑,当年我就没想到过,哈哈,值得学习。

 

3. LocalDate和LocalTime类

java.time.LocalDate
java.time.LocalTime

重头戏来了,现在开始隆重介绍Java 8的常用的时间日期类:LocalDateLocalTime

使用 LocalDate可以获取当前日期(注意只是日期,不包含时间),并可以进行相应处理。

使用 LocalTime可以获取当前时间(注意只是时间,不包含日期)并进行相应处理。这样就更好的符合“单一职责原则”。

构造方法

根据不同的需求,提供了不同的创建方式,主要包括两个静态方法 now()of()方法。其实,在后面我们会看到,在Java 8中,创建时间和日期几乎都会用的这两个方法。

public static void main(String[] args) {
    LocalDate date1 = LocalDate.now();
    LocalDate date2 = LocalDate.of(1998, 2, 4);
    LocalDate date3 = LocalDate.ofEpochDay(180);

    System.out.println(date1);      // 2016-07-11
    System.out.println(date2);      // 1998-02-04
    System.out.println(date3);      // 1970-06-30

    LocalTime time1 = LocalTime.now();
    LocalTime time2 = LocalTime.now().withNano(0);
    LocalTime time3 = LocalTime.of(12, 30);
    LocalTime time4 = LocalTime.ofSecondOfDay(60 * 60 * 2);

    System.out.println(time1);      // 10:56:04.772
    System.out.println(time2);      // 10:56:04
    System.out.println(time3);      // 12:30
    System.out.println(time4);      // 02:00
}

withNano()方法会在后面提及,主要是修改当前对象表示的纳秒数的值。在上面的代码中,有几点需要注意的地方:

  • ofEpochDay(long epochDay)方法中的参数,指的是距1970年1月1日那天的时间间隔。
  • 在Java 8中,时间和日期的格式是按照ISO-8061的时间和日期标准来显示的。年份为4位数,月日时分秒都是2位数,不足两位用0补齐。

常用方法

LocalDate

还记得之前说过的,DayOfWeek枚举类不持有当前时间信息,所以你无法单独使用它来得到今天是星期几这种信息。然而如果获取到了当前日期的LocalDate对象后,问题就迎刃而解了。

LocalDate提供了大量的方法来进行日期信息的获取和计算。有了这一个LocalDate对象,你不仅可以知道这个对象是哪年几月几日星期几,还能够对于年月日进行加减法计算,甚至你可以以周为单位进行日期的加减法计算,比如,你可以轻松解决两个周前的今天是几月几日这类问题。

下面,是常用的方法,请自行查阅官方API文档

方法名返回值类型对该方法的解释
getYear()int获取当前日期的年份
getMonth()Month获取当前日期的月份对象
getMonthValue()int获取当前日期是第几月
getDayOfWeek()DayOfWeek表示该对象表示的日期是星期几
getDayOfMonth()int表示该对象表示的日期是这个月第几天
getDayOfYear()int表示该对象表示的日期是今年第几天
withYear(int year)LocalDate修改当前对象的年份
withMonth(int month)LocalDate修改当前对象的月份
withDayOfMonth(int dayOfMonth)LocalDate修改当前对象在当月的日期
isLeapYear()boolean是否是闰年
lengthOfMonth()int这个月有多少天
lengthOfYear()int该对象表示的年份有多少天(365或者366)
plusYears(long yearsToAdd)LocalDate当前对象增加指定的年份数
plusMonths(long monthsToAdd)LocalDate当前对象增加指定的月份数
plusWeeks(long weeksToAdd)LocalDate当前对象增加指定的周数
plusDays(long daysToAdd)LocalDate当前对象增加指定的天数
minusYears(long yearsToSubtract)LocalDate当前对象减去指定的年数
minusMonths(long monthsToSubtract)LocalDate当前对象减去注定的月数
minusWeeks(long weeksToSubtract)LocalDate当前对象减去指定的周数
minusDays(long daysToSubtract)LocalDate当前对象减去指定的天数
compareTo(ChronoLocalDate other)int比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚,
isBefore(ChronoLocalDate other)boolean比较当前对象日期是否在other对象日期之前
isAfter(ChronoLocalDate other)boolean比较当前对象日期是否在other对象日期之后
isEqual(ChronoLocalDate other)boolean比较两个日期对象是否相等

列出这么多方法,不是要你死记硬背记住它们,而是要在脑海有个印象,知道有哪些常用方法,可以做什么。概括起来,LocalDate类中常用的方法有四种:获取日期信息,修改日期信息,加减法运算和日期对象间的比较。记住了这些,以后在工作中就可以查阅使用,而不用自己在造一遍轮子。

有几点需要注意的地方:

  • 上面列表里面有一个ChronoLocalDate,它是一个接口,LocalDate类实现了这个接口,所以直接传一个LocalDate类对象即可。
  • isEqual(ChronoLocalDate other)这个方法,如果两个对象是同一个对象,或者这两个对象的值相等(同年同月同日),则返回true,否则返回false。
  • 当一个方法返回的是LocalDate对象时,便可以使用链式调用。举个例子,获取昨天的日期,我们可以直接这样写:LocalDate.now().minusDays(1)

下面用代码演示几个方法:

public static void main(String[] args) {
    LocalDate now = LocalDate.now();
    System.out.println(now.getYear());                  // 2016
    System.out.println(now.getDayOfWeek());             // MONDAY
    System.out.println(now.getDayOfMonth());            // 11
    System.out.println(now.withMonth(3));               // 2016-03-11
    System.out.println(now.minusWeeks(2));              // 2016-06-27
    System.out.println(now.plusDays(10));               // 2016-07-21

    LocalDate firstDayOfYear = LocalDate.of(2016,1,1);
    System.out.println(now.compareTo(firstDayOfYear));  // 6
    System.out.println(now.isAfter(firstDayOfYear));    // true
    System.out.println(now.isEqual(firstDayOfYear));    // false
}

LocalTime

LocalDate类中的方法和LocalDate中的类似,同样可以分为:获取时间信息,修改时间信息,加减法运算和时间对象间的比较。方法的具体描述我就不写了。根据LocalDate类中列举的常用方法,你也能猜得出在LocalTime类中有哪些对应的常用方法。下面还是用代码演示几个方法:

public static void main(String[] args) {
    LocalTime now = LocalTime.now();
    System.out.println(now.getHour());              // 14
    System.out.println(now.getMinute());            // 15
    System.out.println(now.getSecond());            // 22
    System.out.println(now.getNano());              // 881000000
    System.out.println(now.withNano(0));            // 14:15:22
    System.out.println(now.minusHours(3));          // 11:15:22.881
    System.out.println(now.minusMinutes(15));       // 14:00:22.881
    System.out.println(now.minusSeconds(20));       // 14:15:02.881

    LocalTime halfOfDay = LocalTime.of(12 ,0);
    System.out.println(now.compareTo(halfOfDay));   // 1
    System.out.println(now.isAfter(halfOfDay));     // true
}

不过有几点需要说明:

  • LocalTime中没有isEqual()方法。
  • getNano()中,nano指的是纳秒(毫微秒),1秒等于1亿纳秒。

 

4. LocalDateTime日期时间类

java.time.LocalDateTime

或许有人觉得,将日期和时间分开处理有些不方便。我想将时间和日期一起处理怎么办?当然可以,Java 8中还提供了LocalDateTime来满足你的这个需求。

构造方法

和前面的类似,可以使用静态方法now()和静态方法of()来创建一个LocalDateTime对象。比如:

public static void main(String[] args) {
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);        // 2016-07-11T14:27:20.169
    LocalDateTime dateTime1 = LocalDateTime.of(1990, 1, 1, 12, 3);
    LocalDateTime dateTime2 = LocalDateTime.of(2000, 2, 4, 8, 4, 20);
    System.out.println(dateTime1);  // 1990-01-01T12:03
    System.out.println(dateTime2);  // 2000-02-04T08:04:20
}

通常,你需要在of()方法中传入6个参数,表示年月日时分秒。关于月份,既可以传入Month对象,也可以传入int值(当然1表示一月份)。也可以将秒这个参数省略了,传入5个参数。也可以增加一个纳秒参数,变为7个参数。

常用方法,这个不想再说了,和LocalDateLocalTime类似。

 

LocalDateTime和LocalDate、LocalTime之间的转化

LocalDate、LocalTime、LocalDateTime之间的互相转换,也是可以走from方法:

        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDate localDate = LocalDate.from(localDateTime); //注意:不可以逆转
        LocalTime localTime = LocalTime.from(localDateTime); //注意:不可以逆转
        System.out.println(localDate);
        System.out.println(localTime);

Date类与新日期时间、时间戳之间转换需要注意的抗:

Date类型可以表示日期,也可以表示日期+时间。因此Date类型转LocalDate、LocalTime、Instant等类型的转换就非常重要了。注意一个坑:他们转换的中间桥梁都是 Instant对象,但是转换的时候如果没有考虑时区,就会报错的。

LocalDate、LocalTime、LocalDateTime转Date,借助中间变量Instant来实现。

        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();

        Instant instant = null;
        ZoneId zone = ZoneId.systemDefault();

        //LocalDateTime转Instant转Date
        instant = localDateTime.atZone(zone).toInstant();
        System.out.println(Date.from(instant));

        //LocalDate转Instant转Date
        instant = localDate.atStartOfDay().atZone(zone).toInstant();
        System.out.println(Date.from(instant));

        //LocalTime转Instant转Date(一般都不用)
        //必须先借助localDate转换成localDateTime 在转成instant 再转date
        LocalDateTime localDateTimeDate = LocalDateTime.of(localDate, localTime);
        instant = localDateTime.atZone(zone).toInstant();
        System.out.println(Date.from(instant));

Date转LocalDate、LocalTime等,借助LocalDateTime对象可保证万无一失。

        Date date = new Date();
        
        //时间戳转instant
        Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
        System.out.println(instant); // 注意:直接输出值是有时区问题的 时差8小时

        //Date直接转Instant
        System.out.println(date.toInstant());
        //Instant --> Date
        Date.from(Instant.now());
        //Calendar --> Instant(这个用得很少)
        Calendar.getInstance().toInstant();        


        // 注意时区的坑和date的表示含义
        // 以ZoneId.systemDefault转换成LocalDateTime后,就可以随意转换了
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        //方式一:使用LocalDate、LocalTime的from
        LocalDate fromLocalDate = LocalDate.from(localDateTime);
        LocalTime fromLocalTime = LocalTime.from(localDateTime);
        System.out.println(fromLocalDate);
        System.out.println(fromLocalTime);

        //方式二:直接to的方式
        LocalDate toLocalDate = localDateTime.toLocalDate();
        LocalTime toLocalTime = localDateTime.toLocalTime();
        System.out.println(toLocalDate);
        System.out.println(toLocalTime);

5.ZonedDateTime(带时区的日期和时间)

Java8使用ZoneId来标识不同的时区。ZonedDateTime的许多方法与LocalDateTime、LocalDate、LocalTime类似。

IANA(Internet Assigned Numbers Authority,因特网拨号管理局)维护着一份全球所有已知的时区数据库,Java使用了IANA的数据库。

        //获得所有可用的时区
        Set<String> allZones = ZoneId.getAvailableZoneIds();

        //获取默认ZoneId对象系统当前所在时区
        ZoneId defZoneId = ZoneId.systemDefault();
        //获取指定时区的ZoneId对象
        ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");

        //ZoneId.SHORT_IDS返回一个Map<String, String> 是时区的简称与全称的映射。下面可以得到字符串 Asia/Shanghai
        String shanghai = ZoneId.SHORT_IDS.get("CTT");
        System.out.println(shanghai); //Asia/Shanghai

 

6. 解析和格式化 - DateTimeFormatter类

在Date和Calendar统治的时代,想要格式化一个日期,只能用Date来格式化,并且SimpleDateFormat还有线程安全隐患,无疑很麻烦。所以在高并发环境下,需要使用SimpleDateFormat,我们可以借助ThreadLocal, 来保证线程安全:

    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(format(date));
    }
    private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    // 和线程绑定 保证安全
    public static String format(Date date) {
        return threadLocal.get().format(date);
    }

在Java 8中,java.time包中的是类是不可变且线程安全的。时间日期的格式是按照ISO-8061的时间和日期标准来显示的。年份为4位数,月日时分秒都是2位数,不足两位用0补齐,日期之间需要用短横线连接,时间之间要用:连接。必须按照此规则来进行解析,比如:

public static void main(String[] args) {
    LocalDate date = LocalDate.parse("2016-09-08");
    LocalTime time = LocalTime.parse("12:24:43");
    System.out.println(date);   // 2016-09-08
    System.out.println(time);   // 12:24:43
}

当然,Java是宽容的,如果你不按照ISO-8061的格式传入,也可以自定义格式。

DateTimeFormatter类:格式化器用于打印和解析日期时间对象。主要提供两种方法 : 一种用于格式化,一种用于解析。

        //String与LocalDate转换
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 解析
        LocalDate localDate = LocalDate.parse("20160708", formatter);
        // 格式化
        String str = formatter.format(localDate);
        System.out.println(str);        // 20160708
        System.out.println(localDate.toString()); // 2016-07-08

        //String与LocalDateTime转换,同理
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        // 解析
        LocalDateTime localDateTime = LocalDateTime.parse("2013/12/31 23:59:59", formatter2);
        // 格式化
        str = formatter2.format(localDateTime);
        System.out.println(str); // 2013/12/31 23:59:59
        System.out.println(localDateTime.toString()); 	// 2013-12-31T23:59:59

DateTimeFormatter预定义了一些格式,可以直接调用format方法。

根据当前操作系统语言环境,有SHORT MEDIUM LONG  FULL 四种不同的风格来格式化。

注意:FormatStyle.FULL – 此格式样式适用于LocalDate.但是使用LocalTime实例抛出异常,jdk9后修复了。

        System.out.println(DateTimeFormatter.BASIC_ISO_DATE.format(LocalDateTime.now()));
        System.out.println(DateTimeFormatter.ISO_DATE.format(LocalDateTime.now()));
        System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(LocalDateTime.now()));
        System.out.println(DateTimeFormatter.ISO_WEEK_DATE.format(LocalDateTime.now()));
        System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));

7. Clock时钟

clock类:提供给我们用于访问某个特定时区的当前瞬时时间或当期瞬时日期时间。

     

 方法等:

    • booleanequals(Object obj)

      检查这个时钟是否等于另一个时钟。

      abstract ZoneIdgetZone()

      获取用于创建日期和时间的时区。

      abstract Instantinstant()

      获取当前的时钟瞬间。

      longmillis()

      获取时钟的当前毫秒时间。

      static Clocksystem(ZoneId zone)

      获取使用最佳可用系统时钟返回当前时刻的时钟。

      static ClocksystemDefaultZone()

      获取使用最佳可用系统时钟返回当前即时的时钟,使用默认时区转换为日期和时间。

      static ClocksystemUTC()

      获取使用最佳可用系统时钟返回当前即时的时钟,使用UTC时区转换为日期和时间。

 ZoneId 是一个时区ID类,比如:Asia/Shanghai

    • static ZoneIdof(String zoneId)

      从ID获取一个 ZoneId的实例,确保该ID有效并且可供使用。

      static ZoneIdsystemDefault()

      获取系统默认时区。

        Clock c1 = Clock.systemUTC(); //系统默认UTC时钟(当前瞬时时间 System.currentTimeMillis())
        Clock c2 = Clock.systemDefaultZone(); //系统默认时区时钟(当前瞬时时间)
        Clock c3 = Clock.system(ZoneId.of("Asia/Shanghai"));//上海时区
        Instant instant = c3.instant();      
        
        System.out.println(c3.millis());//1532179594406
        System.out.println(c3.getZone());//Asia/Shanghai

8.Instant瞬时时间

java.time.Instant类:表示瞬时时间,等价于以前的System.currentTimeMillis()

Instant由两部分组成,代表到格林威治时间(GMT)/UTC的时间,没有时区的作用。所以上面的转换时需要考虑时区。

  1. 从原点开始到指定时间点的秒数s(用long存储),
  2. 距离该秒数s的纳秒数(用int存储)。
    • static Instantnow()

      从系统时钟获取当前瞬间。

      static Instantnow(Clock clock)

      从指定的时钟获取当前时刻。

//瞬时时间 相当于以前的System.currentTimeMillis()  
Instant instant1 = Instant.now();  
System.out.println(instant1.getEpochSecond());//精确到秒 得到相对于1970-01-01 00:00:00 UTC的时间 1532179778  
System.out.println(instant1.toEpochMilli()); //精确到毫秒   1532179778266
		  
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 

9. java.time.Duration

java.time.Duration表示一段时间。可以是用来处理时间戳的差值计算。

        //指定时间的Instant
        Instant temp = Instant.parse("2007-12-03T10:15:30.00Z");
        Instant now = Instant.now();
        Instant instant = now.plusSeconds(TimeUnit.HOURS.toSeconds(25));

        //希望得到两个时间戳,他们相隔了几个小时、几天、几个月?
        System.out.println(now.until(instant, ChronoUnit.HOURS)); //25
        System.out.println(now.until(instant,ChronoUnit.DAYS)); //1(这里显示1不是2哦)
        System.out.println(instant.until(now,ChronoUnit.HOURS)); //-25(注意,这里是负数哦)

        Instant start =  Instant.parse("2017-12-03T10:15:30.00Z");
        // doSomething();
        Instant end = Instant.now();
        //计算时间差
        Duration timeElapsed = Duration.between(start, end);
        long millis = timeElapsed.toMillis();
        System.out.println("millis = " + millis);

10.java.time.Period

java.time.Period类:可以计算两个日期之间包含多少天、周、月、年等。

        LocalDate start = LocalDate.of(2017,10,15);
        LocalDate end = LocalDate.now();
        System.out.println(start);
        System.out.println(end);

        //日常熟悉的表示法,间隔多少年多少月多少天
        Period p = Period.between(start, end);
        System.out.println("相差:" + p.getYears()+"年"+ p.getMonths() + "月" + p.getDays()+ "日");

        //要得到前后的天数绝对值
        long distance = ChronoUnit.DAYS.between(start, end);
        System.out.println("相差:" + distance + "天");

        // 得到前后的天数绝对值,可以输出在两个日期之间获得所有日期
        List<LocalDate> allDays = new ArrayList<>();
        for (int i = 0; i <= distance; i++) {
            allDays.add(start.plusDays(i));
        }
        System.out.println(allDays);

11.时间矫正器(TemporalAdjuster )

TemporalAdjuster : 时间校正器。

有时我们可能需要获取例如:将日期调整到“下个周日”等操作。不过它是个函数式接口。

TemporalAdjusters : 该类通过静态方法提供了大量的常用TemporalAdjuster 的实现。

时间矫正,用的都是with语法。可以理解成和set差不多。

        LocalDateTime ldt1 = LocalDateTime.now();
        //本月第一天
        LocalDateTime ldt2 = ldt1.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println(ldt2);
        //本月的第一个周五
        LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY));
        System.out.println(ldt3);

        // 获取当前时间的下一个工作日(不考虑法定节假日的情况)自己实现一个时间矫正器
        LocalDate localDate = LocalDate.now();
        LocalDate with = localDate.with(x -> {
            LocalDate date = (LocalDate) x;
            DayOfWeek dayOfWeek = date.getDayOfWeek();
            if (dayOfWeek == DayOfWeek.FRIDAY) {
                return date.plusDays(3);
            } else if (dayOfWeek == DayOfWeek.SATURDAY) {
                return date.plusDays(2);
            } else {
                return date.plusDays(1);
            }
        });
        System.out.println(with);

参考文章: https://blog.csdn.net/wl9739/article/details/51882913

ends~

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值