精华内容
下载资源
问答
  • java8日期
    千次阅读
    2020-07-02 10:35:52

    java8日期转时间戳

    如今,一些应用程序仍在使用java.util.Datejava.util.Calendar API,包括使我们的生活更轻松地使用这些类型的库,例如JodaTime。 但是,Java 8引入了新的API来处理日期和时间,这使我们可以对日期和时间表示进行更精细的控制,为我们提供不可变的datetime对象,更流畅的API以及在大多数情况下提高性能,而无需使用其他库。 让我们看一下基础知识。

    LocalDate / LocalTime / LocalDateTime

    让我们开始与最相关的新API的java.util.DateLocalDate ,日期的API,表示没有时间的日期; LocalTime ,不带日期的时间表示; 和LocalDateTime ,这是前两个的组合。 所有这些类型都代表一个区域的本地日期和/或时间,但是,就像java.util.Date一样,它们包含表示该区域的信息,仅表示当前日期和时间。时区。

    首先,这些API支持简单的实例化:

    LocalDate date = LocalDate.of(2018,2,13);
    // Uses DateTimeformatter.ISO_LOCAL_DATE for which the format is: yyyy-MM-dd
    LocalDate date = LocalDate.parse("2018-02-13");
    
    LocalTime time = LocalTime.of(6,30);
    // Uses DateTimeFormatter.ISO_LOCAL_TIME for which the format is: HH:mm[:ss[.SSSSSSSSS]]
    // this means that both seconds and nanoseconds may optionally be present.
    LocalTime time = LocalTime.parse("06:30");
    
    LocalDateTime dateTime = LocalDateTime.of(2018,2,13,6,30);
    // Uses DateTimeFormatter.ISO_LOCAL_DATE_TIME for which the format is the
    // combination of the ISO date and time format, joined by 'T': yyyy-MM-dd'T'HH:mm[:ss[.SSSSSSSSS]]
    LocalDateTime dateTime = LocalDateTime.parse("2018-02-13T06:30");

    在它们之间进行转换很容易:

    // LocalDate to LocalDateTime
    LocalDateTime dateTime = LocalDate.parse("2018-02-13").atTime(LocalTime.parse("06:30"));
    
    // LocalTime to LocalDateTime
    LocalDateTime dateTime = LocalTime.parse("06:30").atDate(LocalDate.parse("2018-02-13"));
    
    // LocalDateTime to LocalDate/LocalTime
    LocalDate date = LocalDateTime.parse("2018-02-13T06:30").toLocalDate();
    LocalTime time = LocalDateTime.parse("2018-02-13T06:30").toLocalTime();

    除此之外,使用`plus`和`minus`方法以及一些实用程序功能,对我们的日期和时间表示进行操作非常容易:

    LocalDate date = LocalDate.parse("2018-02-13").plusDays(5);
    LocalDate date = LocalDate.parse("2018-02-13").plus(3, ChronoUnit.MONTHS);
    
    LocalTime time = LocalTime.parse("06:30").minusMinutes(30);
    LocalTime time = LocalTime.parse("06:30").minus(500, ChronoUnit.MILLIS);
    
    LocalDateTime dateTime = LocalDateTime.parse("2018-02-13T06:30").plus(Duration.ofHours(2));
    
    // using TemporalAdjusters, which implements a few useful cases:
    LocalDate date = LocalDate.parse("2018-02-13").with(TemporalAdjusters.lastDayOfMonth());

    现在我们如何从java.util.Date移到LocalDateTime及其变体? 好吧,这很简单:我们可以将Date类型转换为Instant类型,该类型表示从1970年1月1日开始的时间,然后我们可以使用Instant和当前区域实例化LocalDateTime

    LocalDateTime dateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());

    要转换回日期,我们可以简单地使用Java 8时间类型表示的Instant。 但是要注意的一件事是,尽管LocalDateLocalTimeLocalDateTime不包含任何Zone或Offset信息,但它们确实表示特定区域中的本地日期和/或时间,因此它们确实保留了当前的偏移量。在那个地区。 因此,我们需要提供一个偏移量以将特定类型正确转换为Instant。

    // represents Wed Feb 28 23:24:43 CET 2018
    Date now = new Date();
    
    // represents 2018-02-28T23:24:43.106
    LocalDateTime dateTime = LocalDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault());
    
    // represent Wed Feb 28 23:24:43 CET 2018
    Date date = Date.from(dateTime.toInstant(ZoneOffset.ofHours(1)));
    Date date = Date.from(dateTime.toInstant(ZoneId.systemDefault().getRules().getOffset(dateTime)));

    时间差异–持续时间和期间

    您已经注意到,在以上示例之一中,我们使用了Duration对象。 DurationPeriod是两个日期之间时间的两种表示形式,前者表示以秒和纳秒为单位的时间差,后者以天,月和年表示。

    什么时候应该使用这些? Period ,当你需要知道两者之间的时间差LocalDate陈述:

    Period period = Period.between(LocalDate.parse("2018-01-18"), LocalDate.parse("2018-02-14"));

    您在寻找具有时间信息的表示形式之间的差异时的Duration时间:

    Duration duration = Duration.between(LocalDateTime.parse("2018-01-18T06:30"), LocalDateTime.parse("2018-02-14T22:58"));

    使用toString()输出PeriodDuration ,将基于ISO-8601标准使用特殊格式。 周期使用的模式是PnYnMnD,其中n定义周期内存在的年,月或日的数量。 这意味着P1Y2M3D定义为1年2个月3天。 。 模式中的“ P”是时段指示符,它告诉我们以下格式表示一个时段。 使用该模式,我们还可以使用parse()方法基于字符串创建句点。

    // represents a period of 27 days
    Period period = Period.parse("P27D");

    使用Durations ,由于Java 8不使用相同的模式,因此我们稍微偏离了ISO-8601标准。 ISO-8601定义的模式是PnYnMnDTnHnMn.nS。 这基本上是“ Period模式,带有时间表示形式。 在模式中,T是时间标记,因此后面的部分定义了以小时,分钟和秒为单位的持续时间。

    Java的8个使用两种特定模式的Duration ,解析字符串,一当就是PnDTnHnMn.nS Duration ,以及调用时PTnHnMn.nS toString()上的一个方法Duration实例。

    最后但并非最不重要的一点是,我们还可以通过使用类型上的相应方法来检索时间段或持续时间的各个部分。 但是,重要的是要知道各种日期时间类型也通过使用ChronoUnit枚举类型来支持此功能。 让我们看一些例子:

    // represents PT664H28M
    Duration duration = Duration.between(LocalDateTime.parse("2018-01-18T06:30"), LocalDateTime.parse("2018-02-14T22:58"));
    
    // returns 664
    long hours = duration.toHours();
    
    // returns 664
    long hours = LocalDateTime.parse("2018-01-18T06:30").until(LocalDateTime.parse("2018-02-14T22:58"), ChronoUnit.HOURS);

    使用区域和偏移量– ZonedDateTime和OffsetDateTime

    到目前为止,我们已经展示了新的日期API如何使某些事情变得容易一些。 但是,真正与众不同的是在时区上下文中轻松使用日期和时间的能力。 Java 8为我们提供了ZonedDateTimeOffsetDateTime ,第一个是LocalDateTime其中包含特定区域(例如,欧洲/巴黎)的信息,第二个是带有偏移量的LocalDateTime 。 有什么不同? OffsetDateTime使用UTC /格林威治标准时间与指定日期之间的固定时差,而ZonedDateTime指定表示时间的区域,并将考虑夏时制。

    转换为以下两种类型都很容易:

    OffsetDateTime offsetDateTime = LocalDateTime.parse("2018-02-14T06:30").atOffset(ZoneOffset.ofHours(2));
    // Uses DateTimeFormatter.ISO_OFFSET_DATE_TIME for which the default format is
    // ISO_LOCAL_DATE_TIME followed by the offset ("+HH:mm:ss").
    OffsetDateTime offsetDateTime = OffsetDateTime.parse("2018-02-14T06:30+06:00");
    
    ZonedDateTime zonedDateTime = LocalDateTime.parse("2018-02-14T06:30").atZone(ZoneId.of("Europe/Paris"));
    // Uses DateTimeFormatter.ISO_ZONED_DATE_TIME for which the default format is
    // ISO_OFFSET_DATE_TIME followed by the the ZoneId in square brackets.
    ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-02-14T06:30+08:00[Asia/Macau]");
    // note that the offset does not matter in this case.
    // The following example will also return an offset of +08:00
    ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-02-14T06:30+06:00[Asia/Macau]");

    在它们之间进行切换时,必须记住,从ZonedDateTime转换为OffsetDateTime将考虑夏时制,而在另一个方向上从OffsetDateTimeZonedDateTime意味着您将没有有关区域区域的信息,也不会对夏时制应用任何规则。 这是因为偏移量未定义任何时区规则,也未绑定到特定区域。

    ZonedDateTime winter = LocalDateTime.parse("2018-01-14T06:30").atZone(ZoneId.of("Europe/Paris"));
    ZonedDateTime summer = LocalDateTime.parse("2018-08-14T06:30").atZone(ZoneId.of("Europe/Paris"));
    
    // offset will be +01:00
    OffsetDateTime offsetDateTime = winter.toOffsetDateTime();
    // offset will be +02:00
    OffsetDateTime offsetDateTime = summer.toOffsetDateTime();
    
    OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime();
    
    OffsetDateTime offsetDateTime = LocalDateTime.parse("2018-02-14T06:30").atOffset(ZoneOffset.ofHours(5));
    ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();

    现在,如果我们想知道特定时区或偏移时间在我们自己的时区中怎么办? 嗯,为此还定义了一些方便的功能!

    // timeInMacau represents 2018-02-14T13:30+08:00[Asia/Macau]
    ZonedDateTime timeInMacau = LocalDateTime.parse( "2018-02-14T13:30" ).atZone( ZoneId.of( "Asia/Macau" ) );
    // timeInParis represents 2018-02-14T06:30+01:00[Europe/Paris]
    ZonedDateTime timeInParis = timeInMacau.withZoneSameInstant( ZoneId.of( "Europe/Paris" ) );
    
    OffsetDateTime offsetInMacau = LocalDateTime.parse( "2018-02-14T13:30" ).atOffset( ZoneOffset.ofHours( 8 ) );
    OffsetDateTime offsetInParis = offsetInMacau.withOffsetSameInstant( ZoneOffset.ofHours( 1 ) );

    如果我们不得不一直在这些类型之间手动进行转换以获取我们需要的类型,那将是一件麻烦事。 这就是Spring框架为我们提供帮助的地方。 Spring为我们提供了许多现成的日期时间转换器,这些日期时间转换器已在ConversionRegistry中注册,可以在org.springframework.format.datetime.standard.DateTimeConverters类中找到。

    使用这些转换器时,重要的是要知道它不会转换区域或偏移量之间的时间。 该ZonedDateTimeToLocalDateTimeConverter ,例如,将返回LocalDateTime因为它是在,而不是指定的区域LocalDateTime ,它会在你的应用程序的区域代表。

    ZonedDateTime zonedDateTime = LocalDateTime.parse("2018-01-14T06:30").atZone(ZoneId.of("Asia/Macau"));
    // will represent 2018-01-14T06:30, regardless of the region your application has specified
    LocalDateTime localDateTime = conversionService.convert(zonedDateTime, LocalDateTime.class);

    最后但并非最不重要的一点是,您可以查询ZoneId.getAvailableZoneIds()来查找所有可用时区,或使用地图ZoneId.SHORT_IDS ,其中包含一些时区的缩写版本,例如EST,CST等。

    格式化–使用

    当然,世界各地都使用不同的格式来指定时间。 一个应用程序可能使用MM-dd-yyyy,而另一个应用程序使用dd / MM / yyyy。 一些应用程序希望消除所有混淆,并用yyyy-MM-dd表示其日期。 使用java.util.Date ,我们将快速转向使用多个格式化程序。 但是, DateTimeFormatter类为我们提供了可选的模式,因此我们可以将单个格式化程序用于多种格式! 让我们来看一些例子。

    // Let’s say we want to convert all of patterns mentioned above.
    // 09-23-2018, 23/09/2018 and 2018-09-23 should all convert to the same LocalDate.
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][dd/MM/yyyy][MM-dd-yyyy]");
    LocalDate.parse("09-23-2018", formatter);
    LocalDate.parse("23/09/2018", formatter);
    LocalDate.parse("2018-09-23", formatter);

    模式中的方括号定义了模式中的可选部分。 通过使我们的各种格式成为可选,与字符串匹配的第一个模式将用于转换我们的日期表示形式。 当您使用多种模式时,这可能很难理解,因此让我们看一下使用构建器模式创建DateTimeFormatter方法。

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    	.appendOptional( DateTimeFormatter.ofPattern( "yyyy-MM-dd" ) )
    	.optionalStart().appendPattern( "dd/MM/yyyy" ).optionalEnd()
    	.optionalStart().appendPattern( "MM-dd-yyyy" ).optionalEnd()
    	.toFormatter();

    这些是包含多个模式的基础,但是如果我们的模式仅稍有不同,该怎么办? 让我们看一下yyyy-MM-dd和yyyy-MMM-dd。

    // 2018-09-23 and 2018-Sep-23 should convert to the same LocalDate.
    // Using the ofPattern example we’ve used above will work:
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy-MMM-dd]" );
    LocalDate.parse( "2018-09-23", formatter );
    LocalDate.parse( "2018-Sep-23", formatter );
    
    // Using the ofPattern example where we reuse the common part of the pattern
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyy-[MM-dd][MMM-dd]" );
    LocalDate.parse( "2018-09-23", formatter );
    LocalDate.parse( "2018-Sep-23", formatter );

    但是,在转换为字符串时,不应使用支持多种格式的格式化程序,因为当我们使用格式化程序将日期格式化为字符串表示形式时,它还将使用可选模式。

    LocalDate date = LocalDate.parse("2018-09-23");
    // will result in 2018-09-232018-Sep-23
    date.format(DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy-MMM-dd]" ));
    // will result in 2018-09-23Sep-23
    date.format(DateTimeFormatter.ofPattern( "yyyy-[MM-dd][MMM-dd]" ));

    由于我们处于21世纪,因此显然我们必须考虑全球化,并且我们希望为用户提供本地化日期。 为确保您的DateTimeFormatter返回特定的语言环境,您只需执行以下操作:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEEE, MMM dd, yyyy" ).withLocale(Locale.UK);
    
    
    DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MMM-dd" ).toFormatter(Locale.UK);

    要查找可用的语言环境,可以使用Locale.getAvailableLocales()

    现在可能是您收到的日期格式比您使用的类型包含更多的信息。 一旦提供的日期表示形式与该模式不一致,则DateTimeFormatter将引发异常。 让我们仔细研究这个问题以及如何解决它。

    // The issue: this will throw an exception.
    LocalDate date = LocalDate.parse("2018-02-15T13:45");
    // We provide a DateTimeFormatter that can parse the given date representation.
    // The result will be a LocalDate holding 2018-02-15.
    LocalDate date = LocalDate.parse("2018-02-15T13:45", DateTimeFormatter.ISO_LOCAL_DATE_TIME);

    让我们创建一个可以处理ISO日期,时间和日期时间模式的格式化程序。

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    	.appendOptional( DateTimeFormatter.ISO_LOCAL_DATE )
    	.optionalStart().appendLiteral( "T" ).optionalEnd()
    	.appendOptional( DateTimeFormatter.ISO_LOCAL_TIME )
    	.toFormatter();

    现在,我们可以完美地执行以下所有操作:

    // results in 2018-03-16
    LocalDate date = LocalDate.parse( "2018-03-16T06:30", formatter );
    LocalDate date = LocalDate.parse( "2018-03-16", formatter );
    // results in 06:30
    LocalTime time = LocalTime.parse( "2018-03-16T06:30", formatter );
    LocalTime time = LocalTime.parse( "06:30", formatter );
    LocalDateTime localDateTime = LocalDateTime.parse( "2018-03-16T06:30", formatter );

    现在,下一期是哪里来的? 如果您尝试解析LocalDateTime的日期模式怎么办? 如果您希望使用LocalTime并得到日期表示,反之亦然怎么办?

    // will throw an exception
    LocalDateTime localDateTime = LocalDateTime.parse("2018-03-16", formatter);
    LocalDate localDate = LocalDate.parse("06:30", formatter);

    对于这后两种情况,没有一个正确的解决方案,但这取决于您的要求,或者这些日期和时间代表或可能代表什么。 使用TemporalQuery可以找到魔术,您可以使用它为模式的一部分创建默认值。

    如果我们以LocalDateTime开头,而您只需要LocalDateLocalTime ,则将收到LocalDateTime的相应部分。 要创建LocalDateTime ,我们需要其保存的日期和时间的默认值。 假设如果您不提供有关日期的信息,我们将返回今天的日期,如果您不提供时间,则将假设您的意思是一天的开始。

    由于我们将返回LocalDateTime ,因此不会将其解析为LocalDateLocalTime ,因此让我们使用ConversionService来获取正确的类型。

    TemporalQuery<TemporalAccessor> myCustomQuery = new MyCustomTemporalQuery();
    // results in 2018-03-16
    LocalDateTime localDateTime = conversionService.convert( formatter.parse( "2018-03-16", myCustomQuery ), LocalDateTime.class );
    // results in 00:00
    LocalTime localTime = conversionService.convert( formatter.parse( "2018-03-16", myCustomQuery ), LocalTime.class );
    
    class MyCustomTemporalQuery implements TemporalQuery<TemporalAccessor>
    {
    	@Override
    	public TemporalAccessor queryFrom( TemporalAccessor temporal ) {
    		LocalDate date = temporal.isSupported( ChronoField.EPOCH_DAY )
    			? LocalDate.ofEpochDay( temporal.getLong( ChronoField.EPOCH_DAY ) ) : LocalDate.now();
    		LocalTime time = temporal.isSupported( ChronoField.NANO_OF_DAY )
    			? LocalTime.ofNanoOfDay( temporal.getLong( ChronoField.NANO_OF_DAY ) ) : LocalTime.MIN;
    		return LocalDateTime.of( date, time );
    	}
    }

    使用TemporalQuery ,我们可以检查存在的信息,并为缺少的任何信息提供默认值,从而使我们能够使用应用程序中有意义的逻辑轻松地转换为所需的类型。

    要了解如何编写有效的时间模式,请查看DateTimeFormatter文档

    结论

    大多数新功能需要一些时间来理解和习惯,Java 8 Date / Time API也不例外。 新的API使我们能够更好地访问必要的正确格式,以及使用日期时间操作的更加标准化和易读的方式。 使用这些提示和技巧,我们几乎可以涵盖所有用例。

    翻译自: https://www.javacodegeeks.com/2018/03/java-8-date-and-time.html

    java8日期转时间戳

    更多相关内容
  • Java8日期时间API

    千次阅读 多人点赞 2020-12-12 23:56:51
    文章目录Java 8以前日期时间API存在的问题关于时间和时区GMT和UTC时区Unix时间戳Java 中的 Unix 时间LocalDate、LocalTime、LocalDateTime获取对象的方法常用方法与获取相关的方法(get系类的方法)转换的方法判断的...

    Java 8以前日期时间API存在的问题

    作为开发者,经常需要处理日期时间。在Java 8以前,相信你对 java.util.Datejava.util.Calendarjava.util.GregoiranCalendarjava.text.SimpleDateFormat 这四大类非常熟悉,它们分别用于处理日期、日历、公历、日期时间格式化。

    这四个类有好多陷阱和坑,比如

    1. 非线程安全:这四大类都不是线程安全的。开发者在使用这些类时必须自己处理多线程并发问题。
    2. 设计不佳 :一方面日期和日期格式化分布在多个包中;另一方面,java.util.Date 的默认日期为1970年1月1日,没有统一性。而且 Date 类也缺少直接操作日期的相关方法。
    3. 时区处理困难:因为设计不佳,开发人员不得不编写大量代码来处理时区问题。
    4. 还有其它一些问题,如Calendar类月份从零开始计算等。

    面对种种问题,Java 8 终于重新设计了所有日期时间、日历及时区相关的 API。并把它们都统一放置在 java.time 包和子包下。并作出了以下改进

    1. 新的日期时间 API 是线程安全的。不仅没有 setter 方法,而且任何对实例的变更都会返回一个新的实例,保证原来的实例不变。
    2. 新的日期时间 API 提供了大量的方法,用于修改日期时间的各个部分,并返回一个新的实例。
    3. 借鉴了第三方日期时间库joda很多的优点。
    4. 在时区方面,新的日期时间 API 引入了 ( domain ) 这个概念。

    同时 Java 8 还针对原来复杂的 API 进行重新组合和拆分,分成了好多个类。

    关于时间和时区

    GMT和UTC

    GMT,即格林尼治标准时间,也就是世界时。GMT的正午是指当太阳横穿格林尼治子午线(本初子午线)时的时间。但由于地球自转不均匀不规则,导致GMT不精确,现在已经不再作为世界标准时间使用。

    UTC,即协调世界时。是经过平均太阳时(以格林威治时间 GMT 为准)、地轴运动修正后的新时标,以「秒」为单位的国际原子时所综合精算而成的时间。为确保UTC与GMT相差不会超过0.9秒,在有需要的情况下(例如 1998-12-31T23:59:60Z)会在UTC内加上正或负闰秒。协调世界时区会使用 “Z” 来表示,协调世界时也会被称为 “Zulu time”。UTC现在作为世界标准时间使用。

    所以,UTC与GMT基本上等同,误差不超过0.9秒。不过日常使用中,GMT 与 UTC 的功能与精确度是没有差别的。

    时区

    时区作为地理概念,表示 “遵守统一时间标准的一个地区”。

    使用与 UTC 的偏移来表示时区,例如:中国所在时区为 UTC+08:00(又称为 Chinese Standard Time,即 “中国标准时间”)

    地球自西向东旋转,东边比西边先看到太阳,东边的时间也比西边的早。为了统一世界的时间,1884年的国际经度会议规规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为零时区(基准 UTC),东1-12区,西1-12区,中国北京处于东8区(UTC+08:00),那么我们的时间会领先基准-也就是我们在早上 9 点时,伦敦是早上 1 点。

    Unix时间戳

    计算机中的Unix时间戳,使用自 1970-01-01T00:00:00Z(Z 即表示 UTC 时间)至今的毫秒差作为表示时间的数值,并且移除期间的“闰秒”(例如 1998-12-31T23:59:60Z),这么做当然是为了简化计算机对时间操作的复杂度。Unix 时间体系中,每天固定 86400 秒,这个时间是绝对公立的,它和时区没有任何关系。

    Java 中的 Unix 时间

    Java 确保:每天 24 小时、每小时 60 分、每分钟 60 秒。

    Java 中获取 “当前” 时间的方法,其底层实现,全部由 java.lang.System.currentTimeMillis() 提供自 UTC 1970-01-01T00:00:00 的毫秒数。java.lang.System.currentTimeMillis() 作为 native 方法,其实现与 JVM 所在的机器相关(通常使用 NTP 协议保持更新)。

    LocalDate、LocalTime、LocalDateTime

    java.time.LocalDate 用于表示 “本地日期”,无 “时间”。LocalDate 不承载时区信息。

    java.time.LocalTime 用于表示 “本地时间”,无 “日期”。LocalTime 不承载时区信息。

    java.time.LocalDateTime 用于表示 “本地日期与时间”。LocalDateTime 不承载时区信息。

    LocalDate 实例与 LocalTime 实例能够共同构建 LocalDateTime 实例,由 LocalDateTime 实例能够获取 LocalDate 实例与 LocalTime 实例。

    由于 LocalDateTime 不承载时区信息,因此,其不能与 Instant 相互转换,必须提供时区信息。

    获取对象的方法

    获取对象的方法:

    1. 通过静态方法 :now()(获取的时间是系统当前的时间
    2. 通过静态方法:of()(方法参数可以指定时间
    @Test
    public void test01() {
        /* 通过静态方法 now() 返回该类的实例 */
        //获取当前的日期时分秒
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
    
        //获取当前的日期
        LocalDate now1 = LocalDate.now();
        System.out.println(now1);
    
        //获取当前的时分秒
        LocalTime now2 = LocalTime.now();
        System.out.println(now2);
    
        System.out.println("=========================================");
        /* 静态方法 of() 返回该类的实例 */
        //指定日期时分秒
        LocalDateTime localDateTime = LocalDateTime.of(2048, 11, 25, 12, 00, 30);
        System.out.println(localDateTime);
    
        //指定日期
        LocalDate date = LocalDate.of(2020, 12, 12);
        System.out.println(date);
    
        //指定时分秒
        LocalTime time = LocalTime.of(14, 20, 30);
        System.out.println(time);
    }
    

    输出结果

    2020-12-12T16:02:30.502
    2020-12-12
    16:02:30.502
    =========================================
    2048-11-25T12:00:30
    2020-12-12
    14:20:30
    

    常用方法

    与获取相关的方法(get系类的方法)

    • getYear():获取年
    • getHour():获取小时
    • getMinute():获取分钟
    • getSecond():获取秒值
    • getDayOfMonth():获得月份天数(1-31)
    • getDayOfYear():获得年份天数(1-366)
    • getDayOfWeek():获得星期几(返回一个 DayOfWeek枚举值)
    • getMonth():获得月份(返回一个 Month 枚举值)
    • getMonthValue():获得月份(1-12)
    • getYear():获得年份
    @Test
    public void test02() {
        //获取日期时分秒
        LocalDateTime now = LocalDateTime.now();
    
        //获取年份
        int year = now.getYear();
        System.out.println(year);
    
        //获取月份枚举
        //Month 枚举类,定义了十二个月份
        Month month = now.getMonth();
        System.out.println(month);
    
        //获取月份的数值
        int monthValue = now.getMonthValue();
        System.out.println(monthValue);
    
        //获取当天在本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        System.out.println(dayOfMonth);
    
        //获取小时
        int hour = now.getHour();
        System.out.println(hour);
    
        //获取分钟
        int minute = now.getMinute();
        System.out.println(minute);
    
        //获取秒值
        int second = now.getSecond();
        System.out.println(second);
    }
    

    输出结果

    2020
    DECEMBER
    12
    12
    16
    2
    48
    

    转换的方法

    • toLocalDate():将LocalDateTime转换为相应的LocalDate对象
    • toLocalTime():将LocalDateTime转换为相应的LocalTime对象
    @Test
    public void test04() {
        //获取当前年月日,时分秒
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
    
        //将LocalDateTime转换为相应的LocalDate对象
        LocalDate localDate = now.toLocalDate();
        System.out.println(localDate);
    
        //将LocalDateTime转换为相应的LocalTime对象
        LocalTime localTime = now.toLocalTime();
        System.out.println(localTime);
    }
    

    输出结果

    2020-12-12T16:07:23.045
    2020-12-12
    16:07:23.045
    

    判断的方法

    • isAfter():判断一个日期是否在指定日期之后
    • isBefore():判断一个日期是否在指定日期之前
    • isEqual():判断两个日期是否相同
    • isLeapYear():判断是否是闰年(注意是LocalDate类 和 LocalDateTime类特有的方法)
    @Test
    public void test05() {
        //获取当前的日期
        LocalDate now = LocalDate.now();
    
        //指定的日期
        LocalDate of = LocalDate.of(2015, 12, 12);
    
        //判断一个日期是否在另一个日期之前
        boolean before = of.isBefore(now);
        System.out.println(before);
    
        //判断一个日期是否在另一个日期之后
        boolean after = of.isAfter(now);
        System.out.println(after);
    
        //判断这两个日期是否相等
        boolean after1 = now.equals(of);
        System.out.println(after1);
    
        //判断闰年
        boolean leapYear = of.isLeapYear();
        System.out.println(leapYear);
    }
    

    输出结果

    true
    false
    false
    false
    

    增减年月日时分秒的方法(plus/minus系列的方法)

    增加相关的方法

    • plusYears(int offset):增加指定年份
    • plusMonths(int offset):增加指定月份
    • plusWeeks(int offset):增加指定周
    • plusDates(int offset):增加指定日
    • plusHours(int offset):增加指定时
    • plusMinuets(int offset):增加指定分
    • plusSeconds(int offset):增加指定秒
    • plusNanos(int offset):增加指定纳秒

    减少相关的方法

    • minusYears(int offset):减少指定年
    • minusMonths(int offset):减少指定月
    • minusWeeks(int offset):减少指定周
    • minusDates(int offset):减少指定日
    • minusHours(int offset):减少指定时
    • minusMinuets(int offset):减少指定分
    • minusSeconds(int offset):减少指定秒
    • minusNanos(int offset):减少指定纳秒
    @Test
    public void test07() {
        //增加时间量的方法 plusXXX系类的方法 返回的是一个新的日期对象
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        //可以给当前的日期增加时间量
        LocalDateTime newDate = now.plusYears(1);
        int year = newDate.getYear();
        System.out.println(year);
    
        System.out.println("================================");
        //减去时间量的方法minusXXX 系列的方法 返回的是一个新的日期对象
        LocalDate now1 = LocalDate.now();
        System.out.println(now1);
        LocalDate newDate2 = now1.minusDays(10);
        int dayOfMonth = newDate2.getDayOfMonth();
        System.out.println(dayOfMonth);
    }
    

    输出结果

    2020-12-12T16:12:43.228
    2021
    ================================
    2020-12-12
    2
    

    指定年月日时分秒的方法

    • with(TemporalAdjuster adjuster):指定特殊时间
    • withYear(int year):指定年
    • withDayOfYear(int dayOfYear):指定日
    • withMonth(int month):指定月
    • withDayOfMonth(int dayOfMonth):指定日
    @Test
    public void test08() {
        //指定某个日期的方法 with()方法
        LocalDate now2 = LocalDate.now();
        System.out.println(now2);
        LocalDate localDate = now2.withYear(2014);
        System.out.println(localDate);
    
        // TemporalAdjusters工具类,提供了一些获取特殊日期的方法
        LocalDate with = now2.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println(with);
        LocalDate with1 = now2.with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println(with1);
    
        //获取这个月的第几个星期几是几号,比如 TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.FRIDAY)
        // 代表的意思是这个月的第二个星期五是几号
        LocalDate with2 = now2.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.FRIDAY));
        System.out.println(with2);
    }
    

    输出结果

    2020-12-12
    2014-12-12
    2020-12-01
    2021-01-01
    2020-12-11
    

    将日期格式化为字符串的方法

    • format():格式化字符串
    @Test
    public void test03() {
        //获取当前日期时分秒
        LocalDateTime now = LocalDateTime.now();
    
        //默认格式  年-月-日T时:分:秒
        System.out.println(now);
    
        //指定格式
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        //传入格式
        String dateStr = now.format(ofPattern);
        System.out.println(dateStr);
    }
    

    输出结果

    2020-12-12T16:06:12.705
    2020年12月12日 16时06分12秒
    

    解析字符串为日期时间的方法

    • paser(String str):将一个日期字符串解析成日期对象,注意字符串日期的写法的格式要正确,否则解析失败
    • paser(String str, DateTimeFormatter formatter):将字符串按照参数传入的格式进行解析
    @Test
    public void test06() {
        //给出一个符合默认格式要求的日期字符串
        String dateStr = "2020-01-01";
    
        //把日期字符串解析成日期对象 如果日期字符串时年月日 解析时用  LocalDate
        LocalDate parse = LocalDate.parse(dateStr);
        System.out.println(parse);
    
        System.out.println("===========================================");
        //给出一个符合默认格式要求的 时分秒 字符串
        String dateTimeStr = "14:20:30";
    
        //把 时分秒 字符串解析成时分秒对象
        LocalTime parse1 = LocalTime.parse(dateTimeStr);
        System.out.println(parse1);
    
        System.out.println("=========================================");
        //给出一个符合默认格式要求的 日期时分秒 字符串
        String str = "2018-12-12T14:20:30";
    
        //把 日期时分秒 字符串解析成时分秒对象
        LocalDateTime parse2 = LocalDateTime.parse(str);
        System.out.println(parse2);
    
        System.out.println("========================================");
        //给出一个自定义日期时分秒格式字符串
        String dateStr2 = "2020年12月12日 12:13:14";
    
        //给出一个自定义解析格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    
        //按照指定的格式去解析
        LocalDateTime parse3 = LocalDateTime.parse(dateStr2, formatter);
        System.out.println(parse3);
    }
    

    输出结果

    2020-01-01
    ===========================================
    14:20:30
    =========================================
    2018-12-12T14:20:30
    ========================================
    2020-12-12T12:13:14
    

    TemporalAdjuster接口 - 时间调节器

    前面看到的所有日期操作都是相对比较直接的。有的时候,你需要进行一些更加灵活复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,就需要时间调节器 TemporalAdjuster,可以更加灵活地处理日期。TemporalAdjusters 工具提供了一些通用的功能,并且你还可以新增你自己的功能。

    @Test
    public void testTemporalAdjuster() {
        LocalDate now = LocalDate.now();
        //指定日期
        //对于一些特殊的日期,可以通过一个工具类TemporalAdjusters 来指定
        //见名知意,本月第一天
        TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstDayOfMonth();
        LocalDate with = now.with(temporalAdjuster);
        System.out.println(with);
        //下周周末
        TemporalAdjuster next = TemporalAdjusters.next(DayOfWeek.SUNDAY);
        LocalDate with1 = now.with(next);
        System.out.println(with1);
        System.out.println("===================================");
    
    
        LocalDate now1 = LocalDate.now();
        //自定义日期 - 下一个工作日
        LocalDate with2 = now1.with(new TemporalAdjuster() {
            @Override
            //参数 nowDate 当前的日期对象
            public Temporal adjustInto(Temporal nowDate) {
                //向下转型
                LocalDate date = (LocalDate) nowDate;
                if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
                    LocalDate localDate = date.plusDays(3);
                    return localDate;
                } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                    LocalDate localDate = date.plusDays(2);
                    return localDate;
                } else {
                    LocalDate localDate = date.plusDays(1);
                    return localDate;
                }
            }
        });
        System.out.println("下一个工作日是:" + with2);
    }
    

    输出结果

    2020-12-01
    2020-12-13
    ===================================
    下一个工作日是:2020-12-14
    

    Duration类 - 用于计算两个“时间”间隔的类

    Duration 表示一个时间段,Duration 包含两部分:seconds 表示秒,nanos 表示纳秒,它们的组合表达了时间长度。

    因为 Duration 表示时间段,所以 Duration 类中不包含 now() 静态方法。注意,Duration 不包含毫秒这个属性。

    Duration只能处理两个LocalTime, LocalDateTime, ZonedDateTime; 如果传入的是LocalDate,将会抛出异常

    常用API

    • 静态方法 between():计算两个时间的间隔,默认是
    • toDays():将时间转换为以天为单位的
    • toHours():将时间转换为以时为单位的
    • toMinutes():将时间转换为以分钟为单位的
    • toMillis():将时间转换为以毫秒为单位的
    • toNanos():将时间转换为以纳秒为单位的
    @Test
    public void test10() {
        //计算时间的间隔
        Instant start = Instant.now();
        for (int i = 0; i < 100000; i++) {
            // System.out.println(i);
        }
        Instant end = Instant.now();
        Duration duration = Duration.between(start, end);
        long l = duration.toNanos();
    
        //间隔的时间
        System.out.println("循环耗时:" + l + "纳秒");
    }
    

    输出结果

    循环耗时:1000000纳秒
    

    Period类 - 用于计算两个“日期”间隔的类

    Period 在概念上和 Duration 类似,区别在于 Period 是以年月日来衡量一个时间段。Duration 用于计算两个时间间隔,Period 用于计算两个日期间隔,所以 between() 方法只能接收 LocalDate 类型的参数。

    • 静态方法 between():计算两个日期之间的间隔
    • getYears():获取年份
    • getMonths():获取月份
    • getDays():获取天数
    @Test
    public void test11() {
        //计算两个日期的间隔
        LocalDate birthday = LocalDate.of(2012, 12, 12);
        LocalDate now = LocalDate.now();
    
        //我从出生到现在,有多少岁,零几个月,几天
        //计算两个日期的间隔
        Period between = Period.between(birthday, now);
        int years = between.getYears();
        int months = between.getMonths();
        int days = between.getDays();
        System.out.println("玛雅人的地球都消灭了" + years + "年" + months + "月" + days + "天了...");
    }
    

    输出结果

    玛雅人的地球都消灭了8年0月0天了...
    

    Instant 时间戳类

    java.time.Instant 时间线上的一个瞬时点,承载纳秒级精度的 Unix 时间戳,其 String toString() 方法基于 ISO-8601 进行格式化。Instant 不承载时区信息。

    获取对象的方法:now():注意默认获取出来的是默认时区,和我们相差八个小时(因为我们在东八时区

    设置偏移量的方法:atOffset()

    获取系统默认时区时间的方法:atZone():方法的参数是要一个时区的编号(可以通过时区编号类获取ZonedDateTime类的对象)

    get系列的方法

    • getEpochSecond():获取从1970-01-01 00:00:00当前时间秒值
    • toEpochMilli():获取从1970-01-01 00:00:00当前时间毫秒值
    • getNano():把获取到的当前时间的秒数 换算成纳秒

    ofEpoch系列方法

    • ofEpochSecond():给计算机元年增加秒数
    • ofEpochMilli():给计算机元年增加毫秒数
    @Test
    public void test09() {
        //  Instant 时间戳类从1970 -01 - 01 00:00:00 截止到当前时间的毫秒值
        Instant now = Instant.now();
        System.out.println(now); //获取的是默认时区,获取的不是中国 的时区
    
        //获取当前时区的,我们可以添加偏移量,返回偏移过后的日期
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);
        System.out.println("===========================");
    
        //从1970 - 01 - 01 00:00:00 截止到当前时间的毫秒值
        long l = System.currentTimeMillis();
        System.out.println(l);
        long time = new Date().getTime();
        System.out.println(time);
    
        //JDK1.8 Instant 时间戳类从1970 -01 - 01 00:00:00 截止到当前时间的毫秒值
        Instant now1 = Instant.now();
    
        //toEpochMilli():从1970 -01 - 01 00:00:00 截止到当前时间间隔的毫秒值
        long l1 = now1.toEpochMilli();
        System.out.println(l1);
    
        //获取从1970 -01 - 01 00:00:00 截止到当前时间间隔的秒值
        long epochSecond = now1.getEpochSecond();
        System.out.println(epochSecond);
    
        System.out.println("==========================");
        //给计算机元年增加相应的时间量
        Date date = new Date(1000 * 60 * 60 * 24);
        System.out.println(date);
    
        //现在 给计算机元年增加相应的时间量
        //5. ofEpochSecond() 方法 给计算机元年增加秒数
        //ofEpochMilli() 给计算机元年增加毫秒数
        Instant instant = Instant.ofEpochMilli(1000 * 60 * 60 * 24);
        System.out.println(instant);
    
        //ofEpochSecond() 方法 给计算机元年增加秒数
        Instant instant1 = Instant.ofEpochSecond(60 * 60 * 24);
        System.out.println(instant1);
    }
    

    输出结果

    2020-12-12T08:48:46.480Z
    2020-12-12T16:48:46.480+08:00
    ===========================
    1607762926539
    1607762926540
    1607762926540
    1607762926
    ==========================
    Fri Jan 02 08:00:00 CST 1970
    1970-01-02T00:00:00Z
    1970-01-02T00:00:00Z
    

    Clock - 时钟系统

    Clock 是时钟系统,用于查找当前时刻。你可以用它来获取某个时区下当前的日期或者时间。可以用 Clock 来替代旧的 System.currentTimeInMillis() 与 TimeZone.getDefault() 方法。

    @Test
    public void testClock() {
        //系统默认时间
        Clock clock = Clock.systemDefaultZone();
        System.out.println(clock.instant().toString());
    
        //世界协调时UTC
        Clock clock1 = Clock.systemUTC();
        //通过Clock获取当前时刻
        System.out.println("当前时刻为:" + clock1.instant());
        //获取clock对应的毫秒数,与System.currentTimeMillis()输出相同
        System.out.println(clock1.millis());
        System.out.println(System.currentTimeMillis());
        System.out.println(new Date(System.currentTimeMillis()).toString());
    
        //在clock基础上增加6000秒,返回新的Clock
        Clock clock2 = Clock.offset(clock1, Duration.ofSeconds(6000));
    
        //纽约时间
        Clock clock3 = Clock.system(ZoneId.of("America/New_York"));
        System.out.println("Current DateTime with NewYork clock: " + LocalDateTime.now(clock3));
        System.out.println(clock3.millis());
    }
    

    输出结果

    2020-12-12T09:05:07.025Z
    当前时刻为:2020-12-12T09:05:07.036Z
    1607763907036
    1607763907036
    Sat Dec 12 17:05:07 CST 2020
    Current DateTime with NewYork clock: 2020-12-12T04:05:07.040
    1607763907041
    

    ZonedDate、ZonedTime、ZonedDateTime - 带时区的日期时间

    这个三个类方法及用法和 LocalDate、 LocalTime、 LocalDateTime 基本一样,只不过ZonedDate、ZonedTime、ZonedDateTime 这三个带有特定时区

    ZoneId - 世界时区类

    Java 使用 ZoneId 来标识不同的时区。时区从基准 UTC 开始的一个固定偏移。ZoneId 的子类 ZoneOffset,代表了这种从伦敦格林威治零度子午线开始的时间偏移,也就是时差。

    常用API

    • getAvailableZoneIds():获取世界各个地方的时区的集合
    • systemDefault():获取系统默认时区的ID
    • of(String zoneName):根据各个地区的时区ID名创建对象
    @Test
    public void test13() {
        //ZoneID 世界时区类
        //获取世界各地的时区编号。
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for (String availableZoneId : availableZoneIds) {
            System.out.println(availableZoneId);
        }
    
        System.out.println("=====================");
        //获取系统的默认时区编号
        ZoneId zoneId = ZoneId.systemDefault();
        System.out.println(zoneId);
    
        //获取其他国家的日期
        LocalDateTime now = LocalDateTime.now();
        //获取指定时区的日期时间
        ZoneId zoneId1 = ZoneId.of("Europe/Monaco");
        ZonedDateTime zonedDateTime = now.atZone(zoneId1);  //获得指定时区的当前时间
        System.out.println(zonedDateTime);
    
        System.out.println("=====================");
        //根据时区,获取该地区的日期
        LocalDateTime now1 = LocalDateTime.now(ZoneId.of("America/Phoenix"));  //获得指定时区的当前时间(不带时区信息)
        System.out.println(now1);
    }
    

    输出结果

    America/Toronto
    Asia/Singapore
    Australia/Lindeman
    America/Los_Angeles
    SystemV/EST5EDT
    Pacific/Majuro
    America/Argentina/Buenos_Aires
    Europe/Nicosia
    Pacific/Guadalcanal
    Europe/Athens
    US/Pacific
    Europe/Monaco
    =====================
    Asia/Shanghai
    2020-12-12T20:56:27.214+01:00[Europe/Monaco]
    =====================
    2020-12-12T05:56:27.225
    

    DateTimeFormatter类 - 用于解析日期字符串和格式化日期输出

    DateTimeFormatter用于解析日期字符串和格式化日期输出,创建格式化器最简单的方法是通过 DateTimeFormatter 的静态工厂方法以及常量。

    在java8之前,我们进行时间格式化主要是使用SimpleDateFormat,而在java8中,主要是使用DateTimeFormatter,java8中,预定义了一些标准的时间格式,我们可以直接将时间转换为标准的时间格式

    常用API

    • ofPattern(“yyyy-MM-dd”):静态方法,通过给定格式获取对象
    • format():把一个日期对象的默认格式 格式化成指定的格式字符串
    @Test
    public void test12() {
        // 之前格式化日期的类  new SimpleDateFormat()
        //JDK1.8 DateTimeFormatter
        //指定格式 静态方法 ofPattern()
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // DateTimeFormatter 自带的格式方法
        LocalDateTime now = LocalDateTime.now();
    
        //把日期对象,格式化成字符串
        String format = formatter.format(now);
        //刚才的方式是使用的日期自带的格式化方法
        String format1 = now.format(formatter);
        System.out.println(format);
        System.out.println(format1);
    }
    

    输出结果

    2020-12-12 17:28:50
    2020-12-12 17:28:50
    

    格式化输出 & 字符串解析

    java.time.format.DateTimeFormatter 能够进行 TemporalAccessor 类型(包括:LocalDateLocalTimeLocalDateTimeZonedDateTime)的格式化输出。同时,LocalDateLocalTimeLocalDateTimeZonedDateTime 提供了静态的 parse 方法,能够进行字符串解析。

    LocalDateLocalTimeLocalDateTimeZonedDateTime 允许基于类型的默认格式进行格式化输出和字符串解析。

    类型默认格式示例
    Instant2017-11-23T10:15:30.00Z
    LocalDate2017-11-23
    LocalTime10:15:30
    LocalDateTime2017-11-23T10:15:30
    ZonedDateTime2017-11-23T10:15:30+01:00[Asia/Shanghai]

    使用SimpleDateFormat的正确姿势

    方法一:在需要执行格式化的地方都新建SimpleDateFormat实例,使用局部变量来存放SimpleDateFormat实例

    public static String formatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }
    

    这种方法可能会导致短期内创建大量的SimpleDateFormat实例,如解析一个excel表格里的字符串日期。

    方法二:为了避免创建大量的SimpleDateFormat实例,往往会考虑把SimpleDateFormat实例设为静态成员变量,共享SimpleDateFormat对象。这种情况下就得对SimpleDateFormat添加同步。

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    public static String formatDate(Date date) {
        synchronized (sdf) {
            return sdf.format(date);
        }
    }
    

    这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。

    方法三(推荐):要在高并发环境下能有比较好的体验,可以使用ThreadLocal来限制SimpleDateFormat只能在线程内共享,这样就避免了多线程导致的线程安全问题。

    private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };
    
    public static String formatDate(Date date) {
        return threadLocal.get().format(date);
    }
    

    Java8 日期时间类与Date类的相互转化

    在转换中,我们需要注意,因为java8之前Date是包含日期和时间的,而LocalDate只包含日期,LocalTime只包含时间,所以与Date在互转中,势必会丢失日期或者时间,或者会使用起始时间。如果转LocalDateTime,那么就不存在信息误差。

    Date和Instant互相转换

    @Test
    public void test18() {
        //Date与Instant互相转换
        Instant instant  = Instant.now();
        Date date = Date.from(instant);
        System.out.println(date);
    
        Instant instant2 = date.toInstant();
        System.out.println(instant2);
    }
    

    输出结果

    Sat Dec 12 21:18:13 CST 2020
    2020-12-12T13:18:13.129Z
    

    Date与LocalDateTime互相转换

    @Test
    public void test19() {
        //Date - LocalDateTime
        Date date = new Date();
        System.out.println("current date: " + date);
    
        LocalDateTime localDateTime1 = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        System.out.println("localDateTime1: " + localDateTime1);
    
        LocalDateTime localDateTime2 = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        System.out.println("localDateTime2: " + localDateTime2);
    
        //LocalDateTime - Date
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("localDateTime: " + localDateTime);
    
        Date date1 = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        System.out.println("date1: " + date1);
    }
    

    输出结果

    current date: Sat Dec 12 21:27:47 CST 2020
    localDateTime1: 2020-12-12T21:27:47.592
    localDateTime2: 2020-12-12T21:27:47.592
    localDateTime: 2020-12-12T21:27:47.652
    date1: Sat Dec 12 21:27:47 CST 2020
    

    Date与LocalDate互相转换

    @Test
    public void test20() {
        Date date = new Date();
        System.out.println("current date: " + date);
    
        // Date -LocalDate
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        System.out.println("localDate: " + localDate);
    
        // LocalDate -Date
        LocalDate localDate1 = LocalDate.now();
        //因为LocalDate不包含时间,所以转Date时,会默认转为当天的起始时间,00:00:00
        Instant instant = localDate1.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
        Date date1 = Date.from(instant);
        System.out.println("date1: " + date1);
    }
    

    输出结果

    current date: Sat Dec 12 21:37:51 CST 2020
    localDate: 2020-12-12
    date1: Sat Dec 12 00:00:00 CST 2020
    

    Date转换为LocalTime

    @Test
    public void test21() {
        Date date = new Date();
        System.out.println("current date: " + date);
    
        // Date - LocalTime
        LocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
        System.out.println("localTime: " + localTime);
    }
    

    输出结果

    current date: Sat Dec 12 21:40:47 CST 2020
    localTime: 21:40:47.596
    

    GregorianCalendar与ZonedDateTime相互转换

    @Test
    public void test22() {
        //GregorianCalendar与ZonedDateTime相互转换
        ZonedDateTime zonedDateTime = new GregorianCalendar().toZonedDateTime();
        System.out.println("zonedDateTime: " + zonedDateTime);
        GregorianCalendar calendar = GregorianCalendar.from(zonedDateTime);
        System.out.println("calendar: " + calendar.getTime());
    }
    

    输出结果

    zonedDateTime: 2020-12-12T21:55:08.286+08:00[Asia/Shanghai]
    calendar: Sat Dec 12 21:55:08 CST 2020
    

    Java 8日期时间类图

    img

    类图所示,java.time.temporal 提供的接口:

    1. TemporalField:日期与时间 “字段”,例如:2017-11-18 中的 18 “天”
    2. TemporalUnit:时间 “单位”,例如:1 年 13 天的 13 “天”
    3. TemporalAccessor:“时间相关” 对象的 “只读” 接口
    4. Temporal:“时间相关” 对象的 “读写” 接口,继承自 TemporalAccessor
    5. TemporalAdjusterTemporal 类型对象 “设置 & 调整” 的函数式接口
    6. TemporalAmount:时间段

    java.time 提供的类:

    1. InstantLocalDateLocalTimeLocalDateTimeZonedDateTime:实现 TemporalTemporalAdjuster 接口
    2. DurationPeriod:实现 TemporalAmount 接口

    Java 8时间日期 API 中的设计模式

    • 工厂模式:now()、of() 等工厂方法直接生成日期或者日期时间。

    • 策略模式:LocalDate/LocalTime/LocalDateTime/ZonedDateTime,针对日期、时间、日期和时间、带时区的日期时间,使用具体的时间日期类处理。策略模式在设计一整套东西时,对开发者特别友好。

      前面也提到,所有新的日期时间 API 类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分。一旦你使用了其中某个类的方法,那么非常容易上手其他类的使用。

    • 构建者模式:Java 8 开始在 Calendar 中加入了构建者类,可以按如下方式生成新的 Calendar 对象。

    这里设计模式与标准的教科书式的设计模式可能有所区别,所以我们在使用设计模式时也应灵活处理,不是一成不变的。

    Java 8的日期时间API总结

    前面详细介绍了Java 8的日期时间API,现在进行简单总结一下。

    新的时间与日期 API 中很重要的一点是,它定义清楚了基本的时间与日期的概念,比方说日期、时间、瞬时时间、持续时间、时区及时间段。它们都是基于 ISO8601 日历系统,它是世界民用历法,也就是我们所说的公历。

    java.time包下主要包含下面几个主要的类:

    • LocalDate:表示不带时间的日期,比如:2016-10-20
    • LocalTime:表示不带日期的时间,比如:23:12:10
    • LocalDateTime:日期时间,比如:2016-10-20 23:14:21
    • TemporalAdjuster : 时间调节器
    • TemporalAdjusters:获得指定日期时间等,如当月的第一天、今年的最后一天等
    • Duration:持续时间,计算两个“时间”的间隔
    • Period:日期间隔,计算两个“日期”的间隔
    • Instant:Unix 时间,它代表的是时间戳,比如 2018-01-14T02:20:13.592Z
    • Clock:时钟,获取某个时区下的瞬时时间
    • ZoneId:时区id,例如 Asia/Shanghai
    • ZonedDateTime:带时区的日期时间
    • DateTimeFormatter:时间格式化

    新的 API 区分各种日期时间概念并且各个概念使用相似的方法定义模式,这种相似性非常有利于 API 的学习。总结一下一般的方法规律:

    • of:静态工厂方法,用于创建实例
    • now:静态工厂方法,用当前时间创建实例
    • parse:静态工厂方法,从字符串解析得到对象实例
    • get:获取对象的部分状态
    • is:检查某些东西的是否是 true,例如比较时间前后
    • with:返回一个部分状态改变了的时间日期对象拷贝(单独一个with方法,参数为TemporalAdjusters类型)
    • plus:返回一个时间增加了的时间日期对象拷贝
    • minus:返回一个时间减少了的时间日期对象拷贝
    • to:把当前时间日期对象转换成另外一个,可能会损失部分状态。
    • at:把这个对象与另一个对象组合起来,例如:date.atTime(time)
    • format:将时间日期格式化为字符串

    最后再次声明,Java 8 中新的时间与日期 API 中的所有类都是不可变且线程安全的,任何修改操作都会返回一个新的实例,而之前 java.util.Date、Calendar 以及 SimpleDateFormat 这些关键的类都不是线程安全的。

    展开全文
  • 18个Java8日期处理.md

    2021-06-03 10:55:06
    关于Java8不同情况下日期的处理
  • 主要介绍了18个Java8日期处理的实践(太有用了),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • java8日期类详解

    2020-08-26 15:48:00
    掌握Java8中的提供的java.time包中的常用日期类与相关方法 可以从java.util包的下的日期类相关类过渡到java.time包下的日期类 掌握Java8中的日期与字符串之间的相互转换 为什么会出现新的日期类API ...

    学习目标

    1. 掌握Java8中的提供的java.time包中的常用日期类与相关方法

    2. 可以从java.util包的下的日期类相关类过渡到java.time包下的日期类

    3. 掌握Java8中的日期与字符串之间的相互转换


    为什么会出现新的日期类API

        将java.util.Date类束之高阁才是正确之道 -> Tim Yates
        在Java面世之初,标准库就引入了两种用于处理日期和时间的类,它们是 java.util.Date和java.util.Calendar,而前者堪称类糟糕设计的典范,浏览 API可以发现,从Java1.1开始,Date类中的所有方法就已经被弃用,Java1.1推荐采用Calendar类处理日期和时间,但是这个类同样存在不少问题.

    对于日期的计算困难问题.

            毫秒值与日期直接转换比较繁琐,其次通过毫秒值来计算时间的差额步骤较多.

    package com.itheima.time;
    import java.util.Calendar;
    import java.util.Date;
    /**
    * 计算当前时间距离2000年6月1日相差了多少天.
    *
    * 通过距离1970年1月1日的毫秒差值,可以计算出两个日期之间相隔的天数.
    */
    public class JavaUtilTimeDemo01 {
      public static void main(String[] args) {
        //1.初始化Date对象,无参构造(无参构造默认代表的就是当前时间)
        Date dateNow = new Date();
        //2.获取当前时间的距离1970年1月1日过了多少毫秒.
        long dateTimeNow = dateNow.getTime();
        //3.初始化Calendar对象并设时间为2006年6月1日并且将Calendar对象转换为Date对象.
        Calendar paramterTime = Calendar.getInstance();
        paramterTime.set(2000, Calendar.JUNE, 1);
        //线程安全问题
        //SimpleDateFormat类是线程不安全的,在多线程的情况下,全局共享一个
        //SimpleDateFormat类中的Calendar对象有可能会出现异常.
        Date paramterDateTime = paramterTime.getTime();
        //4.计算paramterDateTime与dateTimeNow之间的毫秒差额.
        Long intervalTime = dateTimeNow -
        paramterDateTime.getTime();
        //5.对intervalTime进行计算获取差额,毫秒值/1000->/60->/60->/24
        long intervalDay = intervalTime / 1000 / 60 / 60 / 24;
        System.out.println("当前时间距离2000年6月1日已经过了" + intervalDay+"天.");
     }
    }

    线程安全问题

      SimpleDateFormat类是线程不安全的,在多线程的情况下,全局共享一个
      SimpleDateFormat类中的Calendar对象有可能会出现异常.

    package com.itheima.time;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    public class JavaUtilTimeDemo02 {
      //创建SimpleDateFormat的对象(单例)
      static SimpleDateFormat SIMPLEDATEFORMAT = new
    SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      public static void main(String[] args) {
        //创建10个线程并启动.
        for (int i = 0; i < 10; i++) {
          new Thread(() -> {
            try {
            
               System.out.println(SIMPLEDATEFORMAT.parse("2018-12-12 12:12:12"));
           } catch (ParseException e) {
              e.printStackTrace();
           }
         }).start();
       }
     }
    }

            另外的一个问题就是在java.util.Date和java.util.Calendar类之前,枚举类型(ENUM)还没有出现,所以在字段中使用整数常量导致整数常量都是可变的,而不是线程安全的.为了处理实际开发中遇到的问题,标准库随后引入了java.sql.Date作为java.util.Date的子类,但是还是没能彻底解决问题.最终JavaSE 8中引入了java.time包,这种全新的包从根本上解决了长久以来的存在的诸多弊,java.time包基于Joda-Time库构件,是一种免费的开源解决方案,实际上在Java 8没有出现之前,公司中已经广泛使用Joda-Time来解决Java中的日期与时间问题,Joda-Time的设计团队也参与了java.time包的开发.


    Date-Time API中的基本类使用

     

    常用类的概述与功能介绍

    • Instant类

     Instant类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳,在之后学习的类型转换中,均可以使用Instant类作为中间类完成转换.

    • Duration类

    Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性.

    • Period类

    Period类表示一段时间的年、月、日.

    • LocalDate类

    LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日.

    • LocalTime类

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

    • LocalDateTime类

    LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年-月-日-时-分-秒.

    • ZonedDateTime类

    ZonedDateTime是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。

     

    now方法在日期/时间类的使用

             Date-Time API中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化.

             now方法可以根据当前日期或时间创建实例.

    package com.itheima.time;
    import java.time.*;
    
    public class Java8TimeClassMethodDemo1 {
      public static void main(String[] args) {
        //使用now方法创建Instant的实例对象.
        Instant instantNow = Instant.now();
        //使用now方法创建LocalDate的实例对象.
        LocalDate localDateNow = LocalDate.now();
        //使用now方法创建LocalTime的实例对象.
        LocalTime localTimeNow = LocalTime.now();
        //使用now方法创建LocalDateTime的实例对象.
        LocalDateTime localDateTimeNow = LocalDateTime.now();
        //使用now方法创建ZonedDateTime的实例对象.
        ZonedDateTime zonedDateTimeNow = ZonedDateTime.now();
        //将实例对象打印到控制台.
        System.out.println("Instant:"+instantNow);
        System.out.println("LocalDate:"+localDateNow);
        System.out.println("LocalTime:"+localTimeNow);
        System.out.println("LocalDateTime:"+localDateTimeNow);
        System.out.println("ZonedDateTime:"+zonedDateTimeNow);
     }
    }

    各个类封装时间所表示的特点

    • Instant封装的时间为祖鲁时间并非当前时间. 祖鲁时间也是格林尼治时间,也就是国际标准时间.
    • LocalDate封装的只有年月日,没有时分秒,格式为yyyy-MM-dd.
    • LocalTime封装的只有时分秒,没有年月日,格式为hh:mm:ss.sss,最后的sss是纳秒.
    • LocalDateTime将LocalDate和LocalTime合二为一,在年月日与时分秒中间使用T作为分隔.
    • ZonedDateTime中封装了年月日时分秒,以及UTC(祖鲁时间)偏移量,并且还有一个地区名.+8:00代表中国是东八区,时间比国际标准时间快八小时.

    Java8 年 月 日 的枚举信息.

    1. Year类(表示年)
    2. YearMonth类(表示年月)
    3. MonthDay类(表示月日)
    package com.itheima.time;
    
    import java.time.*;
    public class Java8TimeClassMethodDemo2 {
      public static void main(String[] args) {
        //初始化Year的实例化对象.
        Year year = Year.now();
        //初始化YearMonth的实例化对象
        YearMonth month = YearMonth.now();
        //初始化MonthDay的实例化对象.
        MonthDay day = MonthDay.now();
     }
    }

    of方法在日期/时间类的应用

         of方法可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有of方法用于生成的对应的对象,而且重载形式多变,可以根据不同的参数生成对应的数据.

    package com.itheima.time;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    public class Java8TimeClassMethodDemo3 {
      public static void main(String[] args) {
        //初始化2018年8月8日的LocalDate对象.
        LocalDate date = LocalDate.of(2018, 8, 8);
        System.out.println("LocalDate:" + date);
        /*
        初始化晚上7点0分0秒的LocalTime对象.
        LocalTime.of方法的重载形式有以下几种,可以根据实际情况自行使用.
        LocalTime of(int hour, int minute) -> 根据小时/分钟生成对象.
        LocalTime of(int hour, int minute, int second) -> 根据小时/分钟/秒生成对象.
        LocalTime of(int hour, int minute, int second, int nanoOfSecond) ->    根据小时/分钟/毫秒/纳秒生成对象.
        注意:如果秒和纳秒为0的话,那么默认不会封装这些数据,只显示小时和分钟.
        */
        LocalTime time = LocalTime.of(19, 0, 0, 0);
        System.out.println("LocalTime:" + time);
        /*
        初始化2018年8月8日下午7点0分的LocalDateTime对象.
        LocalDateTime.of方法的重载形式有以下几种,可以根据事情自行使用.
        LocalDateTime of(int year, int month, int dayOfMonth, int hour, int
    minute, int second, int nanoOfSecond) -> 根据年/月/日/时/分/秒生成对象.
        LocalDateTime of(int year, int month, int dayOfMonth, int hour, int
    minute) -> 根据年/月/日/时/分生成对象.
        注意:LocalDateTime of(LocalDate date, LocalTime time)方法可以将一个
    LocalDate对象和一个LocalTime对象合并封装为一个LocalDateTime对象.
        */
        LocalDateTime.of(2018, 8, 8, 19, 0, 0, 0);
        LocalDateTime localDateTime = LocalDateTime.of(date, time);
        System.out.println("LocalDateTime:" + localDateTime);
     }
    }

     

    为LocalDateTime添加时区信息(拓展)

           在学习ZonedDateTime的时候,发现了这个对象里面封装的不仅有时间日期,并且还有偏移量+时区,那么时区如何在Java中获取呢,通过提供的一个类ZoneId的getAvailableZoneIds方法可以获取到一个Set集合,集合中封装了600个时区.

    //获取所有的时区信息
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for (String zoneId : availableZoneIds) {
          System.out.println(zoneId);
       }

         同样也提供了获取当前系统默认的时区的方式systemDefault()方法.

    //获取当前系统默认的时区信息
        ZoneId zoneId = ZoneId.systemDefault();
        System.out.println(zoneId);

          我们可以通过给LocalDateTime添加时区信息来查看到不同时区的时间,比如说LocalDateTime中当前封装的是上海时间,那么想知道在此时此刻,纽约的时间是什么,就可以将纽约的时区Id添加进去,就可以查看到了,方式如下.

    1. 封装时间LocalDateTime并添加时区信息.
    2. 更改时区信息查看对应时间.
    package com.itheima.time;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    /**
    * 为LocalDateTime添加时区信息.
    */
    public class Java8TimeClassMethodDemo5 {
      public static void main(String[] args) {
        //1.封装LocalDateTime对象,参数自定义 -> 2018年11月11日 8点54分38秒
        LocalDateTime time = LocalDateTime.of(2018, 11, 11, 8, 54, 38);
        //2.封装完成后的time对象只是封装的是一个时间,并没有时区相关的数据,所以添加时区到对象中,使用atZone方法.
        ZonedDateTime zonedDateTime =time.atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println("Asia/Shanghai的时间是:" + zonedDateTime);
        //3.更改时区查看其它时区的当前时间,通过withZoneSameInstant方法即可更改.
        ZonedDateTime otherZonedTime =
        zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
        System.out.println("在同一时刻,Asia/Tokyo的时间是:" + otherZonedTime);
     }
    }

     

    Month枚举类的使用 

           java.time包中引入了Month的枚举,Month中包含标准日历中的12个月份的常量(从JANURAY到DECEMEBER)也提供了一些方便的方法供我们使用.推荐在初始化LocalDate和LocalDateTime对象的时候,月份的参数使用枚举的方式传入,这样更简单易懂而且不易出错,因为如果是老的思维,Calendar传入0的话,那么会出现异常.

    /**
    * Month枚举类的使用.
    */
    public class Java8TimeClassMethodDemo6 {
      public static void main(String[] args) {
        //在初始化LocalDate和LocalDateTime的时候,月份的参数传入枚举类(2011年5月15日11时11分11秒)
        LocalDateTime.of(2011, Month.JUNE,15,11,11,11);
        //of方法可以根据传入的数字返回对应的月份.
        Month month = Month.of(12);
        System.out.println(month);
       
     }
    }


     

    根据现有实例创建日期与时间对象

     

    plus方法在LocalDate与LocalTime中的使用     

           想要修改某个日期/时间对象的现有实例时,我们可以使用plus和minus方法来完成操作.Java8中日期时间相关的API中的所有实例都是不可改变的,一旦创建LocalDate,LocalTime,LocalDateTime就无法修改他们(类似于String),这对于线程安全非常有利.

     

    LocalDate中定义了多种对日期进行增减操作的方法

    • LocalDate plusDays(long days) 增加天数
    • LocalDate plusWeeks(long weeks) 增加周数
    • LocalDate plusMonths(long months) 增加月数
    • LocalDate plusYears(long years) 增加年数

    LocalTime中定义了多种对时间进行增减操作的方法

    • LocalTime plusNanos(long nanos) 增加纳秒
    • LocalTime plusSeconds(long seconds) 增加秒
    • LocalTime plusMinutes(long minutes) 增加分钟
    • LocalTime plusHours(long hours) 增加小时

     

    package com.itheima.time.plus;
    import org.junit.Test;
    import java.time.LocalDate;
    import java.time.Month;
    public class Java8TimeMethodPlusDemo1 {
      public static void main(String[] args) {
        //封装LocalDate对象参数为2016年2月13日.
        LocalDate date = LocalDate.of(2016, Month.FEBRUARY, 13);
        //计算当前时间的4天后的时间.
        LocalDate plusDaysTime = date.plusDays(4);
        //计算当前时间的周后的时间.
        LocalDate plusWeeksTime = date.plusWeeks(3);
        //计算当前时间的5个月后的时间.
        LocalDate plusMonthsTime = date.plusMonths(5);
        //计算当前时间的2年后的时间.
        LocalDate plusYearsTime = date.plusYears(2);
        System.out.println("当前的时间是:"+date);
        System.out.println("4天后的时间是:"+plusDaysTime);
        System.out.println("3周后的时间是:"+plusWeeksTime);
        System.out.println("5个月后的时间是:"+plusMonthsTime);
        System.out.println("2年后的时间是:"+plusYearsTime);
     }
    }
    

    package com.itheima.time.plus;
    import java.time.LocalTime;
    public class Java8TimeMethodPlusDemo2 {
      public static void main(String[] args) {
        //封装LocalTime对象参数为8时14分39秒218纳秒.
        LocalTime time = LocalTime.of(8, 14, 39, 218);
        //计算当前时间500纳秒后的时间.
        LocalTime plusNanosTime = time.plusNanos(500);
        //计算当前时间45秒后的时间.
        LocalTime plusSecondsTime = time.plusSeconds(45);
        //计算当前时间19分钟后的时间.
        LocalTime plusMinutesTime = time.plusMinutes(19);
        //计算当前时间3小时后的时间.
        LocalTime plusHoursTime = time.plusHours(3);
        System.out.println("当前的时间是:" + time);
        System.out.println("45秒后的时间是:" + plusSecondsTime);
        System.out.println("19分钟后的时间是:" + plusMinutesTime);
        System.out.println("500纳秒后的时间是:" + plusNanosTime);
        System.out.println("3小时后的时间是:" + plusHoursTime);
     }
    }

         本文中都是使用plusXXX的方法进行演示,实际上也有对应的减少方法,以minus开头的方法对应的即为减少,实际上minus方法调用的也是plus方法,只不过传入的参数是负数.

    plus和minus方法的应用

         刚才学习到的plusXXX相关的方法都是添加了数值到具体的某一项上,根据观察还有两个单独的plus方法,接下来我们来学习这两个单独的plus方法.

     

    plus(TemporaAmount amountToAdd)

          TemporaAmount是一个接口,当接口作为方法的参数的时候,实际上传入的是接口的实现类对象,根据查看这个接口的体系,可以看到这个接口有一个实现类,名字叫做Period,在学习第一节的时候,说明了这个类表示一段时间.

          如何使用Period来表示一段时间呢?这个类本身提供了of(int year,int month,intday)来表示,例: Period.of(1,2,3)返回的对象表示的即为1年2个月3天这么一个时间段,我们可以使用plus方法添加这个时间段.

    package com.itheima.time.plus;
    import java.time.LocalDate;
    import java.time.Period;
    /*
    今天程序员小郝在查看自己的车辆保险记录的时候查看到还有2年3个月零8天保险就到期了,
    计算2年3个月零8天后的时间是多少.
    */
    public class Java8TimeMethodPlusDemo4 {
      public static void main(String[] args) {
        LocalDate date = LocalDate.now(); //date表示当前时间.
        //固然可以使用对于年月日依次+2,+3,+8的方式来操作,但是有些繁琐,首先我们先将2年3月8天封装为一段时间,也就是封装为一个Period对象.
        Period time = Period.of(2, 3, 8);
        //使用plus方法对于date对象直接进行增加的操作.
        LocalDate endDate = date.plus(time);
        System.out.println("今天是" + date + ",保险到期的时间是" + endDate + ".");
     }
    }

     

    plus(long l,TemporaUnit unit)

          在实际开发过程中,可能还会更精准的去操作日期或者说增加一些特殊的时间,比如说1个世纪,1个半天,1千年,10年等,Java8提供了这些日期的表示方式而不需要去单独进行计算了.TemporaUnit是一个接口,通过查看体系接口发现,可以使用子类ChronoUnit来表示,ChronoUnit封装了很多时间段供我们使用.

    package com.itheima.time.plus;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.Month;
    import java.time.Period;
    import java.time.temporal.ChronoUnit;
    /*
    结婚10年称为锡婚,2020年2月2日11点11分11秒称为对称日,很多情侣准备在那天结婚,如果在那
    天结婚了,那么锡婚会发生在什么时候.
    */
    public class Java8TimeMethodPlusDemo5 {
      public static void main(String[] args) {
        LocalDateTime marryTime = LocalDateTime.of(2020,Month.FEBRUARY, 2, 11, 11, 11);
        //使用plus方法进行计算,添加1个,ChronoUnit.DECADES(十年).
        LocalDateTime time = marryTime.plus(1, ChronoUnit.DECADES);
        System.out.println("如果在" + marryTime + "结婚,那么锡婚是" + time);
        //如果锡婚后的半天准备要请所有亲戚朋友吃饭,那么吃饭的时间是.
        LocalDateTime eatTime = time.plus(1, ChronoUnit.HALF_DAYS);
        System.out.println("半天后吃饭,吃饭的时候是:" + eatTime);
     }
    }

    注意第一个参数为单位,第二个参数为时间长度.
    例:  plus(1, ChronoUnit.DECADES)加1个10年.    plus(1, ChronoUnit.CENTURIES)加1个100年.

     

    with方法在LocalDateTime类的应用

         如果不需要对日期进行加减而是要直接修改日期的话,那么可以使用with方法,with方法提供了很多种修改时间的方式.

    • LocalDateTime withNano(int i) 修改纳秒
    • LocalDateTime withSecond(int i) 修改秒
    • LocalDateTime withMinute(int i) 修改分钟
    • LocalDateTime withHour(int i) 修改小时
    • LocalDateTime withDayOfMonth(int i) 修改日
    • LocalDateTime withMonth(int i) 修改月
    • LocalDateTime withYear(int i) 修改年
    package com.itheima.time.with;
    import java.time.LocalDateTime;
    public class Java8TimeMethodWithDemo1 {
      public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.now();
        //经过使用发现time中的时间有错误,应该是1日,在不知道原有时间的基础上,无法进
        //行增减操作,所以可以直接使用with方法进行修改.
        LocalDateTime endTime = time.withDayOfMonth(1);
        System.out.println("修改前错误的时间是:" + time);
        System.out.println("修改完成之后的时间是:" + endTime);
     }
    }

    with(TemporalField field, long newValue)

           TemporalField是一个接口,通过查看体系结构,可以使用它的子类ChronoField,ChronoField中封装了一些日期时间中的组成部分,可以直接选择之后传入第二个参数进行修改.
    例:with(ChronoField.DAY_OF_MONTH,1); 将日期中的月份中的天数改为1.
    例:with(ChronoField.YEAR,2021); 将日期中的年份改为2021.

    package com.itheima.time.with;
    import java.time.LocalDateTime;
    import java.time.temporal.ChronoField;
    public class Java8TimeMethodWithDemo2 {
      public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.now();
        //经过使用发现time中的时间有错误,应该是1日,在不知道原有时间的基础上,
        //无法进行增减操作,所以可以直接使用with方法进行修改.
        LocalDateTime endTime =time.with(ChronoField.DAY_OF_MONTH,1);
        System.out.println("修改前错误的时间是:" + time);
        System.out.println("修改完成之后的时间是:" + endTime);
     }
    }

     

    调节器TemporalAdjuster与查询TemporalQuery

       

    TemporalAdjuster

          在上一节学习的with方法中学习了可以通过with方法修改日期时间对象中封装的数据,但是有一些时候可能会做一些复杂的操作,比如说将时间调整到下个周的周日,下一个工作日,或者本月中的某一天,这个时候可以使用调节器TemporalAdjuster来更方便的处理日期.

         with方法有一个重载形式,需要传入一个TemporalAdjuster对象,通过查看发现TemporalAdjuster是一个接口,方法的参数是一个接口,那么实际上传入的是这个接口的实现类对象.

     在以上的描述中,发现了一个叫做TemporalAdjusters的类可以给我们提供一些常用的方法,方法如下.

    • static TemporalAdjuster firsyDayOfNextMonth()  下个月的第一天
    • static TemporalAdjuster firstDayOfNextYear()  下一年的第一天
    • static TemporalAdjuster firstDayOfYear()  当年的第一天
    • static TemporaAdjuster firstInMonth(DayOfWeek dayOfWeek) 当月的第一个周x(通过参数确定)
    • static TemporaAdjuster lastDayOfMonth() 当月的最后一天
    • static TemporaAdjuster lastDayOfYear() 当年的最后一天
    • static TemporaAdjuste lastInMonth(DayOfWeek dayOfWeek) 当月的最后一个周x(通过参数确定)
    • static TemporaAdjuster next(DayOfWeek dayOfWeek) 下一个周x(通过参数确定)
    • static TemporaAdjuster previous(DayOfWeek dayOfWeek) 上一个周x(通过参数确定)

          TemporalAdjuster是一个函数式接口,里面有一个抽象方法叫做TemporaladjustInto(Temporal temporal);传入一个Temporal对象通过实现逻辑返回一个Temporal对象,Temporal是LocalDate,LocalTime相关日期类的父接口,实际上传入的就是一个时间日期对象返回一个时间日期对象.

    package com.itheima.time;
    import java.time.LocalDate;
    import java.time.Month;
    import java.time.temporal.TemporalAdjuster;
    import java.time.temporal.TemporalAdjusters;
    public class Java8TimeTemporalAdjusterDemo1 {
      public static void main(String[] args) {
        //封装日期时间对象为当前时间,LocalDate.
        LocalDate time = LocalDate.now();
        /*
        with方法可以修改time对象中封装的数据,需要传入一个TemporalAdjuster对象,
        通过查看发现TemporalAdjuster是一个接口,方法的参数是一个接口,那么实际上传入的是
        这个接口的实现类对象.
        TemporalAdjusters的类可以给我们提供一些常用的方法.
        */
        //with方法传入了TemporalAdjuster类的实现对象,是由TemporalAdjusters类的方
        //法实现了adjustInto方法,当前的逻辑是:将时间修改为当月的第一天.
        LocalDate firstDayOfMonth =time.with(TemporalAdjusters.firstDayOfMonth());
        //将时间修改为下个月的第一天.
        LocalDate firstDayOfNextMonth =time.with(TemporalAdjusters.firstDayOfNextMonth());
        //将时间修改为下一年的第一天.
        LocalDate firstDayOfNextYear =time.with(TemporalAdjusters.firstDayOfNextYear());
        //将时间修改为本年的第一天.
        LocalDate firstDayOfYear =time.with(TemporalAdjusters.firstDayOfYear());
        //将时间修改为本月的最后一天.
        LocalDate lastDayOfMonth =time.with(TemporalAdjusters.lastDayOfMonth());
        //将时间修改为本年的最后一天.
        LocalDate lastDayOfYear =time.with(TemporalAdjusters.lastDayOfYear());
        System.out.println("当月的第一天是:" + firstDayOfMonth);
        System.out.println("下个月的第一天是:" + firstDayOfNextMonth);
        System.out.println("下一年的第一天是:" + firstDayOfNextYear);
        System.out.println("本年的第一天是:" + firstDayOfYear);
        System.out.println("本月的最后一天是:" + lastDayOfMonth);
        System.out.println("本年的最后一天是:" + lastDayOfYear);
     }
    }

     

    DayOfWeek的使用

          DayOfWeek是一周中星期几的枚举类,其中封装了从周一到周日.

    package com.itheima.time;
    import java.time.DayOfWeek;
    import java.time.LocalDate;
    import java.time.temporal.TemporalAdjusters;
    public class Java8TimeTemporalAdjusterDemo2 {
      public static void main(String[] args) {
        //封装日期时间对象为当前时间,LocalDate.
        LocalDate time = LocalDate.now();
        /*
        DayOfWeek是一周中星期几的枚举类,其中封装了从周一到周日.
        */
        //将当前时间修改为下一个周日
        LocalDate nextSunday =time.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        //将当前时间修改为上一个周三
        LocalDate previousWednesday =time.with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));
        System.out.println("下一个周日是:"+nextSunday);
        System.out.println("上一个周三是:"+previousWednesday);
     }
    }

     

    自定义TemporalAdjuster调节器


     通过Java8本身提供的TemporalAdjusters中的方法可以完成一些常用的操作,如果要自定义日期时间的更改逻辑,可以通过实现TemporalAdjuster类接口中的方式来完成.

    • 创建类实现TemporalAdjuster接口
    • 实现TemporalAdjuster中的adjustInto方法,传入一个日期时间对象,完成逻辑之后返回日期时间对象.
    • 通过with方法传入自定义调节器对象完成更改.

    例:假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周末,则调整为周五.

    package com.itheima.time.impl;
    import java.time.DayOfWeek;
    import java.time.LocalDate;
    import java.time.temporal.*;
    /**
    * 假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周末,则调整为周五.
    */
    public class PayDayAdjuster implements TemporalAdjuster {
      @Override
      public Temporal adjustInto(Temporal temporal) {
        //1.将temporal转换为子类对象LocalDate,from方法可以将任何时态对象转换为LocalDate.
        LocalDate payDay = LocalDate.from(temporal);
        //2.判断当前封装的时间中的日期是不是当月15日,如果不是,则更改为15日.
        int day;
        if (payDay.getDayOfMonth() != 15) {
          day = 15;
       } else {
          day = payDay.getDayOfMonth();
       }
       LocalDate realPayDay = payDay.withDayOfMonth(day);
       //3.判断realPayDay对象中封装的星期数是不是周六或者是周日,如果是周末或者是周日则更改为周五.
       if (realPayDay.getDayOfWeek() == DayOfWeek.SUNDAY || realPayDay.getDayOfWeek() == DayOfWeek.SATURDAY) {
          //说明发薪日是周末,则更改为周五.
          realPayDay =     realPayDay.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
       }
       return realPayDay;
    }
    
    }
    package com.itheima.time;
    import com.itheima.time.impl.PayDayAdjuster;
    import java.time.DayOfWeek;
    import java.time.LocalDate;
    import java.time.temporal.TemporalAdjusters;
    public class Java8TimeTemporalAdjusterTest1 {
      public static void main(String[] args) {
        //封装LocalDate对象为2018年12月1日.
        LocalDate payDay = LocalDate.of(2019, 12, 1);
        //2018年12月15日为周末,所以要提前到周五发放工资,通过自定义调节器完成对时间的修改.
        LocalDate realPayDay = LocalDate.from(new PayDayAdjuster().adjustInto(payDay));
        System.out.println("预计的发薪日是2018年12月15日,实际的发薪日为:" + realPayDay);
     }
    }

     

    TemporalQuery的应用

          学习的时态类对象(LocalDate,LocalTime)都有一个方法叫做query,可以针对日期进行查询.R query(TemporalQuery query)这个方法是一个泛型方法,返回的数据就是传入的泛型类的类型,TemporalQuery是一个泛型接口,里面有一个抽象方法是 R queryFrom(TemporalAccessor temporal),TemporalAccessor是Temporal的父接口,实际上也就是LocalDate,LocalDateTime相关类的顶级父接口,这个queryFrom的方法的实现逻辑就是,传入一个日期/时间对象通过自定义逻辑返回数据.

    如果要计划日期距离某一个特定天数差距多少天,可以自定义类实现TemporalQuery接口并且作为参数传入到query方法中.
    例:计算当前时间距离下一个劳动节还有多少天?

    package com.itheima.time.impl;
    import java.time.LocalDate;
    import java.time.Month;
    import java.time.temporal.ChronoField;
    import java.time.temporal.ChronoUnit;
    import java.time.temporal.TemporalAccessor;
    import java.time.temporal.TemporalQuery;
    /**
    * 获取某一天距离下一个劳动节的相隔天数的实现类.
    */
    public class UntilDayQueryImpl implements TemporalQuery<Long> {
      @Override
      public Long queryFrom(TemporalAccessor temporal) {
        //获取当前的年/月/日信息.
        int year = temporal.get(ChronoField.YEAR);
        int month = temporal.get(ChronoField.MONTH_OF_YEAR);
        int day = temporal.get(ChronoField.DAY_OF_MONTH);
        //将获取到的数据封装为一个LocalDate对象.
        LocalDate time = LocalDate.of(year, month, day);
        //封装劳动节的时间,年参数传递year,month和day是5和1.
        LocalDate laborDay = LocalDate.of(year, Month.MAY,1);
        //判断当前时间是否已经超过了当年的劳动节,如果超过了,则laborDay+1年.
        if (time.isAfter(laborDay)){
          laborDay = laborDay.plusYears(1);
       }
        //通过ChronoUnit的between方法计算两个时间点的差额.
        long l = ChronoUnit.DAYS.between(time, laborDay);
        return l;
     }
    }
    
    
    
    package com.itheima.time;
    import com.itheima.time.impl.UntilDayQueryImpl;
    import java.time.LocalDate;
    public class Java8TimeTemporalQueryDemo1 {
      public static void main(String[] args) {
        //封装LocalDate对象为当前时间.
        LocalDate time = LocalDate.now();
        //调用time对象的query方法查询距离下一个五一劳动节还有多少天.
        Long l = time.query(new UntilDayQueryImpl());
        System.out.println("距离下一个五一劳动节还有:" + l + "天.");
     }
    }


     

    java.util.Date与java.time.LocalDate的转换

          Java8中的java.time包中并没有提供太多的内置方式来转换java.util包中用预处理标准日期和时间的类,我们可以使用Instant类作为中介,也可以使用java.sql.Date和java.sql.Timestamp类提供的方法进行转换.

     

    java.util.Date转换为java.time.LocalDate

          java.time包中并没有提供很多的方式来进行直接转换,但是给之前的Date类,Calendar类在Java1.8都提供了一个新的方法,叫做toInstant,可以将当前对象转换为Instant对象,通过给Instant添加时区信息之后就可以转换为LocalDate对象.

    package com.itheima.time.convert;
    import java.time.Instant;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.Date;
    public class Java8TimeDateToLocalDateDemo1 {
      public static void main(String[] args) {
        //初始化Date对象.
        Date d = new Date();
        //将Date类对象转换为Instant类对象.
        Instant i = d.toInstant();
        //Date类包含日期和时间信息,但是并不提供时区信息,和Instant类一样,可以通过
        //Instant类的atZone方法添加时区信息之后进行转换.
        ZonedDateTime zonedDateTime = i.atZone(ZoneId.systemDefault());
        //将ZonedDateTime通过toLocalDate方法转换为LocalDate对象.
        LocalDate localDate = zonedDateTime.toLocalDate();
        System.out.println("转换之前的Date对象是:" + d);
        System.out.println("转换之后的LocalDate对象是:" + localDate);
     }
    }

    java.sql.Date类中的转换方法使用

         java.sql.Date类中提供直接转换为LocalDate的方法,toLocalDate

    package com.itheima.time.convert;
    import java.time.*;
    import java.sql.Date;
    public class Java8TimeDateToLocalDateDemo2 {
      public static void main(String[] args) {
        //初始化java.sql.Date对象.
        Date d = new Date(System.currentTimeMillis());
        //将java.sql.Date对象通过toLocalDate方法转换为LocalDate对象.
        LocalDate localDate = d.toLocalDate();
        System.out.println("转换前的java.sql.Date对象是:" + d);
        System.out.println("转换后的LocalDate对象是:" + localDate);
     }
    }

    java.sql.Timestamp类中的转换方法使用

          TimeStamp是时间戳对象,通过传入一个毫秒值对象进行初始化.

    package com.itheima.time.convert;
    import java.sql.Date;
    import java.sql.Time;
    import java.sql.Timestamp;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    public class Java8TimeDateToLocalDateDemo3 {
      public static void main(String[] args) {
        //初始化java.sql.Timestamp对象.
        Timestamp t = new Timestamp(System.currentTimeMillis());
        //将java.sql.Timestamp对象通过toLocalDateTime方法转换为LocalDateTime对象.
        LocalDateTime localDateTime = t.toLocalDateTime();
        System.out.println("转换之前的Timestamp对象是:" + t);
        System.out.println("转换之后的LocalDateTime对象是:" + localDateTime);
     }
    }

     

    将java.util包中的类转换为java.time包中的相应类

        通过编写转换工具类达到传入Date对象直接进行转换的转换或者将新的日期时间类转换为Date对象

    package com.itheima.time.convert;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.Date;
    /**
    * 编写工具类传入不同的对象可以转换为对应的对象.
    */
    public class Java8TimeConvertTool {
    
    
      /**
      * 将java.sql.Date转换为LocalDate
      *
      * @param date
      * @return
      */
      public static LocalDate convertFromSqlDateToLocalDate(java.sql.Date date) {
         return date.toLocalDate();
      }
    
    
      /**
      * 将LocalDate转换为java.sql.Date
      * @param date
      * @return
      */
      public static java.sql.Date convertFromLocalDateToSqlDate(LocalDate date) {
         return java.sql.Date.valueOf(date);
      }
    
    
      /**
      * 将java.util.Date转换为LocalDate
      * @param date
      * @return
      */
      public static LocalDate convertFromUtilDateToLocalDate(java.util.Date date) {
         return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
      }
    
    
      /**
      * 将java.sql.Timestamp转换为LocalDateTime
      * @param timestamp
      * @return
      */
      public static LocalDateTime convertFromTimestampToLocalDateTime(java.sql.Timestamp timestamp) {
         return timestamp.toLocalDateTime();
      }
    
    
      /**
      * 将LocalDateTime转换为java.sql.Timestamp
      * @param localDateTime
      * @return
      */
      public static java.sql.Timestamp convertFromLocalDateTimeToTimestamp(LocalDateTime localDateTime) {
        return java.sql.Timestamp.valueOf(localDateTime);
      }
    
    
      /**
      * 将LocalDate转换为java.util.Date
      * @param date
      * @return
      */
      public static java.util.Date convertFromLocalDateToUtilDate(LocalDate date){
        ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
     }
    
    }

     

    将java.util.Date类转换为java.time.LocalDate类的第二种方法

    • java.sql.Date类提供了转换为LocalDate的方法,那么可以将java.util.Date先转换为java.sql.Date.
    • 通过java.sql.Date的构造方法直接传入一个毫秒值可以构造一个java.sql.Date对象,毫秒值可以通过java.util.Date对象的getTime方法获取到.
    package com.itheima.time.convert;
    import java.time.Instant;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.Date;
    public class Java8TimeDateToLocalDateDemo4 {
      public static void main(String[] args) {
        //初始化Date对象.
        Date d = new Date();
        //java.sql.Date类提供了转换为LocalDate的方法,那么可以将java.util.Date先转换为 
        //java.sql.Date.通过java.sql.Date的构造方法直接传入一个毫秒值可以构造一个java.sql.Date 
        //对象,毫秒值可以通过java.util.Date对象的getTime方法获取到.
        java.sql.Date date = new java.sql.Date(d.getTime());
        //将java.sql.Date转化为LocalDate.
        LocalDate localDate = date.toLocalDate();
        System.out.println("转换前的java.util.Date类对象是:" + d);
        System.out.println("转换后的LocalDate类对象是:" + localDate);
     }
    }

     

    将java.util.Calendar类转换为java.time.ZonedDateTime类

            Calendar对象自Java1.1开始提供了一个方法获取时区对象的方法,getTimeZone,要将Calendar对象转换为ZonedDateTime需要先获取到时区对象.从Java1.8开始TimeZone类提供了一个方法可以获取到ZonedId.获取到zoneId之后就可以初始化ZonedDateTime对象了,ZonedDateTime类有一个ofInstant方法,可以将一个Instant对象和ZonedId对象作为参数传入构造一个ZonedDateTime对象.

    package com.itheima.time.convert;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.TimeZone;
    public class Java8TimeCalendarToLocalDateDemo1 {
      public static void main(String[] args) {
        //初始化Canlendar对象.
        Calendar cal = Calendar.getInstance();
        //Calendar对象自Java1.1开始提供了一个方法获取时区对象的方法,getTimeZone,要将
        Calendar对象转换为ZonedDateTime需要先获取到时区对象.
        TimeZone timeZone = cal.getTimeZone();
        //从Java1.8开始TimeZone类提供了一个方法可以获取到ZonedId.
        ZoneId zoneId = timeZone.toZoneId();
        //获取到zoneId之后就可以初始化ZonedDateTime对象了,ZonedDateTime类有一个ofInstant方法,可 
        //以将一个Instant对象和ZonedId对象作为参数传入构造一个ZonedDateTime对象.
        ZonedDateTime zonedDateTime =ZonedDateTime.ofInstant(cal.toInstant(), zoneId);
        System.out.println("转换前的Calendar对象是:" + cal);
        System.out.println("转换后的ZonedDateTime对象是:" + zonedDateTime);
     }
    }

     

    将java.util.Calendar类转换为java.time.LocalDateTime类

          Calendar对象可以获取到年月日时分秒的信息,这些信息可以作为LocalDateTime构造方法的参数.

    package com.itheima.time.convert;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.Calendar;
    import java.util.TimeZone;
    public class Java8TimeCalendarToLocalDateTimeDemo1 {
      public static void main(String[] args) {
        //初始化Canlendar对象.
        Calendar cal = Calendar.getInstance();
        //通过Getter方法获取到Calendar对象中封装的数据.
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        //将以上获取到的数据作为LocalDateTime的of方法的参数进行对象的封装.
        LocalDateTime localDateTime = LocalDateTime.of(year, month + 1, day,hour, minute, second);
        System.out.println("转换前的Calendar对象是:" + cal);
        System.out.println("转换后的LocalDateTime对象是:" + localDateTime);
     }
    }

    注意:Calendar获取到的月份依旧是从0开始的,需要在原有的基础上+1,如果不加1,轻则月份少算了1个月,重则出现异常


     

     

    日期的解析与格式化DateTimeFormatter

    • SimpleDateFormat类在刚开始的讲过了是线程不安全的,所以Java8提供了新的格式化类 DateTimeFormatter.
    • DateTimeFormatter类提供了大量预定义格式化器,包括常量(如ISO_LOCAL_DATE),模式字母(如yyyy-MM-dd)以及本地化样式.
    • 与SimpleDateFormat不同的是,新版本的日期/时间API的格式化与解析不需要在创建转换器对象再进行转换了,通过时间日期对象的parse/format方法可以直接进行转换.

    LocalDate类定义的parse和format方法

          format方法需要传入一个DateTimeFormatter对象,实际上查看DateTimeFormatter类之后,指定DateTimeFormatter中的常量即可指定格式化方法,常用的格式化方式有ISO_DATE_TIME/ISO_DATE.

    package com.itheima.time;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    public class Java8TimeFormatAndParseDemo1 {
      public static void main(String[] args) {
        //对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.
        LocalDateTime time = LocalDateTime.now();
        //DateTimeFormatter类中定义了很多方式,通过常量名可以指定格式化方式.
        String result = time.format(DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("ISO_DATE_TIME格式化之后的String是:" + result);
        String result1 = time.format(DateTimeFormatter.ISO_DATE);
        System.out.println("ISO_DATE格式化之后的String是:" + result1);
        //解析字符串的方式通过LocalDateTime类的静态方法parse方法传入需要解析的字符串即可.
        LocalDateTime localDateTime = LocalDateTime.parse(result);
        System.out.println("解析了字符串之后的LocalDateTime是:" + localDateTime);
     }
    }

     

    对日期进行格式化 

          通过DateTimeFormatter的ofLocalizedDate的方法也可以调整格式化的方式.

    此方法需要传入一个FormatStyle类对象,查看后发现FormatStyle对象是一个枚举类,其中有几种方式如下.

    • Full:全显示(年月日+星期)
    • Long:全显示(年月日)
    • Medium:缩略显示(没有年月日汉字)
    • SHORT:精简显示(精简年+月日)
    package com.itheima.time;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.FormatStyle;
    public class Java8TimeFormatAndParseDemo2 {
      public static void main(String[] args) {
        //对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.
        LocalDateTime time = LocalDateTime.now();
        //通过DateTimeFormatter的ofLocalizedDate指定解析格式也可以格式化日期
        String r1 =time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
        String r2 =time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
        String r3 =time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
        String r4 =time.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
        System.out.println("FULL:"+r1);
        System.out.println("LONG:"+r2);
        System.out.println("MEDIUM:"+r3);
        System.out.println("SHORT:"+r4);
     }
    }

    注意:此种方式在不同时区的显示方式不一样,在其他时区不会显示中文,会根据当前系统的默认时区来进行区别显示.

     

    自定义格式化格式   

         除了系统的自带的方式之外,也可以通过DateTimeFormatter类提供的ofPattern方式创建自定时格式化器,格式化的写法与之前使用的SimpleDateFormat相同.

    package com.itheima.time;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.FormatStyle;
    public class Java8TimeFormatAndParseDemo3 {
      public static void main(String[] args) {
        //对LocalDateTime进行格式化与解析,初始化LocalDateTime对象.
        LocalDateTime time = LocalDateTime.now();
        //通过通过DateTimeFormatter的ofPattern方法可以自定义格式化模式.
        String result = time.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss:SSS"));
        System.out.println("LocalDateTime格式化前是:" + time);
        System.out.println("LocalDateTime格式化后是:" + result);
     }
    }

     



    配套视频: https://www.bilibili.com/video/BV1aZ4y1j78G?p=1

    配套文档:https://download.csdn.net/download/Dug_Zhang/12754601

     

     

    百度云:

    完整视频:http://yun.itheima.com/course/658.html?2008zzp
    配套资料:https://pan.baidu.com/s/1p0AGD3Vw0P6ac90FjmxbpA 提取码:ed1l

     

     

    展开全文
  • Java8日期时间API作业 Java8日期时间API的课后作业 根据说明分别实现 根据MeetingSystemV3的说明在脑洞会议系统v2.0的基础上实现新增需求
  • Java8日期格式化

    2020-08-24 15:26:48
    Java8日期格式化 1.日期类型的字符串转换成其他形式 public class test2 { public static String formattedDate(String input, String inputFormat, String outputFormat) { DateTimeFormatter inputFormatter = ...

    Java8日期格式化

    1.日期类型的字符串转换成其他形式

    public class test2 {
        public static String formattedDate(String input, String inputFormat, String outputFormat) {
            DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputFormat);
            LocalDate localDate = LocalDate.parse(input, inputFormatter);
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat);
            return localDate.format(outputFormatter);
        }
    
        public static void main(String[] args) {
            String date1 = formattedDate("2020年08月24日", "yyyy年MM月dd日", "yyyy-MM-dd");
            String date2 = formattedDate("2020/08/24", "yyyy/MM/dd", "yyyy-MM-dd");
            String date3 = formattedDate("2020-08-24", "yyyy-MM-dd", "yyyy/MM/dd");
            String date4 = formattedDate("2020-08-24", "yyyy-MM-dd", "yyyy年MM月dd日");
            System.out.println("data1:" + date1);
            System.out.println("data2:" + date2);
            System.out.println("data3:" + date3);
            System.out.println("data4:" + date4);
        }
    }
    

    测试结果:
    在这里插入图片描述
    2.带时分秒的日期类型的字符串转换成其他形式

    public class test1 {
        public static String formattedDateTime(String input, String inputFormat, String outputFormat) {
            DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputFormat);
            LocalDateTime localDateTime = LocalDateTime.parse(input, inputFormatter);
    
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputFormat);
            return localDateTime.format(outputFormatter);
        }
    
        public static void main(String[] args) {
            String date1 = formattedDateTime("20200824000000", "yyyyMMddHHmmss", "yyyy-MM-dd");
            String date2 = formattedDateTime("20200824000000", "yyyyMMddHHmmss", "yyyy-MM-dd HH:mm:ss");
    
            String date3 = formattedDateTime("2020年08月24日12时00分55秒", "yyyy年MM月dd日HH时mm分ss秒", "yyyy/MM/dd");
            String date4 = formattedDateTime("2020年08月24日12时01分48秒", "yyyy年MM月dd日HH时mm分ss秒", "yyyyMMddHHmmss");
    
            String date5 = formattedDateTime("2020-08-24 13:14:00", "yyyy-MM-dd HH:mm:ss", "yyyyMMdd");
            String date6 = formattedDateTime("2020-08-24 13:14:00", "yyyy-MM-dd HH:mm:ss", "yyyy年MM月dd日HH时mm分ss");
            System.out.println("date1:" + date1);
            System.out.println("date2:" + date2);
            System.out.println("date3:" + date3);
            System.out.println("date4:" + date4);
            System.out.println("date5:" + date5);
            System.out.println("date6:" + date6);
        }
    }
    

    测试结果:
    在这里插入图片描述
    原文链接

    展开全文
  • java8日期相关类

    2018-11-30 11:55:59
    TimeUnit、Instant、LocalDate 、LocalDateTime、Duration.between、DateTimeFormatter、firstDayOfMonth()、after、before等日期处理
  • java8日期

    千次阅读 2018-12-20 10:50:42
    java8的日期处理 优势: java.util.Date 和 SimpleDateFormatter 都不是线程安全的,而 LocalDate 和 LocalTime 和最基本的 String 一样,是不变类型,不但线程安全,而且不能修改。 java.util.Date 月份从0开始,一月...
  • @Test public void DateTimeFormatter_test() { //LocalDateTime ==> String DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime dateTime = LocalDateTime...
  • Java8日期计算:获取两个日期之间的所有日期 现在有个需求–求出两个日期之间的所有日期,包括起止日期,那么我们用Java8的LocalDate怎么方便简单的计算呢? 其实很简单,求出两个日期之间的绝对天数差,用结束时间...
  • 史上最全Java8日期时间工具类

    万次阅读 多人点赞 2020-12-13 14:52:18
    这是我总结的Java8日期工具类,应该是比较全面的,满足日常开发绝大部分需求,分享给大家,有错误之处,还望大神指教。 /** * Java8日期时间工具类 * * @author JourWon * @date 2020/12/13 */ public class ...
  • 死磕18个Java8日期处理,工作必用!

    千次阅读 2021-03-16 20:40:19
    原标题:死磕18个Java8日期处理,工作必用!链接:http://suo.im/5RJhaUJava 8 推出了全新的日期时间API,在教程中我们将通过一些简单的实例来学习如何使用新API。Java处理日期、日历和时间的方式一直为社区所诟病,...
  • 在本篇文章中小编给大家整理了关于java8、jdk8日期转化成字符串的相关知识点和代码,需要的朋友们学习下。
  • java8日期时间格式总结

    千次阅读 2019-07-04 19:17:02
    传统的java日期时间格式和Java8的日期时间格式最大的不同就是现成安全 public class TestDate { public static void main(String[] args) throws Exception{ SimpleDateFormat sdf = new SimpleDateFormat(...
  • Java8日期类型常见用法总结

    千次阅读 2018-12-13 10:05:03
    Java8新引入了一些日期、时间对象,这些对象与老的日期时间对象的使用上存在很大的不同,刚开始会很不习惯,但经过初步的使用后一定会更习惯使用这些新的API的,它使得对日期时间对象的操作上不会再如老的使用方式...
  • Java8日期和时间段的计算

    千次阅读 2020-02-25 16:50:30
    Java8之前,计算日期相差多少天一般的做法都是借助SimpleDateFormat对两个日期格式化之后在进行比较。在编写代码的过程中,计算一个方法具体耗时多少分钟,执行了多少秒等需求,一般也是借助System....
  • java8日期格式化-时间自动补零

    千次阅读 2021-04-12 11:22:48
    java8时间自动补零 从Java 8开始,java.time包提供了新的日期和时间API,以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。 DateTimeFormatter和LocalDateTime DateTimeFormatter和...
  • Java提供了Instant用来标识时间戳,可以很方便的获取到当前的时间戳,也就是从1970-01-01 00:00:00开始到当前时间所经过的秒数 Instant.now() 静态方法获取包含了当前时间戳的Instant实例对象 // 获取当前的时间的...
  • JAVA8日期转换、拼接时间

    千次阅读 2020-05-28 11:00:31
    final String date =LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM"))//转换为年月格式 final StringJoiner ...//拼接"月-" String endTime = sj + " 23:59:59"; System.out.println(endTime);
  • Java8日期及时间处理工具

    千次阅读 2019-06-11 16:31:11
    Java8日期及时间处理工具

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,795
精华内容 17,518
关键字:

java8日期