一、什么是Java8日期和时间API
Java 8 Date Time API是JSR-310实现。它旨在克服传统日期时间实现中的所有缺陷。新Date Time API的设计原则是:1、不可变性
新Date Time API中的所有类都是不可变的,适用于多执行绪环境。
2、关注点分离
新API明确区分人类可读日期时间和机器时间(unix时间戳)。它为Date、Time、DateTime、Timestamp、Timezone等定义了单独的类。
3、清晰度
方法明确定义并在所有类中执行相同的操作。例如,要获取当前例项,我们有now方法。在所有这些类中定义了format和parse方法,而不是为它们设定单独的类。
所有类都使用工厂模式和策略模式来更好地处理。一旦你在其中一个类中使用了这些方法,使用其他类并不难。
4、容易使用
所有新的Date Time API类都带有执行常见任务的方法,例如加号、减号、格式、解析,在日期/时间中获取单独的部分等。
5、可扩充套件
新的Date Time API适用于ISO-8601日历系统,但我们也可以将其与其他非ISO日历一起使用。
二、为什么需要新的日期和时间API
Java8之前的日期和时间相关类存在一些问题:1、没有统一定义
在java.util和java.sql包中都有Date类,格式化和解析类又再次定义在java.text包中。
2、java.sql.Date设计糟糕
java.util.Date包含日期和时间,而java.sql.Date仅包含日期,在java.sql包中有Date没有意义。 这两个类都有相同的名称,这本身就是一个非常糟糕的设计。
3、定义不完整
时间,时间戳,格式和解析没有明确定义的类。通常用SimpleDateFormat类用于解析和格式化。
4、非执行绪安全
所有Date类都是可变的,因此它们不是执行绪安全的。 这是Java Date和Calendar类最大的问题之一。
5、没有合理的国际化和时区支援
日期类不提供国际化,没有时区支援。 因此引入了java.util.Calendar和java.util.TimeZone类,但它们也具有上面列出的所有问题。
三、如何使用新的日期时间API
1、LocalDateLocalDate是一个不可变类,它表示预设格式为yyyy-MM-dd的Date。
我们可以使用now方法获取当前日期。
我们还可以提供年,月和日的输入引数来建立LocalDate例项。
此类为now提供过载方法,我们可以通过ZoneId获取特定时区的日期。
该类提供与java.sql.Date相同的功能。
示例程式码如下:
//当前日期
LocalDate today = LocalDate.now();
System.out.println("Current Date=" + today);
//通过输入引数建立日期
LocalDate firstDay_2019 = LocalDate.of(2019, Month.JANUARY, 1);
System.out.println("Specific Date=" + firstDay_2019);
//通过ZoneId建立日期
LocalDate todayShanghai = LocalDate.now(ZoneId.of("Asia/Shanghai"));
System.out.println("Current Date in IST=" + todayShanghai);
//从基准日期开始建立日期
LocalDate dateFromBase = LocalDate.ofEpochDay(365);
System.out.println("365th day from base date= " + dateFromBase);
LocalDate hundredDay2019 = LocalDate.ofYearDay(2019, 100);
System.out.println("100th day of 2014=" + hundredDay2019);
2、LocalTime
LocalTime是一个不可变类,其例项表示人类可读格式的时间。 它的预设格式是hh:mm:ss.zzz。 就像LocalDate一样,这个类通过传递小时,分钟和秒作为输入引数来提供时区支援和建立例项。
示例程式码如下:
//当前时间
LocalTime time = LocalTime.now();
System.out.println("Current Time=" + time);
//通过输入引数建立时间
LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
System.out.println("Specific Time of Day=" + specificTime);
//通过ZoneId建立时间
LocalTime timeShanghai = LocalTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("Current Time in IST=" + timeShanghai);
//通过基准日期建立时间
LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);
System.out.println("10000th second time= " + specificSecondTime);
3、LocalDateTime
LocalDateTime是一个不可变的日期时间物件,表示日期时间,预设格式为yyyy-MM-dd-HH-mm-ss.zzz。 它提供了一个工厂方法,该方法使用LocalDate和LocalTime输入引数来建立LocalDateTime例项。
示例程式码如下:
//当前日期
LocalDateTime today = LocalDateTime.now();
System.out.println("Current DateTime=" + today);
//通过LocalDate和LocalTime建立日期
today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("Current DateTime=" + today);
//通过输入引数建立日期
LocalDateTime specificDate = LocalDateTime.of(2019, Month.JANUARY, 1, 10, 10, 30);
System.out.println("Specific Date=" + specificDate);
//通过ZoneId建立日期
LocalDateTime todayShanghai = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("Current Date in IST=" + todayShanghai);
//通过基准日期建立日期
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);
System.out.println("10000th second time from 01/01/1970= " + dateFromBase);
4、Instant
Instant类用于处理机器可读的时间格式,它将日期时间储存在unix时间戳中。
示例程式码如下:
//当前时间戳
Instant timestamp = Instant.now();
System.out.println("Current Timestamp = " + timestamp);
//通过timestamp建立
Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
System.out.println("Specific Time = " + specificTime);
//建立Duration
Duration thirtyDay = Duration.ofDays(30);
System.out.println(thirtyDay);
5、日期工具类
大多数日期时间类提供各种实用方法,例如加/减天,周,月等。
示例程式码如下:
LocalDate today = LocalDate.now();
//判断是否是闰年
System.out.println("Year " + today.getYear() + " is Leap Year? " + today.isLeapYear());
//比较日期
System.out.println("Today is before 01/01/2015? " + today.isBefore(LocalDate.of(2015, 1, 1)));
//通过LocalTime建立LocalDateTime
System.out.println("Current Time=" + today.atTime(LocalTime.now()));
//加减操作
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.with(TemporalAdjusters.lastDayOfYear());
System.out.println("Last date of this year= " + lastDayOfYear);
//建立期间
Period period = today.until(lastDayOfYear);
System.out.println("Period Format= " + period);
System.out.println("Months remaining in the year= " + period.getMonths());
6、日期解析和格式化
将日期格式化为不同格式然后解析String以获取Date Time物件是很常见的。
示例程式码如下:
//预设日期格式
LocalDate date = LocalDate.now();
System.out.println("Default format of LocalDate=" + date);
//指定日期格式
System.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
//预设日期格式
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("Default format of LocalDateTime=" + dateTime);
//预设日期时间格式
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));
System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
//预设Instant格式
Instant timestamp = Instant.now();
System.out.println("Default format of Instant=" + timestamp);
//字串解析
LocalDateTime dt = LocalDateTime.parse("27::Apr::2019 21::39::48",
DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"));
System.out.println("Default format after parsing = " + dt);
7、旧版日期时间支援
//java.util.Date转Instant
Instant timestamp = new Date().toInstant();
LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("PST")));
System.out.println("Date = " + date);
//java.util.Date转Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println(time);
//java.util.TimeZone转ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println(defaultZone);
//GregorianCalendar转ZonedDateTime
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
//Instant转java.util.Date
Date dt = Date.from(Instant.now());
System.out.println(dt);
//ZoneId转java.util.TimeZone
TimeZone tz = TimeZone.getTimeZone(defaultZone);
System.out.println(tz);
//ZonedDateTime转GregorianCalendar
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println(gc);
一些最常用的类将是LocalDate和LocalDateTime。 它非常容易使用,可以让你轻松找到对应的方法去完成特定的工作。
将遗留类迁移到新的Date Time类需要一些时间,但它非常值得。