Hey, Nice to meet You. 

必有过人之节.人情有所不能忍者,匹夫见辱,拔剑而起,挺身而斗,此不足为勇也,天下有大勇者,猝然临之而不惊,无故加之而不怒.此其所挟持者甚大,而其志甚远也.          ☆☆☆所谓豪杰之士,

夯实Java基础(十四)----Java8新的日期处理类

1、Java 8新日期介绍

Java8之前处理日期一直是Java程序员比较头疼的问题,从Java 8之后,Java API中添加了许多关于日期的新特性,其中一个最常见也是最实用的便是日期处理的类。

  • java.time.LocalDate:只对年月日做出处理
  • java.time.LocalTime:只对时分秒纳秒做出处理
  • java.time.LocalDateTime :同时可以处理年月日和时分秒

它们是一种更为高效的日期类,比起Date的复杂具有相当高的简洁性,吸取了企业级别的joda.time时间处理的优点,避免了传统的Date和Calendar复合起来计算的难处。Java8 新的日期类都位于com.java.time包下,所以首先来看一下java.time这个包下的类结构图:

image

可以看到除了有四个包:chrono、format、temporal、zone之外,最外层还有一些日期、时间类,这些也是平时比较常用的。而那四个包就用的比较少了,所以先简略介绍下这四个包的用途。

[1]:chrono

chrono包提供历法相关的接口与实现。Java中默认使用的历法是ISO 8601日历系统,它是世界民用历法,也就是我们所说的公历。平年有365天,闰年是366天。闰年的定义是:非世纪年,能被4整除;世纪年能被400整除。为了计算的一致性,公元1年的前一年被当做公元0年,以此类推。此外chrono包提供了四种其他历法,每种历法有自己的纪元(Era)类、日历类和日期类,分别是:

  • 泰国佛教历:ThaiBuddhistEra、ThaiBuddhistChronology和ThaiBuddhistDate;
  • 民国历:MinguoEra、MinguoChronology和MinguoDate;
  • 日本历:JapaneseEra、JapaneseChronology和JapaneseDate
  • 伊斯兰历:HijrahEra、HijrahChronology和HijrahDate:

每个纪元类都是一个枚举类,实现Era接口。Era表示的是一个时间线的分割,比如Java默认的ISO历法中的IsoEra,就包含两个枚举量:BCE和CE,前者表示“公元前”,后者表示“公元”;再比如MinguoEra,包含了两个枚举量:BEFORE_ROC和ROC,ROC的意思是Republic of China,也即新中国,前者表示的就是新中国之前,也即民国,后者表示新中国;所以中国的历法用了“Minguo”这个名字。每种历法的日历系统的实现都是依赖于其纪元的。每个日历类都实现了抽象类AbstractChronology,其中定义了从时间、id、地域设置获取具体日历系统的接口和实现,以及获取特定日历系统下的时间的方法。定义了纪元和日历系统之后,日期类自然就确定好了,每种历法的日期类提供的接口并无大的不同,在实际开发中应用的比较少,也不是本篇的重点,暂且略过。

[2]:format

format包提供了日期格式化的方法。format包中定义了时区名称、日期解析和格式化的各种枚举,以及最为重要的格式化类DateTimeFormatter。需要注意的是,format包类中的类都是final的,都提供了线程安全的访问。在DateTimeFormatter类中提供了ofPattern的静态方法来获得一个DateTimeFormatter,但细看其实现,其实还是调用的DateTimeFormatterBuilder的静态方法:DateTimeFormatterBuilder.appendPattern(pattern).toFormatter();所以我们在实际格式化日期和时间的时候,是两种方式都可以使用的。

[3]:temporal

temporal包中定义了整个日期时间框架的基础:各种时间单位、时间调节器,以及在年月日时分秒中用到的各种属性。Java8中的日期时间类都是实现了temporal包中的时间单位(Temporal)、时间调节器(TemporalAdjuster)和各种属性的接口,所以在后面的日期的操作方法中都是以最基本的时间单位和各种属性为参数的。

[4]:zone

这个包没啥多说的,就是定义了时区转换的各种方法。


而在 java.time 包下比较常用的主要包含下面几个主要的类:

Instant:时间戳
Duration:持续时间,时间差
LocalDate:只包含日期,比如:2016-10-20
LocalTime:只包含时间,比如:23:12:10
LocalDateTime:包含日期和时间,比如:2016-10-20 23:14:21
Period:时间段
ZoneOffset:时区偏移量,比如:+8:00
ZonedDateTime:带时区的时间
Clock:时钟,比如获取目前美国纽约的时间

以及java.time.format包中的

DateTimeFormatter:时间格式化

下面我们通过例子来看如何使用java8新的日期时间库。

2、Java 8日期/时间类

Java 8日期/时间类主要有三个:LocalDate、LocalTime、LocalDateTime

  • LocalDate:表示一个IOS格式(yyyy-MM-hh)的日期,它是不包含具体时间的日期。例如:2014-01-14。它可以用来存储生日、周年纪念日、入职日期等。
  • LocalTime:表示一个时间,它是不含日期的时间。
  • LocalDateTime:表示日期和时间,它包含了日期及时间,不过还是没有偏移信息或者说时区,这是一个最常用的类之一。

它们三者共同特点:

  • 相比于前面的Date和Calendar,他们是线程安全的;
  • 它们是不可变的日期时间对象;

常用方法:由于LocalDate的API与LocalTime、LocalDateTime大都是通用的,所有后面两个的就不展示了。方法使用举例:

创建日期/时间对象

方法 描述
now() 、 now(Zoneld zone) 静态方法,根据当前时间创建对象 、 指定时区的对象
of() 静态方法,根据指定日期,时间创建对象,即自定义日期/时间
// 创建日期/时间对象
@Test
public void testCreateDate() {
    //now():获取当前日期
    LocalDate localDate = LocalDate.now();
    LocalTime localTime = LocalTime.now();
    LocalTime localTime1 = LocalTime.now().withNano(0); // 这个是不带毫秒的
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println("日期:" + localDate);
    System.out.println("时间:" + localTime);
    System.out.println("时间不带毫秒:" + localTime1);
    System.out.println("日期时间:" + localDateTime);

    //of():设置指定的年月日时分秒,没有偏移量
    System.out.println("-----------");
    LocalDateTime localDateTime2 = LocalDateTime.of(2020, 04, 04, 18, 48, 56);
    System.out.println("of()-设置的时间为:" + localDateTime2);
}

获取年、月、日信息

方法 描述
get(TemporalField field) 配合ChronoField枚举获取指定的年月日,例如:ChronoField.YEAR
getYear() 获取日期的年份
getMonth() 获得月份,返回枚举值(如:January)
getMonthValue() 获得月份,返回数字(1-12)
getHour()、getMinute()、getSecond() 获得当前日期的时、分、秒
getDayOfMonth() 获得月份天数(1-31)
getDayOfYear() 获取年份天数(1-366)
getDayOfWeek() 获得星期几
@Test
public void getDateInfo() {
    LocalDateTime localDateTime = LocalDateTime.now();
    //get():获取相关的属性
    System.out.println("年份为:" + localDateTime.get(ChronoField.YEAR));
    System.out.println("月份为:" + localDateTime.get(ChronoField.MONTH_OF_YEAR));
    System.out.println("这年的第几天:" + localDateTime.get(ChronoField.DAY_OF_YEAR));

    //getXXX():获取相关的属性
    System.out.println("这年的第几天:" + localDateTime.getDayOfYear());
    System.out.println("这月的第几天:" + localDateTime.getDayOfMonth());
    System.out.println("这周的星期几:" + localDateTime.getDayOfWeek());
    System.out.println("月份为:" + localDateTime.getMonth());
    System.out.println("月份为:" + localDateTime.getMonthValue());
    System.out.println("小时为:" + localDateTime.getHour());
}

日期的修改

方法 描述
withYear() 将年份修改为指定的值并且返回新的对象
withMonth() 将月份修改为指定的值并且返回新的对象
withDayOfMonth() 将月份修改为指定的值并且返回新的对象
withDayOfYear() 将年份修改为指定的值并且返回新的对象
withHour() 将小时修改为指定的值并且返回新的对象
withMinute() 将分钟修改为指定的值并且返回新的对象
withSecond() 将秒数修改为指定的值并且返回新的对象
with() 根据指定的参数修改,还可以配合TemporalAdjuster提供更加强大的日期修改功能,下面会介绍
@Test
public void testWith() {
    LocalDateTime localDateTime = LocalDateTime.now();
    //withXXX:设置相关的属性,修改后返回了新的对象,体现了不可变性
    LocalDateTime localDateTime2 = localDateTime.withYear(2001);
    System.out.println("当前的时间:" + localDateTime);
    System.out.println("修改年份后:" + localDateTime2);

    LocalDateTime localDateTime3 = localDateTime.withDayOfMonth(22);
    System.out.println("当前的时间:" + localDateTime);
    System.out.println("修改月份后:" + localDateTime3);

    LocalDateTime localDateTime4 = localDateTime.withHour(14);
    System.out.println("当前的时间:" + localDateTime);
    System.out.println("修改小时后:" + localDateTime4);

    // 修改为2222
    LocalDateTime withYear = localDateTime.with(ChronoField.YEAR, 2222);
    System.out.println(withYear);
    // 修改为这年的第15天
    LocalDateTime withDay = localDateTime.with(ChronoField.DAY_OF_YEAR, 15);
    System.out.println(withDay);
}

日期的计算-加减

方法 描述
plusHours() 向当前对象添加几小时
plusDays() 向当前对象添加几天
plusWeeks() 向当前对象添加几周
plusMonths() 向当前对象添加几个月
plusYears() 向当前对象添加几年
minusHours() 从当前对象减去几小时
minusDays() 从当前对象减去几天
minusWeeks() 从当前对象减去几周
minusMonths() 从当前对象减去几月
minusYears() 从当前对象减去几年
plus(long amountToAdd, TemporalUnit unit) 根据TemporalUnit 参数相加
minus(long amountToSubtract, TemporalUnit unit) 根据TemporalUnit 参数相减
@Test
public void testPlusAndMinus() {
    LocalDateTime localDateTime = LocalDateTime.now();
    //plusXXX:增加相关属性
    LocalDateTime localDateTime5 = localDateTime.plusDays(10);
    System.out.println("当前时间:" + localDateTime);
    System.out.println("加10天之后:" + localDateTime5);

    LocalDateTime localDateTime6 = localDateTime.plusYears(2);
    System.out.println("当前时间:" + localDateTime);
    System.out.println("加2年之后:" + localDateTime6);

    //minusXXX:减少相关属性
    LocalDateTime localDateTime7 = localDateTime.minusDays(10);
    System.out.println("当前时间:" + localDateTime);
    System.out.println("减10天之后:" + localDateTime7);

    LocalDateTime localDateTime8 = localDateTime.minusYears(2);
    System.out.println("当前时间:" + localDateTime);
    System.out.println("减2年之后:" + localDateTime8);

    //增加一年-plus(long amountToAdd, TemporalUnit unit)
    localDateTime = localDateTime.plusYears(1);
    localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
    
    //减少一个月-minus(long amountToSubtract, TemporalUnit unit)
    localDateTime = localDateTime.minusMonths(1);
    localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);
}

注:ChronoUnit 枚举表示日期周期单位的标准集合,它实现了TemporalUnit类


日期的判断

方法
isLeapYear() 判断是否为闰年
isEqual() 检查日期是否与指定日期相等
isBefore() 检查日期是否在指定日期前面
isAfter() 检查日期是否在指定日期后面
@Test
public void judgeDate() {
    LocalDate localDate = LocalDate.now();
    boolean leapYear = localDate.isLeapYear();
    System.out.println("是否是闰年:" + leapYear);

    LocalDate date = LocalDate.of(2019, 1, 23);
    boolean equal = date.isEqual(localDate);
    System.out.println("日期是否相等:" + equal);

    boolean before = date.isBefore(localDate);
    boolean after = date.isAfter(localDate);
    System.out.println("否在指定日期前面:" + before);
    System.out.println("否在指定日期后面:" + after);
}

LocalDate ,LocalTime 和 LocalDateTime 之间的互相转换

/**
 * LocalDate ,LocalTime,LocalDateTime 互相转换
 */
@Test
public void testDateConvert() {
    String date = "2020-07-12";
    String time = "15:51:30";
    LocalDate localDate = LocalDate.parse(date);
    LocalTime localTime = LocalTime.parse(time);
    System.out.println(localDate);
    System.out.println(localTime);

    LocalDateTime localDateTime = LocalDateTime.of(2020, 7, 13, 16, 01, 30, 888);
    LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);

    //localDateTime-->LocalDate,LocalTime
    LocalDate localDate1 = localDateTime.toLocalDate();
    LocalTime localTime1 = localDateTime.toLocalTime();

    // LocalDate,LocalTime --> LocalDateTime
    LocalDateTime localDateTime2 = localDate.atTime(16, 2, 30);
    LocalDateTime localDateTime3 = localTime.atDate(localDate);
}

Java日期与旧的日期之间的转换

此处来自:Convert between Date to LocalDateTime - HowToDoInJava

虽然Java8 的日期非常好用,但有时候还是需要转换为Date,二者的相互转换并不是一步到位那么简单,所以,还是需要记录一下转换的api

Date 转 LocalDateTime

Date todayDate = new Date();

LocalDateTime ldt = todayDate.toInstant()
        .atZone( ZoneId.systemDefault() )
        .toLocalDateTime();

System.out.println(ldt);
//2019-05-16T19:22:12.773

LocalDateTime 转 Date

LocalDateTime localDateTime = LocalDateTime.now();

Date date = Date.from( localDateTime.atZone( ZoneId.systemDefault()).toInstant());

System.out.println(date);
//Thu May 16 19:22:37 CST 2019

为了方便直接封装至一个DateUtils工具类中:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
 
public class DateUtils {
 
    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }
 
    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
 
    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }
 
    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
}

3、瞬时(Instant)

Instant类:时间线上的一个瞬时点,表示一个时间戳。设计初衷是为了便于机器使用,不提供人类意义上的时间单位,获取当前时刻的时间戳;它只是简单的从1970年1月1日0时0分0秒(UTC)开始的秒数。常用方法:

方法 描述
now() 静态方法,返回默认的UTC时区的Instant类的对象
atOffset(ZoneOffset offset) 将此瞬间与偏移组合起来创建一个OffsetDateTime
toEpochMilli() 返回1970-01-01 00:00:00到当前的毫秒数,即时间戳
ofEpochMilli(long epochMilli) 静态方法,返回在1970-01-01 00:00:00基础加上指定毫秒数之后的Instant类的对象
ofEpochSecond(long epochSecond) 静态方法,返回在1970-01-01 00:00:00基础加上指定秒数之后的Instant类的对象
@Test
public void testInstant() {
    //now():获取标准时间,即本初子午线的时间,没有偏移量
    Instant instant = Instant.now();
    System.out.println(instant);

    //atOffset:添加偏移量,北京在东八区,时区加八即为北京时间
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime);

    //toEpochMilli:获取1970-01-01 00:00:00 开始的毫秒;类似Date的getTime
    long epochMilli = instant.toEpochMilli();
    System.out.println(epochMilli);

    //ofEpochMilli:通过给定的毫秒数,获取Instant实例;类似Date(long millis)
    Instant ofEpochMilli = Instant.ofEpochMilli(1562384592201L);
    System.out.println(ofEpochMilli);
}

4、日期间隔(Period)/持续时间(Duration)

Java 8 中还引入的两个与日期相关的新类:Period 和 Duration。两个类分别表示时间量或两个日期之间的差,两者之间的差异为:Period基于日期值,而Duration基于时间值。

@Test
public void testDuration() {
    //Duration
    LocalTime time1 = LocalTime.of(15, 7, 50);
    LocalTime time2 = LocalTime.of(17, 8, 53);
    LocalDateTime dateTime1 = LocalDateTime.of(2020, 5, 12, 14, 22, 28);
    LocalDateTime dateTime2 = LocalDateTime.of(2024, 5, 12, 14, 22, 28);
    Instant instant1 = Instant.ofEpochSecond(1);
    Instant instant2 = Instant.now();
    Duration d1 = Duration.between(time1, time2);
    Duration d2 = Duration.between(dateTime1, dateTime2);
    Duration d3 = Duration.between(instant1, instant2);

    System.out.println("LocalTime持续秒数:" + d1.getSeconds());
    System.out.println("LocalDateTime持续秒数:" + d2.getSeconds());
    System.out.println("Instant持续秒数" + d3.getSeconds());
}

@Test
public void testPeriod() {
    //Period
    LocalDate date1 = LocalDate.of(2020, 7, 6);
    LocalDate date2 = LocalDate.of(2025, 9, 10);

    Period period = Period.between(date1, date2);
    System.out.println("相差年数:" + period.getYears());
    System.out.println("相差月数:" + period.getMonths());
    System.out.println("相差天数:" + period.getDays());
    System.out.println("总月数:" + period.toTotalMonths());
}

5、日期校正器TemporalAdjusters

TemporalAdjusters一般配合with()方法来使用。有的时候,你需要对日期进行一些更加 复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjusters对象, 更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的 TemporalAdjusters。你可以通过TemporalAdjusters类的静态工厂方法访问它们,如下所示:

下面是TemporalAdjusters类中的方法:

方法 描述
dayOfWeekInMonth(int ordinal,DayOfWeek dayOfWeek) 返回一个新的日期,它的值为同一个月中每一周的第几天
firstDayOfMonth() 返回一个新的日期,它的值为当月的第一天
firstDayOfNextMonth() 返回一个新的日期,它的值为下月的第一天
firstDayOfNextYear() 返回一个新的日期,它的值为明年的第一天
firstDayOfYear() 返回一个新的日期,它的值为当年的第一天
firstInMonth(DayOfWeek dayOfWeek) 返回一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
lastDayOfMonth() 返回一个新的日期,它的值为当月的最后一天
lastDayOfNextMonth() 返回一个新的日期,它的值为下月的最后一天
lastDayOfNextYear() 返回一个新的日期,它的值为明年的最后一天
lastDayOfYear() 返回一个新的日期,它的值为今年的最后一天
lastInMonth(DayOfWeek dayOfWeek) 返回一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值
next(DayOfWeek dayOfWeek)、previous(DayOfWeek dayOfWeek) 返回一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
nextOrSame(DayOfWeek dayOfWeek)、previousOrSame(DayOfWeek dayOfWeek) 返回一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象

方法使用举例:

@Test
public void testTemporalAdjusters(){
    //dayOfWeekInMonth:返回这个月第二周星期二的日期
    LocalDate localDate1=LocalDate.of(2020,9,15);
    LocalDate localDate2 = localDate1.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
    System.out.println("默认时间:"+localDate1);
    System.out.println("更改时间:"+localDate2);

    //firstDayOfMonth():这个月第一天
    System.out.println("---------");
    LocalDate localDate3=localDate1.with(TemporalAdjusters.firstDayOfMonth());
    System.out.println("默认时间:"+localDate1);
    System.out.println("更改时间:"+localDate3);

    //lastDayOfMonth():这个月最后一天
    System.out.println("---------");
    LocalDate localDate4=localDate1.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println("默认时间:"+localDate1);
    System.out.println("更改时间:"+localDate4);

    //nextOrSame():获取周2时间,如果当前时间刚好是星期2,那么就返回当前时间
    System.out.println("---------");
    LocalDate localDate5 = localDate1.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
    System.out.println("默认时间:"+localDate1);
    System.out.println("更改时间:"+localDate5);
}

运行结果:

img

6、Java 8的Clock时钟类

Java 8增加了一个Clock时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。

package com.shxt.demo02;

import java.time.Clock;

public class Demo10 {
    public static void main(String[] args) {
        // Returns the current time based on your system clock and set to UTC.
        Clock clock = Clock.systemUTC();
        System.out.println("Clock : " + clock.millis());

        // Returns time based on system clock zone
        Clock defaultClock = Clock.systemDefaultZone();
        System.out.println("Clock : " + defaultClock.millis());

    }
}

7、Java 8日期解析和格式化(DateTimeFormatter)

之前格式化有 SimpleDateFormatDateFormat,但是它们两者都是线程不安全的!啥情况下会有这样的问题呢?如果我们为了实现日期转换这样的工具,每次都new一个对象,但是用完了就不用了,就造成了浪费,为此我们会将它写成单例的,但是单例的同时,一个对象供多个线程使用的时候,就会出现线程安全的问题。这个时候就需要这个新的jdk8出的 DateTimeformatter 这个类。

该类提供了三种格式化方法:

  1. 预定义的标准格式。如:DateTimeFormatter.ISO_DATE_TIME;
  2. 本地化相关的格式。如:DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
  3. 自定义的格式。如:DateTimeFormatter.ofPattern(“yyyy-MM-dd hh:mm:ss”);
    // 日期格式化
    //预定义的标准格式
    @Test
    public void test() {
        LocalDateTime now = LocalDateTime.now();
        //预定义的标准格式
        DateTimeFormatter df = DateTimeFormatter.ISO_DATE_TIME;//2019-08-06T16:38:23.756
        //DateTimeFormatter df1 = DateTimeFormatter.ISO_DATE;//2019-08-06
        //格式化操作
        String str = df.format(now);
        System.out.println(str);
    }

    //本地化相关的格式
    @Test
    public void test1() {
        LocalDateTime now = LocalDateTime.now();
        //本地化相关的格式
        //DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//2019年8月6日 下午04时40分03秒
        DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);//19-8-6 下午4:40
        //格式化操作
        String str = df.format(now);
        System.out.println(str);
    }

    //自定义的格式
    @Test
    public void test2() {
        LocalDateTime now = LocalDateTime.now();
        //自定义的格式
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒  SSS毫秒  E 是这一年的D天");
        //格式化操作
        String str = df.format(now);
        System.out.println(str);
    }

6.1 由字符串(String)转为日期

    //把字符串解析为日期对象
    @Test
    public void test3() {
        //1.默认的格式调用parse进行解析
        String date = "2020-12-12";
        LocalDate localDate = LocalDate.parse(date);
        System.out.println(localDate);

        //2.自定义的匹配格式(年月日)
        String date1 = "2020.12.12";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy.MM.dd");
        //--解析操作
        LocalDate localDate1 = LocalDate.parse(date1, dtf);
        System.out.println(localDate1);
        //--注:上面的解析操作等价于下面
        TemporalAccessor accessor = dtf.parse(date1);
        LocalDate localDate2 = LocalDate.from(accessor);
        System.out.println(localDate2);

        //3.有年月日和时间
        String datetime = "2020/12/24 18--15--56";
        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH--mm--ss");
        LocalDateTime localDateTime = LocalDateTime.parse(datetime, dtf1);
        System.out.println(localDateTime);
    }

6.2 由日期转为字符串(String)

  • 如果是LocalDate这种标准格式的,直接toString就可以了。
  • 如果是LocalTime这种格式的,toString会附带纳秒值21:06:30.760163, 这个时候你可以使用日期格式器,或者这样 LocalTime time = LocalTime.now().withNano(0),把纳秒直接清0。
  • 如果是LocalDateTime,这个时候是需要一个日期转换器的。才能由时间+日期->想要的时间。
    //把日期对象转换为字符串
    @Test
    public void test4() {
        //1.LocalDate如果是默认的标准格式(yyyy-MM-dd),则直接调用toString,
        // 如果不是则需要使用DateTimeFormatter进行格式匹配,然后调用dtf的format()
        LocalDate now = LocalDate.now();
        System.out.println(now.toString());

        //2.LocalTime的默认格式
        LocalTime localTime = LocalTime.now().withNano(0);
        System.out.println(localTime.toString());

        //3.LocalDateTime格式,这里使用自定义的格式匹配进行匹配
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.now();
        String result = localDateTime.format(dtf);
        System.out.println(result);
    }

8、Java 8 处理不同时区的时间

Java 8对时区处理的优化也是Java8中日期时间API的一大亮点,不仅分离了日期和时间,也把时区分离出来了。现在有一系列单独的类如ZoneId来处理特定时区,ZoneDateTime类来表示某时区下的时间。这在Java 8以前都是 GregorianCalendar类来做的。下面这个例子展示了如何把本时区的时间转换成另一个时区的时间。

@Test
public void testZone() {
    // 查看当前的时区
    ZoneId defaultZone = ZoneId.systemDefault();
    System.out.println(defaultZone); //Asia/Shanghai

    // 获取所有合法的“区域/城市”字符串
    Set<String> zoneIds = ZoneId.getAvailableZoneIds();

    // 查看美国纽约当前的时间
    ZoneId america = ZoneId.of("America/New_York");
    LocalDateTime shanghaiTime = LocalDateTime.now();
    LocalDateTime americaDateTime = LocalDateTime.now(america);
    System.out.println(shanghaiTime); //2019-11-06T15:20:27.996
    System.out.println(americaDateTime); //2019-11-06T02:20:27.996 ,可以看到美国与北京时间差了13小时

    // 带有时区的时间 由两部分构成,LocalDateTime和ZoneId
    ZonedDateTime americaZoneDateTime = ZonedDateTime.now(america);
    System.out.println(americaZoneDateTime); //2019-11-06T02:23:44.863-05:00[America/New_York]

    // ZoneOffset,它是以当前时间和世界标准时间(UTC)/格林威治时间(GMT)的偏差来计算
    ZoneOffset zoneOffset = ZoneOffset.of("+09:00");
    LocalDateTime localDateTime = LocalDateTime.now();
    OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, zoneOffset);
}

9、Java 8新日期小结

这次主要学习了Java8中新的日期处理类

  1. LocalDate、LocalTime、LocalDateTime处理日期时间都非常的方便,而且它们是线程安全的,
  2. 新版的日期和时间API中,日期和时间对象是不可变的。
  3. LocalDate日期是一个便于使用的日期类,线程安全,Date类比较复杂,时间计算麻烦。
  4. DateTimeFormatter的使用也安全,方便。以后用它来代替SimpleDateFormat
  5. TemporalAdjuster 让你能够用更精细的方式操纵日期,不再局限于一次只能改变它的 一个值,并且你还可按照需求定义自己的日期转换器
  6. JDBC的TimeStamp类和LocalDateTime的转换也很方便,提供了相应的方法。
  7. 使用的时候,日期必须是标准的yyyy-MM-dd格式,比如1月必须写成01,不然会报错。
posted @ 2019-08-06 18:01  唐浩荣  阅读(1481)  评论(0编辑  收藏  举报