JDK8 日期 API 使用

早期日期类的问题

Date 类在 JDK1.1 之前就已经有了,从 API 可以发现,从 JDK1.1开始 Date 类中的好多方法都已经被弃用,Java1.1推荐采用 Calendar 类处理日期和时间,但是这个类同样存在不少问题

Constructor and Description
Date() 分配一个 Date对象,并初始化它,以便它代表它被分配的时间,测量到最近的毫秒。
Date(int year, int month, int date) 已弃用 截至JDK 1.1版,由Calendar.set(year + 1900, month, date)GregorianCalendar(year + 1900, month, date)
Date(int year, int month, int date, int hrs, int min) 已弃用 从JDK 1.1版开始,替换为Calendar.set(year + 1900, month, date, hrs, min)GregorianCalendar(year + 1900, month, date, hrs, min)
Date(int year, int month, int date, int hrs, int min, int sec) 已弃用 截至JDK 1.1版,由Calendar.set(year + 1900, month, date, hrs, min, sec)GregorianCalendar(year + 1900, month, date, hrs, min, sec)
Date(long date) 分配一个 Date对象,并将其初始化为表示自称为“时代”的标准基准时间以后的指定毫秒数,即1970年1月1日00:00:00 GMT。
Date(String s) 已弃用 从JDK 1.1版开始,由DateFormat.parse(String s)

老版本 API 计算困难问题

例子:小明出生于 1995年 12 月20日,计算当前这个时间他已经出生了多少天
步骤思路:
1、初始化 Date 对象,利用无参构造方法
2、获取当前时间距离 1970年1月1日过了多少毫秒
3、初始化 Calendar 对象并设置为 1995年6月20日,并将 Calendar 对象转化为 Date 对象,再转换 1995年6月20日距离 1970年1月1日过了多少毫秒
4、将两个毫秒数做相减操作,然后将毫秒数转换为天数
Date date = new Date();
long nowTime = date.getTime();
Calendar calendar = Calendar.getInstance();
//小心这个坑,calendar 中月份是加一的
calendar.set(1995, 11, 20);
Date birthdayDate = calendar.getTime();
long birthdayTime = birthdayDate.getTime();
//毫秒/1000(秒)/60(分钟)/60(小时)/24(天)
long day = (nowTime-birthdayTime)/1000/60/60/24;
System.out.println("1995年 12 月20日 距离现在 "+ day+"天");//1995年 12 月20日 距离现在 8892天
// 来看看 Java8 新版本 API 如何操作
day = ChronoUnit.DAYS.between(LocalDate.of(1995, 12, 20), LocalDate.now());
System.out.println("1995年 12 月20日 距离现在 "+ day+"天");//1995年 12 月20日 距离现在 8893天

可以看到两种方式计算的结果差了一天,如果自己用计算器算的话,发现后者是对的,说明前者在毫秒转换计算的时候出现了一点误差…

线程安全问题

我们之前对时间的格式化转换一般是用 SimpleDateFormat 类,但是这个类是线程不安全的,在多线程情况下,全局共享一个 SimpleDateFormat 类中的 Calendar 对象有可能出现异常。

/**
 * 创建 10 个线程,将字符串"2018-12-12 12:12:12" 转换为 Date 对象后打印到控制台上
 */
public class Test2 {
    
    
    final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) {
    
    
        //循环,创建 10 个线程
        for(int i=0; i<10; i++){
    
    
            new Thread(()->{
    
    
                try {
    
    
                    Date date = SIMPLE_DATE_FORMAT.parse("2018-12-12 12:12:12");
                    System.out.println(date);
                } catch (ParseException e) {
    
    
                    e.printStackTrace();
                }
            },"threadName"+i).start();
        }
    }
}

在这里插入图片描述
当然啦,解决的方法无非就是加同步代码块呗

而新版本日期 API 都是线程安全的

其它

另外一个问题就是在 java.util.Date 和 java.util.Calendar 类之前,枚举类型还没有出现,所以在字段中使用整数常量都是可变的,而不是线程安全的,为了处理实际开发中遇到的问题,标准库随后引入了 java.sql.Date 作为 java.util.Date 的子类,但是还是没能彻底解决问题。

最终 Java 8 引入了java.time 包,这种全新的包从根本上解决了长久以来存在的诸多弊端

初始化 Calendar 对象,封装日期 2018年8月8日
Calendar calendar = Calendar.getInstance();
//通过 set 方法设置年月日,-> 开发规范:不允许使用没有定义的魔法数字
//出现提示:Should be one of: Calendar.JANUARY, Calendar.FEBRUARY, Calendar.MARCH, Calendar.APRIL...
calendar.set(2018,8,8);
//应该这样,而 calendar 月份从0开始,很容易就忘记
calendar.set(2018,Calendar.AUGUST,12);

Date-Time API 中基本类的使用

Date-Time API 中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过 new 直接创建,需要采用工厂方法加以实例化

System.out.println(Instant.now());//2020-04-18T01:08:23.712Z
System.out.println(LocalDate.now());//2020-04-18
System.out.println(LocalTime.now());//09:08:23.856
System.out.println(LocalDateTime.now());//2020-04-18T09:08:23.857
System.out.println(ZonedDateTime.now());//2020-04-18T09:08:23.857+08:00[Asia/Shanghai]

不仅仅是刚才提供的几个类可以使用 now 方法,Java8 的 Time 包还提供了其它的几个类可以更精确的获取某些信息:

System.out.println(Year.now());//2020
System.out.println(YearMonth.now());//2020-04
System.out.println(MonthDay.now());//--04-18

注意:没有 Month.now(),Month 是个枚举类,有1-12月

of 方法在日期 /时间类的应用

of 方法可以根据给定的参数生成对应的日期/时间对象,基本上每个类都有对应的 of 方法用于生成指定的日期/时间对象,而且重载形式多变,可以根据不同的参数生成对应的数据。

System.out.println(LocalDate.of(2018,8,8));//2018-08-08
System.out.println(LocalTime.of(2,38,20));//02:38:20
System.out.println(LocalDateTime.of(2019,9,9,9,0));//2019-09-09T09:00
System.out.println(YearMonth.of(2020,5));
System.out.println(MonthDay.of(4,22));

对于 LocalTime,如果是初始化晚上的时间,需要加12;如果秒和纳秒是0的话,那么默认不会封装这些数据,只显示小时和钟

System.out.println(LocalTime.of(18,30));//晚上 18:30 
System.out.println(LocalTime.of(19,30,0,0));//晚上 19:30 

注意 LocalDateTime 有个特殊重载方法:of(LocalDate date, LocalTime time)

为 LocalDateTime 添加时区信息

在打印 ZonedDateTime 的时候,发现这个对象封装不仅有时间日期,还有时区,那么时区在 Java 如何获取呢?通过提供的一个类 ZoneId 的 getAvailableZoneIds() 方法可以获取到一个 Set 集合,集合中封装了 600 个时区

System.out.println(ZoneId.systemDefault());//Asia/Shanghai
System.out.println(ZoneId.getAvailableZoneIds());//所有的时区,结果是 set 集合

我们可以通过给 LocalDateTime 添加时区来查看到不同时区的时间,比如 LocalDateTime 中封装的时间是上海时间,想知道此时此刻纽约的时间是什么,就可以将纽约的时区添加进去即可查看到:

  • 封装时间 LocalDateTime 并添加时区信息
  • 更改时区查看对应时间
//1、此时 localDateTime 只是封装了一个时间,并没有时区的概念
LocalDateTime localDateTime = LocalDateTime.of(2018, 11, 28, 8, 54, 38);
//2、添加时区,
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println("Asia/Shanghai 时间:"+zonedDateTime);
//3、更改时区
zonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("同一时刻 Asia/Tokyo 时间:"+zonedDateTime);

Month 枚举类的使用

java.time 包引入了 Month 枚举类,Month 中包含标准日历中的12个月份的常量,也提供了一些方法供我们使用,推荐在初始化 LocalDate 和 LocalDateTime 对象的时候,月份的参数使用 Month 枚举类方式传入,这样简单易懂更不容易出错,因为如果旧的思维, Calendar 月份从0开始,在新 API 传0会出现异常

//月份建议传 Month 枚举
System.out.println(LocalDate.of(2020, Month.OCTOBER, 23));//2020-10-23
//Month.of() 可以根据传入的数字返回对应的枚举
System.out.println(Month.of(12));//DECEMBER

根据现有实例创建日期与时间对象

想要修改某个日期/时间对象的现有实例时,我们可以使用 plus 和 minus 方法来完成操作。
Java 8中时间相关API 的实例都是不可变的,一旦创建,LocalDate,LocalDateTime,LocalTime 就无法修改(类似 String),这对于线程安全非常有利。

//封装一个日期对象,对象生成后,localDate 是无法修改的
LocalDate localDate = LocalDate.of(2020, 3, 20);//2020-03-20
//计算 4 天后的时间, 注意返回的是一个新对象,
LocalDate plusDays = localDate.plusDays(4);//2020-03-24
//计算 3 周后的时间
LocalDate plusWeeks = localDate.plusWeeks(3);//2020-04-10
//计算 5 个月后的时间
LocalDate plusMonths = localDate.plusMonths(5);//2020-08-20
//计算 6 年后的时间
LocalDate plusYears = localDate.plusYears(6);//2026-03-20

上面是加时间,减同理,minusXXX(),查看源码发现,底层调用的还是 plusXX方法

Period、Duration、ChronoUnit 计算时间差

Period类主要是方法getYears(),getMonths()和getDays()来计算,Period 更多的是计算一段时期,比如Period.between(LocalDate.of(2019,5,1),LocalDate.of(2020,5,1)).getDays() 是0,通过getYears 可以得出1 年

LocalDate today = LocalDate.now();
LocalDate birthDate = LocalDate.of(1995, Month.JUNE, 20);
Period p = Period.between(birthDate, today);
System.out.printf("年龄 : %d 年 %d 月 %d 日",p.getYears(),p.getMonths(),p.getDays());

==========sout==========
年龄 : 241011

Duration 提供了使用基于时间的值(如秒,纳秒)测量时间量的方法。

Instant inst1 = Instant.now();
Instant inst2 = inst1.plus(Duration.ofSeconds(10));
System.out.println("相隔毫秒 : " + Duration.between(inst1, inst2).toMillis());
System.out.println("相隔秒 : " + Duration.between(inst1, inst2).getSeconds());
System.out.println("相隔纳秒 : " + Duration.between(inst1, inst2).getNano());

==========sout============
相隔毫秒 : 10000
相隔秒 : 10
相隔纳秒 : 0

ChronoUnit 类可用于在单个时间单位内测量一段时间,例如天数或秒。

LocalDate startDate = LocalDate.of(1993, Month.OCTOBER, 19);
LocalDate endDate = LocalDate.now();
long days = ChronoUnit.DAYS.between(startDate, endDate);
System.out.println("相隔天数   : " + days);

============sout===============
相隔天数   : 9691

当然要计算相隔多少小时得用 LocalDateTime 了,ChronoUnit.HOURS.between(LocalDateTime.of(2019, 5, 1,12,1,2), LocalDateTime.of(2020, 5, 1,2,4,1)),非常简单。

plus 和 minus 方法的应用

上面我们都是对 日期/时间的 某一项进行加减,其实还有两个单独的 plus 方法,Temporal plus(TemporalAmount amount)Temporal plus(long amountToAdd, TemporalUnit unit)

问题:今天小张查看自己车辆保险记录的时候发现还有 2年3个月8天就到期了,计算到期的时间是什么时候

方法一:plusXXX()方法

LocalDate now = LocalDate.now();
//在当前时间基础上加操作 2年3个月8天
LocalDate endTime = now.plusYears(2).plusMonths(3).plusDays(8);
//当前时间:2020-04-25 保险到期时间:2022-08-02
System.out.println("当前时间:"+now+" 保险到期时间:"+endTime);

方法二:plus(TemporalAmount amountToAdd)
TemporalAmount 是一个接口,当接口作为方法参数的时候,实际上传入的是接口的实现类,查看这个接口的实现体系,可以看到有一个类 Period,这个类表示一段时间

LocalDate now = LocalDate.now();
Period period = Period.of(2, 3, 8);
LocalDate endTime = now.plus(period);
//当前时间:2020-04-25 保险到期时间:2022-08-02
System.out.println("当前时间:"+now+" 保险到期时间:"+endTime);

在实际的开发过程中,可能会更精确的去操作日期或者说增加一些特殊的时间,比如说一个实际,一个半天,1千年,Java8 提供了这些日期的表示方式而不需要单独进行计算了。

TemporaUnit 是一个接口,通过接口继承体现可以发现,可以使用子类 ChronoUnit 来表示,ChronoUnit 封装了很多时间段供我们使用。

在这里插入图片描述

//在这天结婚
LocalDateTime marryTime = LocalDateTime.of(2020, 2, 2, 11, 11, 11);
//十年后称为 锡婚
LocalDateTime time = marryTime.plus(1, ChronoUnit.DECADES);//2030-02-02T11:11:11
//半天后(12小时)再请朋友们吃饭
LocalDateTime eatTime = time.plus(1, ChronoUnit.HALF_DAYS);//2030-02-02T23:11:11

with 方法在日期/时间类的应用

以 LocalDateTime 为例,如果不需要对日期进行加减而是要直接修改日期的话可以使用 with 方法,with 方法提供了很多修改时间的方式

//在实际业务中可能调用的是别人的方法获得时间
LocalDateTime time = getTime();
//经过使用发现这个 time 的时间有误,日期应该是 1号
//那么在不知道原有时间的基础上,无法进行增减操作,可以直接使用 with 方法进行修改
LocalDateTime resultTime1 = time.withDayOfMonth(1);
//这种方法也是可以的
LocalDateTime resultTime2 = time.with(ChronoField.DAY_OF_MONTH,1);
System.out.println("原来的时间:"+time);
System.out.println("修正后的时间:"+resultTime1);
System.out.println("修正后的时间:"+resultTime2);

======输出===========
原来的时间:2018-12-12T08:28:44
修正后的时间:2018-12-01T08:28:44
修正后的时间:2018-12-01T08:28:44

当然还有 withHour()、withYear()、withDayOfYear()…等方法

调节器 TemporalAdjuster 与查询 TemporalQuery

之前我们通过 with 方法修改日期中封装的 数据,但是有些时候可能会做些复杂的操作,比如将时间调整到下个周的周日,下一个工作日,或者本月的某一天,这个时候可以使用 调节器TemporalAdjuster 来更方便的处理日期

LocalDate now = LocalDate.now();
//修改为本月的第一天
LocalDate firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth());
//修改为当月的最后一天
LocalDate lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth());
//修改为当年的最后一天
LocalDate lastDayOfYear = now.with(TemporalAdjusters.lastDayOfYear());
//修改为下一年的第一天
LocalDate firstDayOfNextYear = now.with(TemporalAdjusters.firstDayOfNextYear());
//修改为下个月的第一天
LocalDate firstDayOfNextMonth = now.with(TemporalAdjusters.firstDayOfNextMonth());

//修改为下一个周日
LocalDate nextSunday = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
//修改为上一个周三
LocalDate previousWEDNESDAY = now.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));

自定义 TemporalAdjusters 调节器

通过 Java8 本身提供的 TemporalAdjusters 中方法可以完成一些常用的操作,如果要自定义日期的时间的更改逻辑,可以通过实现 TemporalAdjuster 接口的方式完成
思考:发薪日是每月 15号,如果发薪日是周末,则调整为周五

自定义调节器

public class DateAdjuest implements TemporalAdjuster {
    
    
    @Override
    public Temporal adjustInto(Temporal temporal) {
    
    
        LocalDate payDate = LocalDate.from(temporal);
        //把发薪日修改为 15
        LocalDate realPayDay = payDate.withDayOfMonth(15);
        //接着判断这个日子是不是周末,如果是则提前改为上一个周五 发工资
        if (payDate.getDayOfWeek()== DayOfWeek.SUNDAY || payDate.getDayOfWeek()==DayOfWeek.SATURDAY)
            realPayDay = realPayDay.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
        return realPayDay;
    }
}
LocalDate date = LocalDate.of(2019, 12, 15);
LocalDate realtime = LocalDate.from(new DateAdjuest().adjustInto(date));
System.out.println("原来的日期是:"+date+"真实发薪日:"+realtime);
========输出=============
原来的日期是:2019-12-15真实发薪日:2019-12-13

TemporalQuery 的使用

LocalDate、LocalTime 有一个方法叫做 query,可以针对日期进行查询,query(TemporalQuery<R> query) 是一个泛型方法,返回的数据就是传入的泛型类型,而 TemporalQuery 是一个泛型接口,里面有一个抽象方法 queryFrom(TemporalAccessor temporal) ,TemporalAccessor 是 Temporal 的父接口,实际上也就是 LocalDate、LocalTime 相关类的顶级父接口,这个 queryFrom 方法的实现逻辑就是 传入一个日期/时间对象,通过自定义逻辑返回数据。如果要计划日期距离某一特定天数差多少天,可以自定义实现类 TemporalQuery 并作为参数传递到 query 方法中。

思考:计算当前时间距离下一个劳动节还有多少天?

public class TemporalQueryImpl implements TemporalQuery<Long> {
    
    
    @Override
    public Long queryFrom(TemporalAccessor temporal) {
    
    
        //TemporalAccessor 是 LocalDate、LocalTime 的父接口,
        //相当于 LocalDate就是这个接口的实现类,将 temporal 转换为 LocalDate 进行使用
        LocalDate now = LocalDate.from(temporal);
        //封装当年的劳动节时间
        LocalDate laborDay = LocalDate.of(now.getYear(), Month.MAY, 1);
        //判断当前时间是否已经超过当年的劳动年,如果超过,laborDay 加一年
        if (now.isAfter(laborDay)){
    
    
            laborDay = laborDay.plusYears(1);
        }
        //通过 ChronoUnit 类的 between 方法来计算两个时间点的差额
        long days = ChronoUnit.DAYS.between(now, laborDay);
        //返回的就是相隔的天数
        return days;
    }
}
Long days = now.query(new TemporalQueryImpl());
System.out.println("当前时间是:"+now+" 距离下个劳动节还有:"+days);

思考:计算当前时间距离下一个圣诞节/儿童节/劳动节还有多少天?

public class TemporalQueryImpl implements TemporalQuery<Long[]> {
    
    
    /**
     * @param temporal
     * @return 表示距离三个节日的差额,0索引表示圣诞节,1->儿童节,2->劳动节
     */
    @Override
    public Long[] queryFrom(TemporalAccessor temporal) {
    
    
        //TemporalAccessor 是 LocalDate、LocalTime 的父接口,
        //相当于 LocalDate就是这个接口的实现类,将 temporal 转换为 LocalDate 进行使用
        LocalDate now = LocalDate.from(temporal);
        //封装圣诞节
        LocalDate d1 = LocalDate.of(now.getYear(), Month.DECEMBER, 25);
        //封装儿童节
        LocalDate d2 = LocalDate.of(now.getYear(), Month.JUNE, 1);
        //封装当年的劳动节时间
        LocalDate d3 = LocalDate.of(now.getYear(), Month.MAY, 1);
        //判断当前时间是否已经超过当年的劳圣诞节/儿童节/劳动节,如果超过,加一年
        if (now.isAfter(d1)) d1 = d1.plusYears(1);
        if (now.isAfter(d2)) d2 = d2.plusYears(1);
        if (now.isAfter(d3)) d3 = d3.plusYears(1);

        //通过 ChronoUnit 类的 between 方法来计算两个时间点的差额
        Long[] days = {
    
    ChronoUnit.DAYS.between(now, d1),ChronoUnit.DAYS.between(now, d2),ChronoUnit.DAYS.between(now, d3)};
        //返回的就是相隔的天数
        return days;
    }
}
Long[] days = now.query(new TemporalQueryImpl());
System.out.println("当前时间是:"+now+" \n距离下个圣诞节还有:"+days[0]+" \n距离下个儿童节还有:"+days[1]+" \n距离下个劳动节还有:"+days[2]);
==============输出==============
当前时间是:2020-04-25 
距离下个圣诞节还有:244 
距离下个儿童节还有:37 
距离下个劳动节还有:6

java.util.Date 与 java.time.LocalDate 转换

对于老项目的改造,需要将 Date 或者 Calendar 转换为 java.time包中相应的类,Java8 中 java.time 包并没有提供太多的内置方式来转换 java.util 包中预处理标准日期和时间的类,我们可以使用 Instant 类作为中介,也可以使用 java.sql.Date 和 java.sql.Timestamp 类提供的方法进行转换

使用 Instant 类将 java.util.Date 转换为 java.time.LocalDate

java.time 包并没有提供很多的方式进行直接转换,但是之前的 Date类、Calendar类在 Java8 都提供了一个新的方法叫 toInstant,可以将当前对象转换为 Instant 对象,通过给 Instant 添加时区信息后就可以转换为 LocalDate 对象。

// 初始化 java.util.Date 对象
Date date = new Date();
//转换为 Instant
Instant instant = date.toInstant();
//添加时区
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
// zonedDateTime 通过 toLocalDate()方法转换
LocalDate localDate = zonedDateTime.toLocalDate();
System.out.println("原生 date:"+date);
System.out.println("转换后 localDate: "+localDate);

========sout==========
原生 date:Sat Apr 25 13:00:24 CST 2020
转换后 localDate: 2020-04-25

java.sql.Date 类中的转换方法使用

看清楚 这个包,java.sql.Date

//初始化 java.sql.Date 对象
Date date = new Date(System.currentTimeMillis());
// java.sql.Date 自带 toLocalDate() 方法进行转换
LocalDate localDate = date.toLocalDate();
System.out.println("java.sql.date:"+date);
System.out.println("java.time.localDate: "+localDate);
=========sout=========
java.sql.date:2020-04-25
java.time.localDate: 2020-04-25

java.util.Timestamp 类中的转换方法使用

Timestamp timestamp = new Timestamp(System.currentTimeMillis());
LocalDateTime localDateTime = timestamp.toLocalDateTime();

将 java.util.Date 转换为 java.time.LocalDate 方法二

这种方法就是使用 java.sql.Date 作为中间桥梁,因为 java.sql.Date 提供了 toLocalDate() 方法…

java.util.Date date = new Date();
java.sql.Date sqlDate = new java.sql.Date(date.getTime());
LocalDate localDate = sqlDate.toLocalDate();

将java.util.Calendar 转换为 ZonedDateTime

//初始化 Calendar 对象
Calendar calendar = Calendar.getInstance();
//Java1.1 可以通过 calendar 获取时区对象( ZonedDateTime 必须要有时区)
TimeZone timeZone = calendar.getTimeZone();
//Java1.8可以通过 timeZone 获取到 zoneId->有了 zoneId 就可以构建 ZonedDateTime 对象了
ZoneId zoneId = timeZone.toZoneId();
//通过 ZonedDateTime 的 ofInstant() 方法封装成 ZonedDateTime 对象
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), zoneId);
//有了 zonedDateTime 也就有了 localDate、localDateTime
zonedDateTime.toLocalDate();
zonedDateTime.toLocalDateTime();
zonedDateTime.toLocalTime();

将java.util.Calendar 转换为 LocalDateTime

当然我们可以先得到 ZonedDateTime 再通过 toLocalDateTime 获取,就像上面一样。
但是 Calendar 本身就可以获取到年月日时分秒信息,这些信息可以作为 LocalDateTime 参数进行构造。

Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR);
int minite = calendar.get(Calendar.MINUTE);
int seconds = calendar.get(Calendar.SECOND);
//注意因为 Calendar 中的月份是从 0 开始的,所以这里获取到的月份要加 1
LocalDateTime time = LocalDateTime.of(year, month + 1, day, hour, minite, seconds);
System.out.println(time);//2020-04-25T01:30:06

日期的解析与格式化 DateTimeFormatter

SimpleDateFormate 之前说过是线程不安全的,所以 Java8 提供了新的格式化类 DateTimeFormatter。DateTimeFormatter 提供了大量的预定义格式化器,包括常量如 ISO_LOCAL_DATE,模式字母(yyyy-MM-dd)及本地化样式

新日期类的 format 和 parse 方法

LocalDateTime localDateTime = LocalDateTime.now();
//通过 format 进行格式化
String s1 = localDateTime.format(DateTimeFormatter.ISO_DATE);
String s2 = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println(localDateTime);
System.out.println("ISO_DATE 格式:"+s1);
System.out.println("ISO_DATE_TIME 格式:"+s2);

//通过 parse 解析
LocalDateTime time = LocalDateTime.parse(s2);
LocalDate date = LocalDate.parse(s1);
System.out.println(time);
System.out.println(date);

========sout==========
2020-04-25T13:41:16.639
ISO_DATE 格式:2020-04-25
ISO_DATE_TIME 格式:2020-04-25T13:41:16.639
2020-04-25T13:41:16.639
2020-04-25

DateTimeFormatter.ofLocalizedDate 指定解析格式

LocalDateTime localDateTime = LocalDateTime.now();
// 通过 DateTimeFormatter.ofLocalizedDate 指定解析格式
String s1 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
String s2 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
String s3 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
String s4 = localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
System.out.println("FULL: "+s1);
System.out.println("LONG: "+s2);
System.out.println("MEDIUM: "+s3);
System.out.println("SHORT: "+s4);

============sout=============
FULL: 2020425日 星期六
LONG: 2020425日
MEDIUM: 2020-4-25
SHORT: 20-4-25

这种方式在不同地区显示方式会不一样,在其它地区不会显示中文,会根据当前默认时区来进行区别显示

自定义格式化格式

LocalDateTime localDateTime = LocalDateTime.now();
String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));

猜你喜欢

转载自blog.csdn.net/lhg_55/article/details/105745491