日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 8 日期和时间解读

發布時間:2023/12/3 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 8 日期和时间解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自?Java 8 日期和時間解讀

????????現在,一些應用程序仍然在使用java.util.Date和java.util.Calendar API和它們的類庫,來使我們在生活中更加輕松的處理日期和時間,比如:JodaTime。然而,Java 8 引進的新的類庫來處理日期和時間,這可以使我們更加精細的控制時間的表示,可以管理不可變的時間對象,同時,不需要使用其它的類庫,更加流暢的API在大多數情況下對性能也有很大的提升。下面我們來了解一下Java 8 日期和時間的一些基礎知識:

LocalDate/LocalTime/LocalDateTime

????????讓我們從與 java.util.Date最相關的新的API開始: LocalDate:表示日期,不表示時間。 LocalTime:表示時間,不表示日期。 LocalDateTime:上面兩者的組合。 所有的這些日期和時間表示類型,都表示某個區域的日期或者時間。但是,就像java.util.Date中的零區域信息一樣,只是表示當前區域的日期和時間。

????首先這些API支持一個簡單的實例:

LocalDate date = LocalDate.of(2018,2,13); // Uses DateTimeformatter.ISOLOCALDATE 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();

????????除此之外,使用“加”“減”法來進行我們的日期和時間操作,像其它公用功能一樣,簡單的難以置信:?

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呢?它們又有哪些不同?好吧,這很簡單:我們可以把一個時間類型轉換為一個實例類型,這是從1970年1月1日開始的,然后,我們可以在當前區域使用這個實例來實例化一個LocalDateTime。

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

????????為了轉換日期,我們可以簡單的使用java8時間類型的實例。需要注意的一點是,雖然LocalDate,LocalTime和LocalDateTime不包含任何區域和偏移信息,它們代表了一個特定區域的日期和/或時間,同樣的,它們帶有該區域的偏移。因此,為了正確的將特定類型轉換為實例,我們需要提供一個偏移。

// 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對象。Duration和Period是兩個日期之間時間的兩種表示方法,前者用秒和納秒來區分時間,后者使用年月日。

????????它們應該在哪些情況下使用呢?如果你需要知道兩個LocalDate表示的時間之間日期段的時候,你可以選擇使用Period:

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()方法輸出Period和Duration的時候,將會用到基于ISO-8601標準的一種特定格式。Period的模式是PnYnMnD,日期中n定義了當前的年月日。P1Y2D3意思就是1年2個月3天。模式中的‘P’表示日期標識符,它告訴我們接下來的格式表示的是日期。使用這種模式我們同樣可以創建一個基于使用parse()方法的string的日期。

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

????????使用Duration的時候,我們稍微偏離了ISO-8601標準,因為Java8不使用同樣的模式。ISO-8601定義的模式是PnYnMnDTnHnMn.nS,它是建立在Period的模式基礎上并對其進行了拓展的一種時間表示。在這個模式中,T是時間標識符,所以,它后面定義的是時分秒。

????????Java8中,Duration使用了兩種模式,當把一個String解析為一個Duration的時候使用PnDTnHnMn.nS模式,當在一個Duration實例中調用toString方法的時候,使用PTnHnMn.nS模式。

????????最后同樣重要的是,我們可以使用相應的方法類型來檢索一個時期或者時間中的任何一部分。各種類型的日期時間通過使用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);

時區時間和偏移時間

????????到目前為止,我們已經展示了新日期時間API如何使事情變的更加簡單。但是,真正不同的是在時區環境下更加簡單的使用日期和時間。Java8為我們提供了ZonedDateTime和OffsetDateTime,前者是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]");

????????當在它們之間轉換的時候,你必須要記住把ZoneDateTime轉換為OffsetDateTime的時候,需要考慮到夏令時,反而言之,當把OffsetDateTime轉換為ZonedDateTime的時候,意味著你將不會獲得區域的信息,也不適用夏令時的規則。應為偏移沒有定義任何時區規則,也不會綁定到任何區域。

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 Framework給我們提供了幫助。Spring為我們提供了一些開箱即用的日期時間轉換器,這些轉換器注冊在ConversionRegistry,在org.springframework.format.datetime.standard.DateTimeConverters類中可以找到。

????這使用這些轉換器的時候,重要的是要知道在區域和偏移之間是不會轉換的。比如說,ZonedDateTimeToLocalDateTimeConverter將會返回它所指定的區域的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);

????最后重要的是,你可以檢索ZonId.getAvailableZoneIds()來查找所有可用的時區,或者使用ZoneId.SHORT_IDS,它包含了一些簡寫版本的時區,例如:EST,CST等等。

格式化—使用DateTimeFormatter

????????當然,世界上不同的區域使用不同的格式來指定時間。一個應用程序可能使用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);

????????方括號中的內容定義了模式中的可操作部分,通過使我們的各種格式可選,匹配string的第一個模式將會被用來轉換我們表示的日期。當我們使用混合模式的時候,閱讀起來將會非常困難,所以,讓我們使用builder模式來創建我們的DateTimeFormatter。

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

????????這些是包含多種模式的基礎知識,但是,如果我們的模式僅僅是略有不同該怎么辦呢?讓我們來看一下yyy-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 );

????????但是,當轉換為String的時候,不可以使用支持多種格式的格式化器,因為當我們使用格式化器把我們的日期轉換為string表示的時候,它也將使用可選模式。

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的使用中找到,你也可以使用TemporalQuery為模式的一部分來創建缺省值。

????????如果我們開始使用的是LocalDateTime,但是你只是想要一個LocalTime或者是一個LocalTime,你將會接受到LocalDateTime的對應部分。為了創建一個LocalDateTime,我們需要它所持有的日期和時間的默認值。日入說,如果你沒有提供日期的信息,我們將會得到一個當前日期的返回值,如果你沒有提供時間信息,我么會認為這是一天的起始。

????????由于我們正在返回一個LocalDateTime,它不會被解析為一個LocalDate或者是LocalTime,所以,讓我們使用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> {@Overridepublic 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我們可以檢查哪些信息是當前的,并且可以為許多丟失的信息提供缺省值,這使我們可以很簡單的在我們的應用程序中使用合理的邏輯轉換為我們所需要的類型。

結論

大多數新功能都需要時間來理解和習慣,Java8 Date/Time API也不例外。新的API為我們提供了訪問所需要的更好的正確格式,為我們提供了使用日期時間操作的更加標準、更具可讀性的方式。使用這些技巧和竅門,我們幾乎可以涵蓋我們所有的用例。


總結

以上是生活随笔為你收集整理的Java 8 日期和时间解读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。