JDK 8 新特性 | 新时间日期 API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:

  • 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 − Java的日期/时间类的定义并不一致,在java.utiljava.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendarjava.util.TimeZone类,但他们同样存在上述所有的问题。

Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:

  • Local(本地) − 简化了日期时间的处理,没有时区的问题。
  • Zoned(时区) − 通过指定的时区处理日期时间。

新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。

下面先来介绍Java 8中新时间日期 API。

本地化日期时间 API:LocalDate 、LocalTime 、LocalDateTime


LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601 日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法。

方法 描述 示例
now() 静态方法,根据当前时间创建对象 LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
of() 静态方法,根据指定日期/时间创建对象 LocalDate localDate = LocalDate.of(2016, 10, 26);
LocalTime localTime = LocalTime.of(02, 22, 56);
LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays, plusWeeks, plusMonths, plusYears 向当前 LocalDate 对象添加几天、几周、几个月、几年 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
minusDays, minusWeeks, minusMonths, minusYears 从当前 LocalDate 对象减去几天、几周、几个月、几年
plus, minus 添加或减少一个 Duration 或 Period
withDayOfMonth, withDayOfYear, withMonth, withYear 将月份天数、年份天数、月份、年份修改为指定的值并返回新的 LocalDate 对象
getDayOfMonth 获得月份天数(1-31)
getDayOfYear 获得年份天数(1-366)
getDayOfWeek 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth 获得月份, 返回一个 Month 枚举值
getMonthValue 获得月份(1-12)
getYear 获得年份
until 获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字
isBefore, isAfter 比较两个 LocalDate
isLeapYear 判断是否是闰年

使用示例:

@Test                                                               
public void testLocalDateTime() {                                   

    // 获取当前的日期时间                                                    
    LocalDateTime ldt = LocalDateTime.now();                        
    System.out.println("当前时间: " + ldt);                             

    LocalDateTime ldt2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
    System.out.println("使用指定数据: " + ldt2);                          

    LocalDateTime ldt3 = ldt2.plusYears(20);                        
    System.out.println("加20年: " + ldt3);                            

    LocalDateTime ldt4 = ldt2.minusMonths(2);                       
    System.out.println("减2个月: " + ldt4);                            

    System.out.println("年: " + ldt.getYear());                      
    System.out.println("月: " + ldt.getMonthValue());                
    System.out.println("日: " + ldt.getDayOfMonth());                
    System.out.println("时: " + ldt.getHour());                      
    System.out.println("分: " + ldt.getMinute());                    
    System.out.println("秒: " + ldt.getSecond());                    
}                                                                                                                          

运行结果:

当前时间: 2018-06-17T21:59:07.883
使用指定数据: 2016-11-21T10:10:1020年: 2036-11-21T10:10:102个月: 2016-09-21T10:10:10
年: 2018
月: 6
日: 17
时: 21
分: 59
秒: 7

Instant 时间戳


用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算。

使用示例:

@Test                                                        
public void testInstant() {                                  
    // 默认使用 UTC 时区(0时区)                                      
    Instant ins = Instant.now();                             
    System.out.println(ins);                                 

    // 偏移8个时区                                                
    OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
    System.out.println(odt);                                 
    // 获取纳秒                                                  
    System.out.println(ins.getNano());                       

    // 在 1970年1月1日 00:00:00 加5秒                              
    Instant ins2 = Instant.ofEpochSecond(5);                 
    System.out.println(ins2);                                
}                                                            

运行结果:

2018-06-17T14:08:39.252Z
2018-06-17T22:08:39.252+08:00
252000000
1970-01-01T00:00:05Z

Duration 和 Period


  • Duration:用于计算两个“时间”间隔
  • Period:用于计算两个“日期”间隔

使用示例:

@Test                                                                  
public void testDurationAndPeriod() {                                  
    try {                                                              
        Instant ins1 = Instant.now();                                  
        Thread.sleep(1000); // 休息一秒                                    
        Instant ins2 = Instant.now();                                  
        System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));  

        System.out.println("----------------------------------");      

        LocalDate ld1 = LocalDate.now();                               
        LocalDate ld2 = LocalDate.of(2011, 1, 1);                      

        Period pe = Period.between(ld2, ld1);                          
        System.out.println(pe.getYears());                             
        System.out.println(pe.getMonths());                            
        System.out.println(pe.getDays());                              

    } catch (InterruptedException e) {                                 
    }                                                                  
}                                                                      

运行结果:

所耗费时间为:PT1.004S
----------------------------------
7
5
16

日期的操纵


  • TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
  • TemporalAdjusters : 该类通过静态方法提供了大量的常用TemporalAdjuster 的实现。

使用示例:

@Test                                                                       
public void testTemporalAdjuster() {                                        

    LocalDateTime ldt = LocalDateTime.now();                                
    System.out.println("当前日期: " + ldt);                                     

    LocalDateTime ldt2 = ldt.withDayOfMonth(10);                            
    System.out.println("设置为这个月的10号: " + ldt2);                              

    LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
    System.out.println("下个周日: " + ldt3);                                    

    // 自定义:下一个工作日                                                           
    LocalDateTime ldt5 = ldt.with((l) -> {                                  
        LocalDateTime ldt4 = (LocalDateTime) l;                             

        DayOfWeek dow = ldt4.getDayOfWeek();                                

        if (dow.equals(DayOfWeek.FRIDAY)) {                                 
            return ldt4.plusDays(3);                                        
        } else if (dow.equals(DayOfWeek.SATURDAY)) {                        
            return ldt4.plusDays(2);                                        
        } else {                                                            
            return ldt4.plusDays(1);                                        
        }                                                                   
    });                                                                     

    System.out.println("自定义:下一个工作日: " + ldt5);                              
}                                                                           

运行结果:

当前日期: 2018-06-17T22:29:02.459
设置为这个月的10号: 2018-06-10T22:29:02.459
下个周日: 2018-06-24T22:29:02.459
自定义:下一个工作日: 2018-06-18T22:29:02.459

解析与格式化


java.time.format.DateTimeFormatter 类:该类提供了三种
格式化方法:

  • 预定义的标准格式
  • 语言环境相关的格式
  • 自定义的格式

使用示例:

@Test                                                                             
public void testDateTimeFormatter() {                                             
    // DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;                  

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");

    LocalDateTime ldt = LocalDateTime.now();                                      
    String strDate = ldt.format(dtf);                                             
    System.out.println(strDate);                                                  

    LocalDateTime newLdt = ldt.parse(strDate, dtf);                               
    System.out.println(newLdt);                                                   
}                                                                                 

运行结果:

2018061722:31:14 星期日
2018-06-17T22:31:14

时区的处理:ZonedDate、ZonedTime、ZonedDateTime


Java8 中加入了对时区的支持,带时区的时间分别为:ZonedDate、ZonedTime、ZonedDateTime。

其中每个时区都对应着 ID地区ID ,都为 “{区域}/{城市}” 的格式。例如 :Asia/Shanghai 等。

  • ZoneId:该类中包含了所有的时区信息
  • getAvailableZoneIds() : 可以获取所有时区信息
  • of(id) : 用指定的时区信息获取 ZoneId 对象

使用示例:

@Test                                                                 
public void testZoned() {                                                 
    LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
    System.out.println(ldt);                                          

    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));   
    System.out.println(zdt);                                          
}

@Test                                              
public void testZoneId() {                         
    Set<String> set = ZoneId.getAvailableZoneIds();
    set.forEach(System.out::println);              
}                                                  

运行结果:

2018-06-17T22:34:16.216
2018-06-17T07:34:16.216-07:00[US/Pacific]
Asia/Aden
America/Cuiaba
Pacific/Honolulu
Pacific/Rarotonga
America/Guatemala
Australia/Hobart
Europe/London
......
US/Central
SystemV/EST5EDT
Pacific/Majuro
America/Argentina/Buenos_Aires
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco

源码地址:https://gitee.com/liupeifeng3514/JDK8_New_Features

猜你喜欢

转载自blog.csdn.net/liupeifeng3514/article/details/80721556