java8日期转时间戳_Java 8日期和时间
java8日期轉(zhuǎn)時(shí)間戳
如今,一些應(yīng)用程序仍在使用java.util.Date和java.util.Calendar API,包括使我們的生活更輕松地使用這些類型的庫(kù),例如JodaTime。 但是,Java 8引入了新的API來(lái)處理日期和時(shí)間,這使我們可以對(duì)日期和時(shí)間表示進(jìn)行更精細(xì)的控制,為我們提供不可變的datetime對(duì)象,更流暢的API以及在大多數(shù)情況下提高性能,而無(wú)需使用其他庫(kù)。 讓我們看一下基礎(chǔ)知識(shí)。
LocalDate / LocalTime / LocalDateTime
讓我們開始與最相關(guān)的新API的java.util.Date : LocalDate ,日期的API,表示沒(méi)有時(shí)間的日期; LocalTime ,不帶日期的時(shí)間表示; 和LocalDateTime ,這是前兩個(gè)的組合。 所有這些類型都代表一個(gè)區(qū)域的本地日期和/或時(shí)間,但是,就像java.util.Date一樣,它們包含零表示該區(qū)域的信息,僅表示當(dāng)前日期和時(shí)間。時(shí)區(qū)。
首先,這些API支持簡(jiǎn)單的實(shí)例化:
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");在它們之間進(jìn)行轉(zhuǎn)換很容易:
// 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`方法以及一些實(shí)用程序功能,對(duì)我們的日期和時(shí)間表示進(jìn)行操作非常容易:
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());現(xiàn)在我們?nèi)绾螐膉ava.util.Date移到LocalDateTime及其變體? 好吧,這很簡(jiǎn)單:我們可以將Date類型轉(zhuǎn)換為Instant類型,該類型表示從1970年1月1日開始的時(shí)間,然后我們可以使用Instant和當(dāng)前區(qū)域?qū)嵗疞ocalDateTime 。
LocalDateTime dateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());要轉(zhuǎn)換回日期,我們可以簡(jiǎn)單地使用Java 8時(shí)間類型表示的Instant。 但是要注意的一件事是,盡管LocalDate , LocalTime和LocalDateTime不包含任何Zone或Offset信息,但它們確實(shí)表示特定區(qū)域中的本地日期和/或時(shí)間,因此它們確實(shí)保留了當(dāng)前的偏移量。在那個(gè)地區(qū)。 因此,我們需要提供一個(gè)偏移量以將特定類型正確轉(zhuǎn)換為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)));時(shí)間差異–持續(xù)時(shí)間和期間
您已經(jīng)注意到,在以上示例之一中,我們使用了Duration對(duì)象。 Duration和Period是兩個(gè)日期之間時(shí)間的兩種表示形式,前者表示以秒和納秒為單位的時(shí)間差,后者以天,月和年表示。
什么時(shí)候應(yīng)該使用這些? Period ,當(dāng)你需要知道兩者之間的時(shí)間差LocalDate陳述:
Period period = Period.between(LocalDate.parse("2018-01-18"), LocalDate.parse("2018-02-14"));您在尋找具有時(shí)間信息的表示形式之間的差異時(shí)的Duration時(shí)間:
Duration duration = Duration.between(LocalDateTime.parse("2018-01-18T06:30"), LocalDateTime.parse("2018-02-14T22:58"));使用toString()輸出Period或Duration ,將基于ISO-8601標(biāo)準(zhǔn)使用特殊格式。 周期使用的模式是PnYnMnD,其中n定義周期內(nèi)存在的年,月或日的數(shù)量。 這意味著P1Y2M3D定義為1年2個(gè)月3天。 。 模式中的“ P”是時(shí)段指示符,它告訴我們以下格式表示一個(gè)時(shí)段。 使用該模式,我們還可以使用parse()方法基于字符串創(chuàng)建句點(diǎn)。
// represents a period of 27 days Period period = Period.parse("P27D");使用Durations ,由于Java 8不使用相同的模式,因此我們稍微偏離了ISO-8601標(biāo)準(zhǔn)。 ISO-8601定義的模式是PnYnMnDTnHnMn.nS。 這基本上是“ Period模式,帶有時(shí)間表示形式。 在模式中,T是時(shí)間標(biāo)記,因此后面的部分定義了以小時(shí),分鐘和秒為單位的持續(xù)時(shí)間。
Java的8個(gè)使用兩種特定模式的Duration ,解析字符串,一當(dāng)就是PnDTnHnMn.nS Duration ,以及調(diào)用時(shí)PTnHnMn.nS toString()上的一個(gè)方法Duration實(shí)例。
最后但并非最不重要的一點(diǎn)是,我們還可以通過(guò)使用類型上的相應(yīng)方法來(lái)檢索時(shí)間段或持續(xù)時(shí)間的各個(gè)部分。 但是,重要的是要知道各種日期時(shí)間類型也通過(guò)使用ChronoUnit枚舉類型來(lái)支持此功能。 讓我們看一些例子:
// 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);使用區(qū)域和偏移量– ZonedDateTime和OffsetDateTime
到目前為止,我們已經(jīng)展示了新的日期API如何使某些事情變得容易一些。 但是,真正與眾不同的是在時(shí)區(qū)上下文中輕松使用日期和時(shí)間的能力。 Java 8為我們提供了ZonedDateTime和OffsetDateTime ,第一個(gè)是LocalDateTime其中包含特定區(qū)域(例如,歐洲/巴黎)的信息,第二個(gè)是帶有偏移量的LocalDateTime 。 有什么不同? OffsetDateTime使用UTC /格林威治標(biāo)準(zhǔn)時(shí)間與指定日期之間的固定時(shí)差,而ZonedDateTime指定表示時(shí)間的區(qū)域,并將考慮夏時(shí)制。
轉(zhuǎn)換為以下兩種類型都很容易:
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]");在它們之間進(jìn)行切換時(shí),必須記住,從ZonedDateTime轉(zhuǎn)換為OffsetDateTime將考慮夏時(shí)制,而在另一個(gè)方向上從OffsetDateTime至ZonedDateTime意味著您將沒(méi)有有關(guān)區(qū)域區(qū)域的信息,也不會(huì)對(duì)夏時(shí)制應(yīng)用任何規(guī)則。 這是因?yàn)槠屏课炊x任何時(shí)區(qū)規(guī)則,也未綁定到特定區(qū)域。
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();現(xiàn)在,如果我們想知道特定時(shí)區(qū)或偏移時(shí)間在我們自己的時(shí)區(qū)中怎么辦? 嗯,為此還定義了一些方便的功能!
// 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 ) );如果我們不得不一直在這些類型之間手動(dòng)進(jìn)行轉(zhuǎn)換以獲取我們需要的類型,那將是一件麻煩事。 這就是Spring框架為我們提供幫助的地方。 Spring為我們提供了許多現(xiàn)成的日期時(shí)間轉(zhuǎn)換器,這些日期時(shí)間轉(zhuǎn)換器已在ConversionRegistry中注冊(cè),可以在org.springframework.format.datetime.standard.DateTimeConverters類中找到。
使用這些轉(zhuǎn)換器時(shí),重要的是要知道它不會(huì)轉(zhuǎn)換區(qū)域或偏移量之間的時(shí)間。 該ZonedDateTimeToLocalDateTimeConverter ,例如,將返回LocalDateTime因?yàn)樗窃?#xff0c;而不是指定的區(qū)域LocalDateTime ,它會(huì)在你的應(yīng)用程序的區(qū)域代表。
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);最后但并非最不重要的一點(diǎn)是,您可以查詢ZoneId.getAvailableZoneIds()來(lái)查找所有可用時(shí)區(qū),或使用地圖ZoneId.SHORT_IDS ,其中包含一些時(shí)區(qū)的縮寫版本,例如EST,CST等。
格式化–使用
當(dāng)然,世界各地都使用不同的格式來(lái)指定時(shí)間。 一個(gè)應(yīng)用程序可能使用MM-dd-yyyy,而另一個(gè)應(yīng)用程序使用dd / MM / yyyy。 一些應(yīng)用程序希望消除所有混淆,并用yyyy-MM-dd表示其日期。 使用java.util.Date ,我們將快速轉(zhuǎn)向使用多個(gè)格式化程序。 但是, DateTimeFormatter類為我們提供了可選的模式,因此我們可以將單個(gè)格式化程序用于多種格式! 讓我們來(lái)看一些例子。
// 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);模式中的方括號(hào)定義了模式中的可選部分。 通過(guò)使我們的各種格式成為可選,與字符串匹配的第一個(gè)模式將用于轉(zhuǎn)換我們的日期表示形式。 當(dāng)您使用多種模式時(shí),這可能很難理解,因此讓我們看一下使用構(gòu)建器模式創(chuàng)建DateTimeFormatter方法。
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendOptional( DateTimeFormatter.ofPattern( "yyyy-MM-dd" ) ).optionalStart().appendPattern( "dd/MM/yyyy" ).optionalEnd().optionalStart().appendPattern( "MM-dd-yyyy" ).optionalEnd().toFormatter();這些是包含多個(gè)模式的基礎(chǔ),但是如果我們的模式僅稍有不同,該怎么辦? 讓我們看一下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 );但是,在轉(zhuǎn)換為字符串時(shí),不應(yīng)使用支持多種格式的格式化程序,因?yàn)楫?dāng)我們使用格式化程序?qū)⑷掌诟袷交癁樽址硎拘问綍r(shí),它還將使用可選模式。
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世紀(jì),因此顯然我們必須考慮全球化,并且我們希望為用戶提供本地化日期。 為確保您的DateTimeFormatter返回特定的語(yǔ)言環(huán)境,您只需執(zhí)行以下操作:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEEE, MMM dd, yyyy" ).withLocale(Locale.UK);DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MMM-dd" ).toFormatter(Locale.UK);要查找可用的語(yǔ)言環(huán)境,可以使用Locale.getAvailableLocales() 。
現(xiàn)在可能是您收到的日期格式比您使用的類型包含更多的信息。 一旦提供的日期表示形式與該模式不一致,則DateTimeFormatter將引發(fā)異常。 讓我們仔細(xì)研究這個(gè)問(wèn)題以及如何解決它。
// 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);讓我們創(chuàng)建一個(gè)可以處理ISO日期,時(shí)間和日期時(shí)間模式的格式化程序。
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendOptional( DateTimeFormatter.ISO_LOCAL_DATE ).optionalStart().appendLiteral( "T" ).optionalEnd().appendOptional( DateTimeFormatter.ISO_LOCAL_TIME ).toFormatter();現(xiàn)在,我們可以完美地執(zhí)行以下所有操作:
// 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 );現(xiàn)在,下一期是哪里來(lái)的? 如果您嘗試解析LocalDateTime的日期模式怎么辦? 如果您希望使用LocalTime并得到日期表示,反之亦然怎么辦?
// will throw an exception LocalDateTime localDateTime = LocalDateTime.parse("2018-03-16", formatter); LocalDate localDate = LocalDate.parse("06:30", formatter);對(duì)于這后兩種情況,沒(méi)有一個(gè)正確的解決方案,但這取決于您的要求,或者這些日期和時(shí)間代表或可能代表什么。 使用TemporalQuery可以找到魔術(shù),您可以使用它為模式的一部分創(chuàng)建默認(rèn)值。
如果我們以LocalDateTime開頭,而您只需要LocalDate或LocalTime ,則將收到LocalDateTime的相應(yīng)部分。 要?jiǎng)?chuàng)建LocalDateTime ,我們需要其保存的日期和時(shí)間的默認(rèn)值。 假設(shè)如果您不提供有關(guān)日期的信息,我們將返回今天的日期,如果您不提供時(shí)間,則將假設(shè)您的意思是一天的開始。
由于我們將返回LocalDateTime ,因此不會(huì)將其解析為L(zhǎng)ocalDate或LocalTime ,因此讓我們使用ConversionService來(lái)獲取正確的類型。
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 ,我們可以檢查存在的信息,并為缺少的任何信息提供默認(rèn)值,從而使我們能夠使用應(yīng)用程序中有意義的邏輯輕松地轉(zhuǎn)換為所需的類型。
要了解如何編寫有效的時(shí)間模式,請(qǐng)查看DateTimeFormatter文檔 。
結(jié)論
大多數(shù)新功能需要一些時(shí)間來(lái)理解和習(xí)慣,Java 8 Date / Time API也不例外。 新的API使我們能夠更好地訪問(wèn)必要的正確格式,以及使用日期時(shí)間操作的更加標(biāo)準(zhǔn)化和易讀的方式。 使用這些提示和技巧,我們幾乎可以涵蓋所有用例。
翻譯自: https://www.javacodegeeks.com/2018/03/java-8-date-and-time.html
java8日期轉(zhuǎn)時(shí)間戳
總結(jié)
以上是生活随笔為你收集整理的java8日期转时间戳_Java 8日期和时间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何创建网站的快捷方式(如何创建网站)
- 下一篇: spock测试_使用Spock测试您的代