【Java8新特性】2.日期时间API

目录

一、前言

二、本地日期时间

1、LocalDate

2、LocalTime

3、LocalDateTime

4、格式化日期时间DateTimeFormatter

二、时间戳、日期段、时间段

三、时区日期时间

1、ZonedDateTime

2、ZoneId

四、小结


一、前言

Java8之前,Java日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理,看上去有点混乱。而日期类并不提供国际化,没有时区支持,因此还需要引入java.util.Caleandar类和java.util.TimeZone类,导致时区处理比较繁琐。另外,java.util.Date是非线程安全的,所有的日期类都是可变的,这也是一个痛点。

针对上述种种,Java8重写了一套关于所有处理日期、时间、日期/时间、时区、时刻(instants)、时间段(Duration)、日期段(Period)、时钟(clock)等操作的API,统一放在了java.time包下,结束了以前存在的混乱,繁琐和安全等问题。其中的Local(本地)简化了日期时间的处理,没有时区的问题;Zoned(时区)通过制定的时区处理日期时间。

二、本地日期时间

1、LocalDate

  • 它是一个不可变的日期时间对象(线程安全的),表示日期,通常被视为年月日,默认日期格式为:yyyy-MM-dd,(注意:YYYY代表的是week year —— 即当天所在的周属于的年份,存在跨年问题谨慎使用!yyyy代表标准的年份);
  • 也可以访问其他日期字段,例如日期,星期几和星期等;
  • 该类是对日期的描述,不能存储或表示时间或时区,也不能代表时间线上的即时信息,没有附加信息,如偏移或时区;
  • 日期相关API的demo演示如下:
 /**
 * Java8日期时间类API Demo
 *  
 * @createTime 2020/10/20 21:41
 * @author weixiangxiang
 */
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) {

        // 创建LocalDate对象的四种方式,默认日期格式为:yyyy-MM-dd 
        LocalDate currDate = LocalDate.now();// 当前日期
        LocalDate cDate1 = LocalDate.of(2020, 10, 12);//指定日期1
        LocalDate cDate2 = LocalDate.of(2020, Month.OCTOBER, 9);//指定日期2
        LocalDate pDate = LocalDate.parse("2020-10-09");
        logger.info("当前日期为:" + currDate + "/" + cDate1 + "/" + pDate);

        // 获取日期的年月日周  
        int year = currDate.getYear();  // 年
        int month = currDate.getMonth().getValue();  // 月
        int monthValue = currDate.getMonthValue();  // 月
        int dayOfWeek = currDate.getDayOfWeek().getValue(); // 周的第几天
        int day = currDate.getDayOfMonth();  // 月的第几天
        int dayOfYear = currDate.getDayOfYear();  // 年的第几天
        logger.info("测试今天的日期:" + year + "/" + month + "/" + day);
        
        // 日期有关的判断比较、加减运算、日期推算 :中plus或plusXXX表示往后推,minus或minusXXX表示往前推,with或withXXX表示更改成指定日期
        logger.info("今年是否为闰年:"+currDate.isLeapYear());

        logger.info("比较两个日期是否相同-1:"+cDate1.equals(cDate2));
        logger.info("比较两个日期是否相同-2:"+cDate1.isEqual(cDate2));
        logger.info("cDate1是否在比较的日期之前:"+cDate1.isBefore(cDate2));
        logger.info("cDate1是否在比较的日期之后:"+cDate1.isAfter(cDate2));

        logger.info("计算相差日期为:" + cDate1.compareTo(cDate2));   

        logger.info("当前日期加一年:" + currDate.plusYears(1));   
        logger.info("当前日期加一年:" + currDate.plus(1, ChronoUnit.YEARS));
        logger.info("当前日期减一年:" + currDate.minusYears(1));   
        logger.info("当前日期减一年:" + currDate.minus(1, ChronoUnit.YEARS)); 

        logger.info("当前日期加一个月:" + currDate.plusMonths(1)); 
        logger.info("当前日期加一周:" + currDate.plusWeeks(1));   
        logger.info("当前日期加一天:" + currDate.plusDays(1));   

        logger.info("更改当前日期的年:"+currDate.withYear(2016));   
        logger.info("更改当前日期的月:"+currDate.withMonth(8));    
        logger.info("更改当前日期的日:"+currDate.withDayOfMonth(7));   
        logger.info("更改到当前日期的第几天:"+currDate.withDayOfYear(47));   

        logger.info("取本年的第一天日期:"+currDate.with(TemporalAdjusters.firstDayOfYear())); 
        logger.info("取本年的最后一天日期:"+currDate.with(TemporalAdjusters.lastDayOfYear())); 
        logger.info("取明年的第一天日期:"+currDate.with(TemporalAdjusters.firstDayOfNextYear()));
        logger.info("取明年的最后一天日期:"+currDate.plusYears(1).with(TemporalAdjusters.lastDayOfYear()));

        logger.info("取本月的第一天日期:"+currDate.with(TemporalAdjusters.firstDayOfMonth())); 
        logger.info("取本月的第n天日期(如n=18):"+currDate.withDayOfMonth(18)); 
        logger.info("取下个月的第一天日期:"+currDate.with(TemporalAdjusters.firstDayOfNextMonth()));	
        logger.info("取下个月的最后一天日期:"+currDate.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth())); 
        logger.info("取上个月的第一天日期:"+currDate.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth())); 
        logger.info("取上个月的第一天日期:"+currDate.minus(1, ChronoUnit.MONTHS).with(TemporalAdjusters.firstDayOfMonth()));
        logger.info("取上个月的最后一天日期:"+currDate.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth())); 
    }
}

2、LocalTime

  • 它是一个不可变的时间对象(线程安全的),代表一个时间,通常被看作是时分秒,精度为纳秒,默认时间格式为:HH:mm:ss.nnn,(注意:H代表使用24小时制,h代表使用12小时制);
  • 它不能存储或表示日期或时区。 相反,它是在挂钟上看到的当地时间的描述, 它不能代表时间线上的即时信息,而没有附加信息,如偏移或时区;
  • 时间相关API的demo演示如下:
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) {
        // 创建LocalTime对象的三种方式 ,默认时间格式为:HH:mm:ss.nnn 
        LocalTime currTime = LocalTime.now();
        LocalTime cTime = LocalTime.of(20, 10, 10);
        LocalTime pTime = LocalTime.parse("20:19:18");
        logger.info("当前时间为(默认精确到毫秒ms):" + currTime);   //20:19:18.684
        logger.info("指定时间为:" + cTime + "   " + pTime);   //20:10:10   20:19:18
        
        // 获取小时、分钟、秒、纳秒 
        logger.info("当前时间报时:" + currTime.getHour() + currTime.getMinute() + 
                        currTime.getSecond() + currTime.getNano()); 
        // 时间常量
        logger.info("最大时间:" + LocalTime.MAX); //23:59:59.999999999
        logger.info("最小时间:" + LocalTime.MIN); //00:00
        logger.info("凌晨零时时间:" + LocalTime.MIDNIGHT); //00:00
        logger.info("中午时间:" + LocalTime.NOON);  //12:00

        // 日期推算:plus或plusXXX表示往后推,minus或minusXXX表示往前推,with或withXXX表示更改成指定日期 
        logger.info("当前时间往后推1个小时:" + currTime.plus(1,ChronoUnit.HOURS));  
        logger.info("当前时间往后推5分钟:" + currTime.plusMinutes(5)); 
        logger.info("当前时间往前推10秒:" + currTime.minusSeconds(10));  
        logger.info("当前时间往前推5纳秒:" + currTime.minus(5,ChronoUnit.NANOS));  
    }
}

3、LocalDateTime

  • 它是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒,默认日期时间格式为:yyyy-MM-ddTHH:mm:ss.nnn;
  • 该类不存储或表示时区,它不能代表时间线上的即时信息,而没有附加信息,如偏移或时区;

  • 日期时间相关API的demo演示如下:

public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) {
        // 创建LocalDateTime对象的三种方式 ,默认日期时间格式为:yyyy-MM-ddTHH:mm:ss.nnn 
        LocalDateTime currDateTime = LocalDateTime.now();
        LocalDateTime cDateTime =LocalDateTime.of(2020,10,9,23,50,0,0);
        LocalDateTime pDateTime = LocalDateTime.parse("2020-10-09T23:57:43.280");
        logger.info("当前日期时间为:" + currDateTime); 	// 如2020-10-09T23:57:43.280
        logger.info("当前日期时间为:" + cDateTime);	// 如2020-10-09T23:50
        logger.info("当前日期时间为:" + pDateTime);	// 如2020-10-09T23:57:43.280
        
        // LocalDate、LocalTime与LocalDateTime转换  
        LocalDateTime ld1 = currDate.atTime(currTime);
        LocalDateTime ld2 = currTime.atDate(currDate);
        logger.info("当前日期时间为:" + ld1);   // 如2020-10-09T23:19:18.684
        logger.info("当前日期时间为:" + ld2);  // 如2020-10-09T23:19:18.684
    }
}

4、格式化日期时间DateTimeFormatter

  • 该类位于java.time.format包下,用于打印和解析日期时间对象;
  • 有三种格式化类型:(使用模版预定义常量 —— 如BASIC_ISO_DATE、使用模式字母 —— 如yyyy-MM-dd HH:mm:s、使用本地化样式 —— 如long或medium);
  • 格式化方法 —— format(),解析方法 —— parse() 。格式化可以使用DateTimeFormatter预置的格式,也可以通过DateTimeFormatter.ofPattern方法来指定格式。
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) {
        // 从对应模版的常量指定需要的输出格式  
        logger.info("指定格式为yyyyMMdd:" + LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE));
        logger.info("指定格式为yyyy-MM-ddTHH:mm:ss.nnn:" + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));
        logger.info("指定格式为yyyy-MM-ddTHH:mm:ss.nnn:" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
		
        // 自定义输出格式,常见的有以下三种  
        logger.info("指定格式为yyyyMMddHHmmss:" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); // 如20201010011859
        logger.info("指定格式为yyyy-MM-dd HH:mm:ss:" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now())); // 如2020-10-10 01:18:59
        logger.info("指定格式为yyyy/MM/dd HH:mm:ss:" + DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now())); // 如2020/10/10 01:18:59

        logger.info("解析:" + LocalDateTime.parse("20201010011830", DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); // 如2020-10-10T01:18:30
    }
}

二、时间戳、日期段、时间段

  • 时间戳Instant:它是以Unix元年(默认传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算;
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) {
        // 可以通过now()/ofEpochMilli()/ofEpochSecond()/parse()等方式创建时间戳对象
        Instant instant = Instant.now();
        logger.info("当前时间(UTC时区)为:" + instant);  // 如2020-10-09T16:24:26.195Z
        logger.info("获取时间戳为:" + instant.toEpochMilli());  // 如1602260666195
        logger.info("当前时间偏移量6h运算:" + instant.atOffset(ZoneOffset.ofHours(6)));  // 如2020-10-09T22:24:26.195+06:00
        logger.info("以Unix元年为起点,进行偏移量120s运算:" + Instant.ofEpochSecond(120)); // 如1970-01-01T00:02:00Z
    }
}
  • 日期段Period:以年,月和日为单位建立数量或时间量,这个类是不可变的和线程安全的。
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) { 
        // 均可通过通过of方法、ofXXX方法和between方法创建Period 
        Period period = Period.of(2020, 10, 10);
        logger.info("当前日期:" + period); //P2020Y10M10D
        logger.info("当前日期年份:" + period.getYears());
        logger.info("当前日期月份:" + period.getMonths());
        logger.info("当前日期几号:" + period.getDays());

        Period bPeriod = Period.between(cDate1,cDate2);
        logger.info("当前日期:" + bPeriod); //P7D
        logger.info("间隔年数:" + bPeriod.getYears()); //0
        logger.info("间隔月数:" + bPeriod.getMonths()); //0
        logger.info("间隔天数:" + bPeriod.getDays()); //7
    }
}
  • 时间段Duration:该类以秒和纳秒为单位建立数量或时间量,它可以使用其他基于持续时间的单位进行访问,例如分钟和小时。这个类是不可变的和线程安全的。
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) { 
        LocalDateTime cDateTime =LocalDateTime.of(2020,10,9,23,50,0,0);
        LocalDateTime pDateTime = LocalDateTime.parse("2020-10-09T23:57:43.280");

        // 均可通过通过of方法、ofXXX方法和between方法创建Duration 
        Duration duration = Duration.between(cDateTime,pDateTime); //from - to
        logger.info("间隔天数:" + duration.toDays());   //7
        logger.info("间隔小时数:" + duration.toHours()); //168
        logger.info("间隔毫秒数:" + duration.toMillis()); //605263280

        Duration durationDay = Duration.of(7, ChronoUnit.DAYS);
        Duration durationHours = Duration.ofHours(2);
        Duration durationMin = Duration.ofMinutes(60);
        Duration durationMill = Duration.of(10000,ChronoUnit.MILLIS);
        // 距当前时间比较产生的间隔
        logger.info("间隔小时数:" + durationDay);   //PT168H
        logger.info("间隔分钟数:" + durationHours.toMinutes());   //120
        logger.info("间隔分钟数:" + durationMin.toMinutes());   //60
        logger.info("间隔分钟数:" +durationMill);   //PT10S
    }
}

三、时区日期时间

1、ZonedDateTime

  • 表示不可变的具有时区的日期时间,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。例如,值“2020-10-03T10:15:30+01:00 Europe/Paris”可以存储在ZonedDateTime;
  • ZonedDateTime拥有相当于三个独立对象的状态,一个LocalDateTime ,一个ZoneIdZoneOffset 。偏移量ZoneOffset和本地日期时间LocalDateTime用于在必要时定义一个时间戳。 区域ID用于获取偏移量如何以及何时更改的规则。偏移不能自由设置,因为区域控制哪些偏移是有效的。
public class XxxTest{
    /** 日志记录器 */
    private static Logger logger = LoggerFactory.getLogger(XxxTest.class);

    public static void main(String[] args) { 
        // ZoneId表示不同的时区,大约有40不同的时区。
        Set<String> allZoneIds = ZoneId.getAvailableZoneIds();

        logger.info("获取当前时区:" + ZoneId.systemDefault()); // 如Asia/Shanghai

        // 创建时区日期时间对象
        logger.info("创建当前时区的日期时间:" + ZonedDateTime.now());
        logger.info("创建当前时区的日期时间:" + ZonedDateTime.parse("2020-10-10T01:26:23.765+08:00[Asia/Shanghai]"));

        // LocalDateTime转换成特定的时区
        ZonedDateTime zonedDateTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Asia/Shanghai"));
        logger.info("获取特定时区:" + zonedDateTime); // 如2020-10-10T01:26:23.765+08:00[Asia/Shanghai]
    }
}

2、ZoneId

  • 用于识别用于在Instant和LocalDateTime之间转换的规则,有两种不同类型的ID:固定偏移量 —— 从UTC /格林威治完全解析的偏移量,对所有本地日期时间使用相同的偏移量;地理区域 —— 适用于查找UTC /格林威治的偏移量的特定规则集的区域。大多数固定偏移量由ZoneOffset表示。
  • 更详细的解释可以去查看ZoneId的API说明。

四、小结

至此,Java8新增的日期时间API已分析完毕,需要更详细的方法说明或解释,可以去查找API文档了解,日期时间API的核心就是LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration了,掌握并熟练的使用它们是后端必备的,也可以通过这些类提供的API封装成自己的日期时间工具类,满足项目中对各种日期时间的需求。不积硅步无以至千里,点滴付出终将有所收获,共同进步 ~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值