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();
        }
    }

}
发布了159 篇原创文章 · 获赞 186 · 访问量 67万+

猜你喜欢

转载自blog.csdn.net/KingBoyWorld/article/details/84882048