Java基础扩展提升总结:Java 8 新特性之(五)新日期时间API

新日期时间API

一、旧的日期时间API存在的问题

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:

  • 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。

示例:

package NewDataAPI;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Demo1 {

    public static void main(String[] args) throws Exception{
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        //DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-M-dd");
        Callable<Date> callable=new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                    return sdf.parse("2019-8-17");
            }
        };
        //使用线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Future<Date>> list=new ArrayList<>();
        //提交任务,提交十次
        for(int i=0;i<10;i++){
            Future<Date> future = executorService.submit(callable);
            //存储结果
            list.add(future);
        }
        //遍历
        for (Future<Date> dateFuture : list) {
            System.out.println(dateFuture.get());
        }
        //关闭线程池
        executorService.shutdown();
    }
}

 上述代码可能执行成功,也可能执行不成功。

成功的话会获得如下十个时间:

Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019
Sat Aug 17 00:00:00 CST 2019

但是很大可能会出现 java.util.concurrent.ExecutionException 异常。 

二、新日期时间API简介

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:

  • Local(本地) − 简化了日期时间的处理,没有时区的问题。
  • ZoneId (时区) − 通过定制的时区处理日期时间。

解决上述旧日期时间API的并发问题:

package NewDataAPI;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Demo1 {

    public static void main(String[] args) throws Exception{
//        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-M-dd");
        Callable<LocalDate> callable=new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
                    return LocalDate.parse("2019-8-17", dtf);
            }
        };
        //使用线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Future<LocalDate>> list=new ArrayList<>();
        //提交任务
        for(int i=0;i<10;i++){
            Future<LocalDate> future = executorService.submit(callable);
            list.add(future);
        }
        //获取时间
        for (Future<LocalDate> dateFuture : list) {
            System.out.println(dateFuture.get());
        }
        executorService.shutdown();
    }
}

我们使用LocalDate来代替旧的Date类,使用DateTimeFormatter 来代替SimpleDateFormate类,这就解决的日期时间的并发问题。

DateTimeFormatter 和 LocalDate 都是Java 8 中新日期时间 API 中的两个类,都是支持多线程的。

三、本地化日期时间 API

LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日 历系统的日期、时间 、日期和时间。它们提供了简单的日期或时间,不包含与时区相关的信息。

(1)LocalDate

LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日。 也可以访问其他日期字段,例如日期,星期几和星期。该类不存储或表示时间或时区。

继承关系和类声明:

java.lang.Object 
|____java.time.LocalDate

package java.time;

/**
 * @since 1.8
 */
public final class LocalDate
        implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {

    public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1);

    public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);
}

(2)LocalTime

LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时 - 秒。 时间表示为纳秒精度。 它不存储或表示日期或时区。

继承关系和类声明:

java.lang.Object 
|____java.time.LocalTime 

package java.time;
/**
 * @since 1.8
 */
public final class LocalTime
        implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {

    public static final LocalTime MIN;

    public static final LocalTime MAX;

    public static final LocalTime MIDNIGHT;//午夜

    public static final LocalTime NOON;//正午
}

(3)LocalDateTime

LocalDateTime 是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒。 也可以访问其他日期和时间字段,例如日期,星期几和星期。 时间表示为纳秒精度。 该类不存储或表示时区。

LocalDateTime继承关系和类声明:

java.lang.Object 
|____java.time.LocalDateTime 

package java.time;

/**
 * @since 1.8
 */
public final class LocalDateTime
        implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable{
    public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);

    public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
}

LocalDateTime的简单使用:

package NewDataAPI;

import java.time.LocalDateTime;

public class StuLocalDateTime {
    public static void main(String[] args) throws Exception{
        //获取当前时间的LocalDateTime对象
        LocalDateTime localDateTime =LocalDateTime.now();
        System.out.println(localDateTime);
        //获取其他时间,输入不存在的时间时,会报DateTimeException异常
        LocalDateTime localDateTime1 = LocalDateTime.of(2015,7,23,12,12,12);
        System.out.println(localDateTime1);

        //加时间,很多plus开头的方法,用于增加不同的时间单位的时间。
        LocalDateTime localDateTime2 = localDateTime1.plusMonths(3);
        System.out.println(localDateTime2);

        //减时间,很多minus开头的方法,用于减少不同的时间单位的时间
        LocalDateTime localDateTime3 = localDateTime2.minusDays(10);
        System.out.println(localDateTime3);

        //获取部分时间,很多get()开头的方法,用于获取不同部分的时间
        System.out.println(localDateTime3.getYear());
        System.out.println(localDateTime3.getMonth());
        System.out.println(localDateTime3.getDayOfMonth());
    }
}

四、时间戳(Instant)和时区(ZoneId)

 1、Instant 时间戳

Instant表示在时间线上的瞬间点。它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始 所经历的描述进行运算。

Instant instant = Instant.now();//获取当前时间:2019-08-19T12:47:27.296Z
System.out.println(System.currentTimeMillis());
//转换为毫秒值,与System.currentTimeMillis()等价
System.out.println(instant.toEpochMilli());

Duration:基于时间的时间量,如'34.5秒'。该类以秒和纳秒为单位建立数量或时间量。

Period :日历系统中的日期时间,例如“2年3个月4天”。这个课程以年,月和日为单位建立数量或时间量。

//获取两个时间差
long l = Duration.between(instant2, instant).toHours();
System.out.println(l);

2、ZoneID

一个时区ID,如 Asia/Shanghai。用于识别用于在Instant和LocalDateTime之间转换的规则。 有两种不同类型的ID:

  • 固定偏移量 - 从UTC /格林威治完全解析的偏移量,对所有本地日期时间使用相同的偏移量
  • 地理区域 - 适用于查找UTC /格林威治的偏移量的特定规则集的区域

大多数固定偏移量由ZoneOffset表示

//获取所有时区,很多
System.out.println("-------所有时区-------");
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String availableZoneId : availableZoneIds) {
    System.out.println(availableZoneId);
}
//获取默认时区
System.out.println("-------默认时区-------");
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);

3、时间转换

Date转换成LocalDateTlme:

需要将Date先转成Instant,然后Instant再转成LocalDateTime。

Date date=new Date();
//把date转成instant
Instant instant1 = date.toInstant();
//intant转成LocalDateTime
LocalDateTime localDateTime = instant1
    .atZone(ZoneId.systemDefault())
    .toLocalDateTime();

LocalDateTime转Date

Instant instant3 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date2 = Date.from(instant3);

五、时间调整器

TemporalAdjusters :

时间调整器,调整时间对象的策略。

有时我们可能需要获 取例如:将日期调整到“下个周日”等操作。 TemporalAdjusters类通过静态方法提供了大量的常用 TemporalAdjusters 的实现。

调整器是修改时间物体的关键工具。 它们存在于外部化调整过程中,根据策略设计模式允许不同的方法。 示例可以是设置日期避免周末的调整器,或者将日期设置为月份的最后一天。

示例:

获取下一个周一

LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
//获取下个周一
LocalDateTime localDateTime1 =localDateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println(localDateTime1);

结果:

2019-08-19T21:33:09.358
2019-08-26T21:33:09.358

DateTimeFormatter:

格式化器用于打印和解析日期时间对象。

该类提供打印和解析的主要应用程序入口点,并提供DateTimeFormatter的常见DateTimeFormatter:

  • 使用预定义的常量,如ISO_LOCAL_DATE
  • 使用模式字母,如uuuu-MMM-dd
  • 使用本地化样式,如long或medium

更复杂的格式化程序由DataTimeFoematterBuilder提供。

  • formate():格式化日期
  • parse():解析日期

示例:

字符串转LocalDate(或LocalTime或LocalDateTime)

LocalDate(或LocalTime或LocalDateTime)转字符串

package NewDataAPI;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class StuDateTimeFormatter {
    public static void main(String[] args) {
        //1、创建并设置模式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

        //把字符串转成日期
        LocalDate localDate = LocalDate.parse("2019/08/19",dateTimeFormatter);
        System.out.println(localDate);

        //日期转成字符串
        String date = dateTimeFormatter.format(LocalDate.now());
        System.out.println(date);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值