Java8新特性-LocalDateTime

当我们开始使⽤Java操作⽇期和时间的时候,会有⼀些棘⼿。你也许会通过 System.currentTimeMillis() 来返回1970年1⽉1⽇到今天的毫秒数。或者使⽤ Date类来操作⽇期;当遇到加减⽉份、天数的时候 你⼜需要⽤到Calendar类; 当需要格式化⽇期的时候需要使⽤java.text.DateFormat类。 总⽽⾔之在Java中 操作⽇期不是很⽅便,以⾄于很多开发者不得不使⽤第三⽅库,⽐如: jodatime。

一、Date存在的问题

  • 结构定义混乱
    • java.util Date包含日期时间
    • java.sql Date包含日期
    • java.text 时间格式化
  • API不易用
  • 非线程安全
    • 可变,SimpleDateFormate
  • 国际化
    • Calendar TimeZone

二、Java8新的日期时间类

  • 结构清晰
    • java.time LocalDate/LocalTime/LocalDateTime 自带格式化
  • 不可变,线程安全
  • 提供常用的方法,方法名通俗易懂并按照一定规则进行命名,如加、减、格式化、解析、提取某个时间单位
  • 扩展性,支持不同的日历系统,ISO-8601和非ISO的日历
  • 兼容性,目前hibernate,mybatis,jackson都有很好的支持

三、包结构

  • java.time包

这是新的Java⽇期/时间API的基础包,所有的主要基础类都 是这个包的⼀部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在绝⼤多数 情况下,这些类能够有效地处理⼀些公共的需求。

  • java.time.chrono包

这个包为⾮ISO的⽇历系统定义了⼀些泛化的API, 我们可以扩展AbstractChronology类来创建⾃⼰的⽇历系统。

  • java.time.format包

这个包包含能够格式化和解析⽇期时间对象的类,在绝⼤多数情况下,我们不应该直接使⽤它们,因为java.time包中相应的类已 经提供了格式化和解析的⽅法。 java.time.temporal包:这个包包含⼀些时态对象,我们可以⽤其找出关于 ⽇期/时间对象的某个特定⽇期或时间,⽐如说,可以找到某⽉的第⼀天或最后⼀天。你可以⾮常容易地认出这些⽅法,因为它们都具有“withXXX”的格 式。

  • java.time.zone包

这个包包含⽀持不同时区以及相关规则的类。

四、常用类

  • ZoneId: 时区ID,⽤来确定Instant和LocalDateTime互相转换的规则
  • Instant: ⽤来表示时间线上的⼀个点
  • LocalDate: 表示没有时区的⽇期, LocalDate是不可变并且线程安全的
  • LocalTime: 表示没有时区的时间, LocalTime是不可变并且线程安全的
  • LocalDateTime: 表示没有时区的⽇期时间, LocalDateTime是不可变并且 线程安全的
  • Clock: ⽤于访问当前时刻、⽇期、时间,⽤到时区
  • Duration: ⽤秒和纳秒表示时间的数量

五、API示例

最常用的就是LocalDate,LocalTime,LocalDateTime三个类,API很类似,所以接下来以LocalDateTime进行演示

5.1 创建

//获取当前时间
LocalDateTime today = LocalDateTime.now();

//使用LocalDate and LocalTime 创建LocalDateTime
today = LocalDateTime.of(LocalDate.now(), LocalTime.now());

//通过of方法参数创建
LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);

//不正确的参数会抛出异常
//Exception in thread "main" java.time.DateTimeException: Invalid value for HourOfDay (valid values 0 - 23): 25
LocalDateTime illegalDate = LocalDateTime.of(2014, Month.FEBRUARY, 28, 25,1,1); 

//获取"Asia/Kolkata",加尔哥达
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));

//通过时间戳获取时间
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);

5.2 日期运算

LocalDateTime today = LocalDateTime.now();

    //获取当前年,并判断是否是闰年
    System.out.println("Year " + today.getYear() + " is Leap Year? " + today.toLocalDate().isLeapYear());

    //比较两个日期的先后
    System.out.println("Today is before 01/01/2015? " + today.isBefore(LocalDateTime.of(2015,1, 1, 11, 30)));

    //时间加减
    System.out.println("10 days after today will be " + today.plusDays(10));
    System.out.println("3 weeks after today will be " + today.plusWeeks(3));
    System.out.println("20 months after today will be " + today.plusMonths(20));
    System.out.println("10 days before today will be " + today.minusDays(10));
    System.out.println("3 weeks before today will be " + today.minusWeeks(3));
    System.out.println("20 months before today will be " + today.minusMonths(20));

    //查询日期的特定点
    System.out.println("First date of this month= " + today.with(TemporalAdjusters.firstDayOfMonth()));
    LocalDate lastDayOfYear = today.toLocalDate().with(TemporalAdjusters.lastDayOfYear());
    System.out.println("Last date of this year= " + lastDayOfYear);

    //两个日期间的间隔
    Period period = today.toLocalDate().until(lastDayOfYear);
    System.out.println("Period Format= " + period);

5.3 日期格式化

    LocalDateTime now = LocalDateTime.now();
    String formatTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd mm:ss"));
    System.out.println(formatTime);

5.4 日期转换

    //Date转换为新的API
    Date date = new Date();
    LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.of(ZoneId.SHORT_IDS.get("PST")));

    //LocalDateTime转换为Date
    Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());

    //Calendar转换为Instant
    Instant time = Calendar.getInstance().toInstant();
    
    //TimeZone 转换为 ZoneId
    ZoneId defaultZone = TimeZone.getDefault().toZoneId();
    System.out.println(defaultZone);

5.5 工具类

工具类地址

5.6 补充

不安全的SimpleDateFormat

public class UnSafeDateFormatExample0 {

    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final CountDownLatch countDownLatch = new CountDownLatch(5000);
        final Semaphore semaphore = new Semaphore(50);

        for (int i = 0; i < 5000; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    format();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

    private static void format() {
        try {
            format.parse("1999-12-01 12:12");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

}
package com.aapoint.util; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; public class LocalDateTimeUtil { /** * 比较 localDateTime2 是否在localDateTime1之前(比较大小) * @param localDateTime1 * @param localDateTime2 * @return */ public static Boolean compare(LocalDateTime localDateTime1,LocalDateTime localDateTime2){ return localDateTime1.isBefore(localDateTime2); } /** * 获取当前月份前/后的月份的第一天 * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String firstDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,0,i); //获取该月份的第一天 String firstDay = date.with(TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("第一天为:"+firstDay); return firstDay; } /** * 获取当前月份前/后的月份的最后一天 * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String lastDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,0,i); //获取该月份的最后一天 String lastDay = date.with(TemporalAdjusters.lastDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("最后一天为:"+lastDay); return lastDay; } /** * 获取当时间前/后的时间(天) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainDay(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,1,i); //获取天 String day = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // System.out.println("获取的时间为(天):"+day); return day; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainHours(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,2,i); //获取该月份的最后一天 String hours = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(小时):"+hours); return hours; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainMinutes(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,3,i); //获取该月份的最后一天 String minutes = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(分钟):"+minutes); return minutes; } /** * 获取当时间前/后的时间(小时) * @param i 指定距离当前月份的时间 * @param state 状态 0.当月 1.前 2.后 * @return */ public static String obtainSeconds(Integer state,Integer i){ LocalDateTime date = null; //type 类型 0.月 1.天 2.小时 3.分钟 4.秒 date = getLocalDateTime(state,4,i); //获取该月份的最后一天 String seconds = date.format(DateTimeFormatter.ofPattern("HH:mm:ss")); // System.out.println("获取的时间为(秒):"+seconds); return seconds; } public static void main(String[] args) { System.out.println("当前时间为:"+LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); System.out.println("前一个月份的第一天为:"+LocalDateTimeUtil.firstDay(1,1)); System.out.println("前一个月份的最后一天为:"+LocalDateTimeUtil.lastDay(1,1)); System.out.println("当前时间的前一天为:"+LocalDateTimeUtil.obtainDay(1,1)); System.out.println("当前时间的后一天为:"+LocalDateTimeUtil.obtainDay(2,1)); System.out.println("当前时间的前一小时为:"+LocalDateTimeUtil.obtainHours(1,1)); System.out.println("当前时间的后一小时为:"+LocalDateTimeUtil.obtainHours(2,1)); System.out.println("当前时间的前一分钟为:"+LocalDateTimeUtil.obtainMinutes(1,1)); System.out.println("当前时间的后一分钟为:"+LocalDateTimeUtil.obtainMinutes(2,1)); System.out.println("当前时间的前一秒为:"+LocalDateTimeUtil.obtainSeconds(1,1)); System.out.println("当前时间的后一秒为:"+LocalDateTimeUtil.obtainSeconds(2,1)); } private static LocalDateTime getLocalDateTime(Integer state,Integer type,Integer i) { LocalDateTime date; if(state == 0){ date = LocalDateTime.now(); }else if(state == 1){ if(type == 0) { //获取月 date = LocalDateTime.now().minusMonths(i); }else if(type == 1){ //获取天 date = LocalDateTime.now().minusDays(i); }else if(type == 2){ //获取小时 date = LocalDateTime.now().minusHours(i); }else if(type == 3){ //获取分钟 date = LocalDateTime.now().minusMinutes(i);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值