Java日期时间API系列35—–Jdk8中java.time包中的新的日期时间API类应用,微秒和纳秒等更精确的时间格式化和解析。

  通过Java日期时间API系列1—–Jdk7及以前的日期时间类中得知,Java8以前除了java.sql.Timestamp扩充纳秒,其他类最大只精确到毫秒;Java8 time包所有相关类都支持纳秒。下面是示意图:

 

 

图中的nano 是 一秒钟包含的纳秒值,0到999999999。毫秒,微秒和纳秒都是通过这个值计算得到的。

 

1.Timestamp格式化中的纳秒。

java.sql.Timestamp.toString()方法中的格式为:

格式化模板是:yyyy-mm-dd hh:mm:ss.fffffffff,这里的 fffffffff 指的是纳秒,但会将最后的0省略掉。比如:

2020-05-23 17:06:30.0
2020-05-23 17:06:30.272
2020-05-23 17:06:30.27215
2020-05-23 17:06:30.27215062

 

2.Timestamp格式解析

.

/**
     * 解析Timestamp格式字符串为LocalDateTime  默认格式 yyyy-mm-dd hh:mm:ss.fffffffff 其中 fffffffff 纳秒,省略后面的0 比如:
     * 
     * 2020-05-23 17:06:30.0
     * 2020-05-23 17:06:30.272
     * 2020-05-23 17:06:30.27215
     * 2020-05-23 17:06:30.27215062
     *

* @param text
*
@return LocalDateTime
*/
public static LocalDateTime parseTimestampStyleToLocalDateTime(String text){
//预处理
Objects.requireNonNull(text, "text");
text
=text.trim();
if(!text.contains(".")){
throw new DateTimeException("text is not supported! " + text);
}

//.分割成2部分,分别分析
String[] textArr = text.split("\\.");
String main
= textArr[0];
String nanoOfSecond
= textArr[1];
int mainLen = main.length();
int len = nanoOfSecond.length();
if(mainLen != DateFormatPattern.YYYY_MM_DD_HH_MM_SS.length()){
throw new DateTimeException("text is not supported! " + text);
}
if(len>9){
throw new DateTimeException("text is not supported! " + text);
}

//纳秒部分补0
StringBuilder sb = new StringBuilder();
for(int i=0;i<9-len;i++){
sb.append(
"0");
}
nanoOfSecond
= nanoOfSecond+sb.toString();
text
= main+"."+nanoOfSecond;

//使用yyyy-MM-dd HH:mm:ss.SSSSSSSSS 标准格式解析
return parseToLocalDateTime(text, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_SSSSSSSSS_FMT);
}

 

测试:

  /**
     * 含纳秒Timestamp时间格式解析
     */
    @Test
    public void parseTimestampStyleTest(){
        
        Date date = DateTimeFormatterUtil.smartParseToDate("2020-05-23 17:06:30");
        
        Date date2 = DateTimeFormatterUtil.parseTimestampStyleToDate("2020-05-23 17:06:30.0");
        
        Date date3 = DateTimeFormatterUtil.parseTimestampStyleToDate("2020-05-23 17:06:30.0");
        
        Assert.assertEquals(date, date2);
        Assert.assertEquals(date2, date3);
        
        LocalDateTime localDateTime1 = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23 17:06:30.272150");
        
        LocalDateTime localDateTime2 = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23 17:06:30.27215");
        Assert.assertEquals(localDateTime1, localDateTime2);
    }

 

 

 

3.微秒和纳秒的格式化和解析

 // ==================================yyyy-MM-dd HH:mm:ss.SSSSSS 相关Pattern==================================    
    
    /**
     * yyyy-MM-dd HH:mm:ss.SSSSSS 比如:2020-05-23 17:06:30.272150
     */
    public static final String YYYY_MM_DD_HH_MM_SS_SSSSSS = "yyyy-MM-dd HH:mm:ss.SSSSSS";
    
    
    
    // ==================================yyyy-MM-dd HH:mm:ss.SSSSSSSSS 相关Pattern==================================    
    
    /**
     * yyyy-MM-dd HH:mm:ss.SSSSSSSSS 比如:2020-05-23 17:06:30.272150620
     */
    public static final String YYYY_MM_DD_HH_MM_SS_SSSSSSSSS = "yyyy-MM-dd HH:mm:ss.SSSSSSSSS";    

 

 

(1)格式化

  /**
     * 含纳秒时间格式化
     */
    @Test
    public void formatTimeWithNanoTest(){
        LocalDateTime localDateTime = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23T17:06:30.272150620+08:00");
        //时间格式化
        Assert.assertEquals("17:06:30.272", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.HH_MM_SS_SSS_FMT));
        Assert.assertEquals("17:06:30.272150", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.HH_MM_SS_SSSSSS_FMT));
        Assert.assertEquals("17:06:30.272150620", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.HH_MM_SS_SSSSSSSSS_FMT));
        
        //日期时间格式化
        Assert.assertEquals("2020-05-23 17:06:30.272150", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_SSSSSS_FMT));
        Assert.assertEquals("2020-05-23 17:06:30.272150620", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_SSSSSSSSS_FMT));

        //ISO日期时间格式化
        Assert.assertEquals("2020-05-23T17:06:30.272150620+0800", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_SSSSSSSSS_Z_FMT));
        Assert.assertEquals("2020-05-23T17:06:30.272150620+08:00", DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_SSSSSSSSS_XXX_Z_FMT));
    }

 

 

 

(2)解析

 /**
     * 含纳秒时间格式解析
     */
    @Test
    public void parseTimeWithNanoTest(){
        LocalDateTime localDateTime1 = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23T17:06:30.272150620+08:00");
        
        LocalDateTime localDateTime2 = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23T17:06:30.272150+08:00");
        
        LocalDateTime localDateTime3 = DateTimeFormatterUtil.smartParseToLocalDateTime("2020-05-23T17:06:30.272+08:00");
        
        Assert.assertTrue(localDateTime3.isBefore(localDateTime2));
        
        Assert.assertTrue(localDateTime2.isBefore(localDateTime1));
    }

 

4.LocalDateTime转Date会精度丢失,丢失毫秒以后部分。

因为Date只精确到毫秒,下面是转换方法:DateTimeConverterUtil类中

    /**
     * LocalDateTime转Date
     * @param localDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
Date from(Instant instant)方法:
    public static Date from(Instant instant) {
        try {
            return new Date(instant.toEpochMilli());
        } catch (ArithmeticException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

 

 核心部分:new Date(instant.toEpochMilli()); 创建Date只使用了Instant的时间戳部分 instant.toEpochMilli()。只到毫秒。

 

源代码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列34—–Jdk8中java.time包中的新的日期时间API类应用,使用Period一行代码计算生日。

  通过Java日期时间API系列9—–Jdk8中java.time包中的新的日期时间API类的Period和Duration的区别中得知,Period可以比较2个日期相差的年月日。年龄计算是2个日期相差的年的值,具体还要根据月日微调,如果小于生日年龄减1。下面使用Period可以非常方便的计算年龄。

 

1.使用Period一行代码计算生日

核心代码就是一行代码: 

Period.between(birthDay, LocalDate.now()).getYears();

 

 

    /**
     * 计算年龄
     * @param birthDay
     * @return int 年龄
     */
    public static int getAge(LocalDate birthDay){
        Objects.requireNonNull(birthDay, "birthDay");
        Period period = Period.between(birthDay, LocalDate.now());
        if (period.getYears() < 0) {
            throw new DateTimeException("birthDay is before now!");
        } else {
            return period.getYears();
        }
    }
    
    /**
     * 计算年龄
     * @param birthDay
     * @return int 年龄
     */
    public static int getAge(Date birthDay){
        return getAge(DateTimeConverterUtil.toLocalDate(birthDay));
    }
    
    /**
     * 计算年龄
     * @param birthDay
     * @return int 年龄
     */
    public static int getAge(LocalDateTime birthDay){
        return getAge(DateTimeConverterUtil.toLocalDate(birthDay));
    }

 

 

测试代码:

 

    /**
     * 年龄生日测试
     */    
    @Test
    public void getAgeBirthDayTest(){
        Date date = DateTimeCalculatorUtil.getDate(2000, 6, 4);
        System.out.println(DateTimeCalculatorUtil.getAge(date));
        
    }

 

 

输出:

20

 

2.使用Java8以前的Calendar计算生日

public static int getAgeByBirth(Date birthDay) throws ParseException {
        int age = 0;
        Calendar cal = Calendar.getInstance();
        if (cal.before(birthDay)) { //出生日期晚于当前时间,无法计算
            throw new IllegalArgumentException(
                    "The birthDay is before Now.It's unbelievable!");
        }
        int yearNow = cal.get(Calendar.YEAR);  //当前年份
        int monthNow = cal.get(Calendar.MONTH);  //当前月份
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
        cal.setTime(birthDay);
        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
        age = yearNow - yearBirth;   //计算整岁数
        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前,年龄减一
            } else {
                age--;//当前月份在生日之前,年龄减一
            }
        }
        return age;
    }

 

原地址:https://blog.csdn.net/sunnyljs/java/article/details/80934685

测试代码

@Test
    public void getAgeByBirthTest() throws ParseException{
        Date date = DateTimeCalculatorUtil.getDate(2000, 6, 4);
        System.out.println(getAgeByBirth(date));
    }

 

输出

20

 

3.对比上面2种方法,Java8 时间api非常方便。

(1)Period线程安全。

(2)Period一行代码非常简洁。

 

 

源代码地址:https://github.com/xkzhangsan/xk-time