自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java時(shí)間操作類庫-Joda-Time

開發(fā) 前端
上一周在做一個(gè)產(chǎn)品的需求的時(shí)候有個(gè)動(dòng)態(tài)計(jì)算時(shí)間段(如現(xiàn)在是13:00,則時(shí)間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發(fā)時(shí)間為當(dāng)前時(shí)間+參數(shù)【2h10min】,最遲的時(shí)間段為開始時(shí)間在20點(diǎn)前結(jié)束時(shí)間在20點(diǎn)后的時(shí)間段),期間大量使用到了日期時(shí)間類庫,本著熟悉日期時(shí)間類庫才有了這篇文章,文章最后我會(huì)把我如何實(shí)現(xiàn)的這個(gè)需求的一個(gè)算法貼出來。

 前言

上一周在做一個(gè)產(chǎn)品的需求的時(shí)候有個(gè)動(dòng)態(tài)計(jì)算時(shí)間段(如現(xiàn)在是13:00,則時(shí)間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發(fā)時(shí)間為當(dāng)前時(shí)間+參數(shù)【2h10min】,最遲的時(shí)間段為開始時(shí)間在20點(diǎn)前結(jié)束時(shí)間在20點(diǎn)后的時(shí)間段),期間大量使用到了日期時(shí)間類庫,本著熟悉日期時(shí)間類庫才有了這篇文章,文章最后我會(huì)把我如何實(shí)現(xiàn)的這個(gè)需求的一個(gè)算法貼出來。

一、JDK8以前版本中的時(shí)間類庫

1.1 原始時(shí)間類庫存在的缺陷與不足

我們?cè)谑褂肑ava8之前的類庫時(shí),都會(huì)在處理日期-時(shí)間的時(shí)候總是不爽,這其中包括且不限于以下的槽點(diǎn):

在Java 1.0版本中,對(duì)時(shí)間、日期的操作完全依賴于 java.util.Data 類,只能以毫秒的精度表示時(shí)間,無法表示日期。

  • 在易用性方面有著很大的缺陷,年份的起始時(shí)間選擇是1900年,月份是從0開始。
  • toString 方法返回值不直觀,帶有時(shí)區(qū)。

在Java1.1 版本中,廢棄了很多Date 類中的很多方法,并且新增了 java.util.Calendar。但是與Date相同,Calendar 類也有類似的問題和設(shè)計(jì)缺陷,導(dǎo)致在使用這些類寫出的代碼也很容易出錯(cuò)。

  • 月份依然是從0開始計(jì)算。
  • 常用的日期、時(shí)間操作需要同時(shí)使用Date、Canendar、SimpleDateFormat,比較繁瑣。
  • 部分特性只存在于某一個(gè)類(解析和格式化日期或時(shí)間的DateFormat方法只存在于Date類中)。
  • DateFormat 不是線程安全的,如果兩個(gè)線程嘗試使用同一個(gè)formatter 解析日期,可能會(huì)得到無法預(yù)期的結(jié)果。
  • Date 和 Canendar 都是可變的。

1.2 關(guān)于SimpleDateFormat 線程不安全的原因

由于 parse 方法使用的貢獻(xiàn)變量 calendar 不是線程安全的。在 format (subFormat) 方法中進(jìn)行了 calendar 的賦值,在 parse 進(jìn)行了值得處理,因此在并發(fā)的情況下會(huì)造成 calendar 清理不及時(shí),值被覆蓋的情況。

  1. /** 
  2.  * The {@link Calendar} instance used for calculating the date-time fields 
  3.  * and the instant of time. This field is used for both formatting and 
  4.  * parsing. 
  5.  *   
  6.  * <p>Subclasses should initialize this field to a {@link Calendar} 
  7.  * appropriate for the {@link Locale} associated with this 
  8.  * <code>DateFormat</code>. 
  9.  * @serial 
  10.  */ 
  11. protected Calendar calendar; 
  12.  
  13. @Override 
  14. public StringBuffer format(Date date, StringBuffer toAppendTo, 
  15.                            FieldPosition pos){ 
  16.     pos.beginIndex = pos.endIndex = 0; 
  17.     return format(date, toAppendTo, pos.getFieldDelegate()); 
  18.  
  19. // Called from Format after creating a FieldDelegate 
  20. private StringBuffer format(Date date, StringBuffer toAppendTo, 
  21.                             FieldDelegate delegate) { 
  22.     // Convert input date to time field list 
  23.     calendar.setTime(date); 
  24.  
  25.  // At this point the fields of Calendar have been set.  Calendar 
  26.  // will fill in default values for missing fields when the time 
  27.  // is computed. 
  28.  
  29.  pos.index = start; 
  30.  
  31.  Date parsedDate; 
  32.  try { 
  33.         parsedDate = calb.establish(calendar).getTime(); 
  34.         // If the year value is ambiguous, 
  35.         // then the two-digit year == the default start year 
  36.         if (ambiguousYear[0]) { 
  37.             if (parsedDate.before(defaultCenturyStart)) { 
  38.                 parsedDate = calb.addYear(100).establish(calendar).getTime(); 
  39.             } 
  40.         } 
  41.  } 

 1.3 如何解決上述線程不安全問題?

  1. 使用ThreadLocal 為每個(gè)線程都創(chuàng)建一個(gè)線程獨(dú)享 SimpleDateFormat 變量;
  2. 需要的時(shí)候創(chuàng)建局部變量;
  3. 使用 org.apacle.commons.lang3.time.DateFormatUtils
  4. 使用Joda-Time (后面介紹)

二、Joda-Time 日期時(shí)間類庫

2.1 簡介

Joda-Time 是Joda提供的一個(gè)遵循Apache2.0 開源協(xié)議的 JDK以外的優(yōu)質(zhì)日期和時(shí)間開發(fā)庫。

  1. Joda除Joda-Time之外的項(xiàng)目有Joda-Money、Joda-Beans、Joda-Convert、Joda-Collect Joda官網(wǎng) 

2.1.1 為什么使用Joda-Time

  1. 使用方便:Calendar 訪問“正常的”日期困難,并且缺乏簡單的防腐,Joda-Time 擁有簡單的字段訪問,比如獲得年的 getYear() 和 獲得星期 中的天 getDayOfWeek() 。
  2. 易于擴(kuò)展:JDK支持通過使用子類實(shí)現(xiàn)多個(gè)日歷系統(tǒng),但是這是非常笨重的,并且在實(shí)現(xiàn)中很難選出另一個(gè)日歷系統(tǒng)。Joda-Time 支持基于 Chronology 類實(shí)現(xiàn)多個(gè)可插拔的日歷系統(tǒng)。
  3. 功能全面:Joda-Time 提供了所有的日期和時(shí)間計(jì)算的必須功能,它提供了即裝即用的特性。
  4. 最新的時(shí)區(qū)計(jì)算:時(shí)區(qū)的實(shí)現(xiàn)基于公共時(shí)區(qū)信息數(shù)據(jù)庫,每年更新數(shù)次。新版本的Joda-Time 包括了這個(gè)數(shù)據(jù)庫的所有更改,應(yīng)盡早進(jìn)行必要的更新,手動(dòng)更新區(qū)域數(shù)據(jù)很容易。
  5. 日歷支持:提供了8種日歷系統(tǒng)。
  6. 互通性:內(nèi)部使用毫秒進(jìn)行標(biāo)識(shí),這與JDK或者其他公共的時(shí)間表示相一致。
  7. 性能良好:支持針對(duì)所有訪問的域進(jìn)行最小的計(jì)算。
  8. 良好的測試覆蓋率:有全方位的測試人員保證庫的質(zhì)量、
  9. 具有完整文檔:有一個(gè)完整的用戶指南,該指南提供了一個(gè)概述,涵蓋常見的使用場景。javadoc 非常詳細(xì),涵蓋API的其余部分。
  10. 發(fā)展:自2002年以來積極發(fā)展,是一個(gè)成熟的可靠的代碼庫,一些相關(guān)的項(xiàng)目目前也是可用的。
  11. 開源:遵循Apache 2.0開源協(xié)議發(fā)布。

2.1.2 Joda-Time 的關(guān)鍵優(yōu)點(diǎn)

  1. LocalDate:只包含日期
  2. LocalTime:只包含時(shí)間
  3. Instant:時(shí)間軸上的時(shí)間點(diǎn)
  4. DateTime:時(shí)區(qū)中完整的日期和時(shí)間
  5. DateTimeZone:更好的時(shí)區(qū)
  6. Duration和Period:持續(xù)時(shí)間
  7. Interval:兩個(gè)時(shí)間點(diǎn)之間的時(shí)間
  8. 全面并且靈活的時(shí)間格式化與轉(zhuǎn)換

正因?yàn)镴oda-Time 與 Java8 之前的時(shí)間類庫相比,具備了如此多的優(yōu)點(diǎn),所以 Joda-Time 成為事實(shí)上的標(biāo)準(zhǔn)的Java日期和時(shí)間庫。

2.2 特性解讀

2.2.1 Joda-Time和JDK的互操作性

互操作性是指:Joda 類能夠生成 java.util.Date 的實(shí)例(以及Calendar),這可以讓我們保留現(xiàn)有對(duì)JDK的依賴,又能夠使用Joda處理復(fù)雜的日期/時(shí)間計(jì)算。

Date To Joda-Time

  1. Date date = new Date(); 
  2. DateTime dateTime = new DateTime(date); 

 Canendar To Joda-Time

  1. Calendar calendar = Calendar.getInstance(); 
  2. DateTime dateTime = new DateTime(calendar); 

 Joda-Time To Date

  1. Date date = new Date();   
  2. DateTime dateTime = new DateTime(date);                        
  3. Date date2 = dateTime.toDate(); 

 Joda-Time To Calendar

  1. Calendar calendar = Calendar.getInstance();   
  2. dateTime = new DateTime(calendar);   
  3. Calendar calendar2 = dateTime.toCalendar(Locale.CHINA);  

 2.2.2 Joda的關(guān)鍵日期/時(shí)間概念理解

Joda 使用了以下概念,使得它們可以應(yīng)用到任何日期/時(shí)間庫:

不可變性(Immutability)

Joda-Time與java.lang.String類似,它們的實(shí)例均無法修改(因?yàn)槿我鈱?duì)其值改變的操作都會(huì)生成新的對(duì)象),這也代表了它們是線程安全的。

瞬時(shí)性(Instant)

如接口 org.joda.time.ReadableInstant 中所表示的那樣,Instant 表示的是一個(gè)精確的時(shí)間點(diǎn),是從 epoch:1970-01-01T00:00:00Z 開始計(jì)算的毫秒數(shù),這也的設(shè)計(jì)也使得其子類都可以與JDK Date 以及 Calendar 類兼容。

  1. /** 
  2.  * Defines an instant in the datetime continuum. 
  3.  * This interface expresses the datetime as milliseconds from 1970-01-01T00:00:00Z. 
  4.  * <p> 
  5.  * The implementation of this interface may be mutable or immutable. 
  6.  * This interface only gives access to retrieve data, never to change it. 
  7.  * <p> 
  8.  * Methods in your application should be defined using <code>ReadableInstant</code> 
  9.  * as a parameter if the method only wants to read the instant without needing to know 
  10.  * the specific datetime fields. 
  11.  * <p> 
  12.  * The {@code compareTo} method is no longer defined in this class in version 2.0. 
  13.  * Instead, the definition is simply inherited from the {@code Comparable} interface. 
  14.  * This approach is necessary to preserve binary compatibility. 
  15.  * The definition of the comparison is ascending order by millisecond instant. 
  16.  * Implementors are recommended to extend {@code AbstractInstant} instead of this interface. 
  17.  * 
  18.  * @author Stephen Colebourne 
  19.  * @since 1.0 
  20.  */ 
  21. public interface ReadableInstant extends Comparable<ReadableInstant> { 
  22.  
  23.     /** 
  24.      * Get the value as the number of milliseconds since 
  25.      * the epoch, 1970-01-01T00:00:00Z. 
  26.      * 
  27.      * @return the value as milliseconds 
  28.      */ 
  29.     long getMillis(); 
  30.                        ······ 

 DateTime 類繼承圖如下:


局部性(Partial)

瞬時(shí)性表達(dá)的是與epoch相對(duì)的時(shí)間上的一個(gè)精確時(shí)刻,而一個(gè)局部時(shí)間指的是一個(gè)時(shí)間的一部分片段,其可以通過一些方法使得時(shí)間產(chǎn)生變動(dòng)(本質(zhì)上還是生成了新的類),這樣可以把它當(dāng)做重復(fù)周期中的一點(diǎn),用到多個(gè)地方。

年表(Chronology)

Joda-Time的設(shè)計(jì)核心就是年表(org.joda.time.Chronology),從根本上將,年表是一種日歷系統(tǒng),是一種計(jì)算時(shí)間的特殊方式,并且在其中執(zhí)行日歷算法的框架。Joda-Time支持的8種年表如下所示:

  • ISO(默認(rèn)) - org.joda.time.chrono.ISOChronology
  • GJ - org.joda.time.chrono.GJChronology
  • Gregorian - org.joda.time.chrono.GregorianChronology
  • Julian - org.joda.time.chrono.JulianChronology
  • Coptic - org.joda.time.chrono.CopticChronology
  • Buddhist - org.joda.time.chrono.BuddhistChronology
  • Ethiopic - org.joda.time.chrono.EthiopicChronology
  • Islamic - org.joda.time.chrono.IslamicChronology

以上的每一種年表都可以作為特定日歷系統(tǒng)的計(jì)算引擎,是可插拔的實(shí)現(xiàn)。

時(shí)區(qū)(Time zone)

具體定義詳見百科解釋,在實(shí)際編碼過程中任何嚴(yán)格的時(shí)間計(jì)算都必須涉及時(shí)區(qū)(或者相對(duì)于GMT),Joda-Time中對(duì)應(yīng)的核心類為org.joda.time.DateTimeZone,雖然日常的使用過程中,并未涉及到對(duì)時(shí)區(qū)的操作,但是DateTimeZone如何對(duì)DateTime產(chǎn)生影響是比較值得注意的,此處不進(jìn)行贅述。

2.3 具體使用方法

上面介紹我完了Joda-Time的一些概念,接下來具體使用我們來進(jìn)行說明:

2.3.1 創(chuàng)建 Joda-Time 對(duì)象

瞬時(shí)性-ReadableInstant

  1. // 1.使用系統(tǒng)時(shí)間 
  2. DateTime dateTime1 = new DateTime(); 
  3. // 2.使用jdk中的date 
  4. Date jdkDate1 = new Date(); 
  5. DateTime dateTime2 = new DateTime(jdkDate1); 
  6. // 3.使用毫秒數(shù)指定 
  7. Date jdkDate2 = new Date(); 
  8. long millis = jdkDate.getTime(); 
  9. DateTime dateTime3 = new DateTime(millis); 
  10. // 4.使用Calendar 
  11. Calendar calendar = Calendar.getInstance(); 
  12. DateTime dateTime4 = new DateTime(calendar); 
  13. // 5.使用多個(gè)字段指定一個(gè)瞬間時(shí)刻(局部時(shí)間片段) 
  14. // year month day hour(midnight is zero) minute second milliseconds 
  15. DateTime dateTime5 = new DateTime(2000, 1, 1, 0, 0, 0, 0); 
  16. // 6.由一個(gè)DateTime生成另一個(gè)DateTime 
  17. DateTime dateTime6 = new DateTime(dateTime1); 
  18. // 7.有時(shí)間字符串生成DateTime 
  19. String timeString = "2019-01-01T00:00:00-06:00"
  20. DateTime dateTime7 = DateTime.parse(timeString); 

 局部性-ReadablePartial

當(dāng)程序中處理的日期、時(shí)間并不需要是完整時(shí)刻的時(shí)候,可以創(chuàng)建一個(gè)局部時(shí)間,比如只希望專注于年/月/日, 或者一天中的時(shí)間,或者是一周中的某天。Joda-Time中有表示這些時(shí)間的是org.joda.time.ReadablePartial接口,實(shí)現(xiàn)它的兩個(gè)類LocalDate和LocalTime是分別用來表示年/月/日和一天中的某個(gè)時(shí)間的。

  1. // 顯示地提供所含的每個(gè)字段 
  2. LocalDate localDate = new LocalDate(2019, 1, 1); 
  3. // 6:30:06 PM 
  4. LocalTime localTime = new LocalTime(18, 30, 6, 0); 

 LocalDate是替代了早期Joda-Time版本中使用的org.joda.time.YearMonthDay,LocalTime是替代早期版本的org.joda.time.TimeOfDay。(均已被標(biāo)注為過時(shí)狀態(tài))。

時(shí)間跨度

Joda-Time提供了三個(gè)類用于表示時(shí)間跨度(在某些業(yè)務(wù)需求中,它們可能會(huì)非常有用)。

Duration

這個(gè)類表示以毫秒為單位的絕對(duì)精度,提供標(biāo)準(zhǔn)數(shù)學(xué)轉(zhuǎn)換的方法,同時(shí)把時(shí)間跨度轉(zhuǎn)換為標(biāo)準(zhǔn)單位。

Period

這個(gè)類表示以年月日單位表示。

Interval

這個(gè)類表示一個(gè)特定的時(shí)間跨度,使用一個(gè)明確的時(shí)刻界定這段時(shí)間跨度的范圍。Interval 為半開 區(qū)間,所以由其封裝的時(shí)間跨度包括這段時(shí)間的起始時(shí)刻,但是不包含結(jié)束時(shí)刻。

2.3.2 使用Joda-Time的方法處理時(shí)間

  1. DateTime today = new DateTime(); 
  2. // 獲取777秒之前的時(shí)間 
  3. DateTime dateTime1 = today.minus(777 * 1000); 
  4. // 獲取明天的時(shí)間 
  5. DateTime tomorrow = today.plusDays(1); 
  6. // 獲取當(dāng)月第一天的日期 
  7. DateTime dateTime2 = today.withDayOfMonth(1);  
  8. // 獲取當(dāng)前時(shí)間三個(gè)月后的月份的最后一天 
  9. DateTime dateTime3 = today.plusMonths(3).dayOfMonth().withMaximumValue(); 

 下面列出部分DateTime方法列表: plus/minus開頭的方法(比如:plusDay, minusMonths):用來返回在DateTime實(shí)例上增加或減少一段時(shí)間后的實(shí)例

  • plus(long duration) 增加指定毫秒數(shù)并返回
  • plusYears(int years) 增加指定年份并返回
  • plusMonths(int months) 增加指定月份并返回
  • plusWeeks(int weeks) 增加指定星期并返回
  • plusDays(int days) 增加指定天數(shù)并返回
  • plusHours(int hours) 增加指定小時(shí)并返回
  • plusMinutes(int minutes) 增加指定分鐘并返回
  • plusSeconds(int seconds) 增加指定秒數(shù)并返回
  • plusMillis(int millis) 增加指定毫秒并返回

與之相反的是minus前綴的 plus是增加 minus是減少

with開頭的方法:用來返回在DateTime實(shí)例更新指定日期單位后的實(shí)例

  • withCenturyOfEra(int centuryOfEra) 更新時(shí)間世紀(jì)單位并返回
  • withYearOfCentury(int yearOfCentury)更新世紀(jì)年并返回
  • withYear(int year) 更新時(shí)間年并返回
  • withWeekyear(int weekyear) 更新時(shí)間周數(shù)并返回
  • withMonthOfYear(int monthOfYear)更新時(shí)間月份并返回
  • withDayOfYear(int dayOfYear) 更新時(shí)間天數(shù)并返回
  • withDayOfMonth(int dayOfMonth) 更新時(shí)間天數(shù)并返回
  • withDayOfWeek(int dayOfWeek) 更新時(shí)間天數(shù)并返回
  • withHourOfDay(int hour) 更新時(shí)間小時(shí)并返回
  • withMinuteOfHour(int minute) 更新時(shí)間分鐘并返回
  • withSecondOfMinute(int second) 更新時(shí)間秒數(shù)并返回
  • withMillisOfSecond(int millis) 更新時(shí)間毫秒并返回
  • withMillisOfDay(int millis) 更新時(shí)間毫秒并返回
  • withTimeAtStartOfDay() 獲取當(dāng)天最早時(shí)間

判斷DateTime對(duì)象大小狀態(tài)的一些操作方法

  • compareTo(DateTime d) 比較兩時(shí)間大小 時(shí)間大于指定時(shí)間返回 1 時(shí)間小于指定時(shí)間返回-1 相等返回0
  • equals(DateTime d) 比較兩時(shí)間是否相等
  • isAfter(long instant) 判斷時(shí)間是否大于指定時(shí)間
  • isAfterNow() 判斷時(shí)間是否大于當(dāng)前時(shí)間
  • isBefore(long instant) 判斷時(shí)間是否小于指定時(shí)間
  • isBeforeNow() 判斷時(shí)間是否小于當(dāng)前時(shí)間
  • isEqual(long instant) 判斷時(shí)間是否等于指定時(shí)間
  • isEqualNow() 判斷時(shí)間是否等于當(dāng)前時(shí)間

2.3.3 以Joda-Time的方式格式化時(shí)間

  1. // 傳入的格式化模板只需與JDK SimpleDateFormat兼容的格式字符串即可 
  2. public static String convert(Date date,String dateFormat){ 
  3.     return new DateTime(date).toString(dateFormat); 
  4. // 將JDK中的Date轉(zhuǎn)化為UTC時(shí)區(qū)的DateTime 
  5. DateTime dateTime = new DateTime(new Date(), DateTimeZone.UTC); 
  6. // 將String轉(zhuǎn)換為DateTime 
  7. public static Date convertUTC2Date(String utcDate){ 
  8.     DateTime dateTime =DateTime.parse(utcDate, DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); 
  9.     return dateTime.toDate(); 
  10.  } 

 更多使用方法請(qǐng)參考官方文檔。

三、JAVA 8中新的時(shí)間類庫

3.1 簡介

由于JDK之前版本的類庫的缺陷和糟糕的使用體驗(yàn),再加上已經(jīng)成為事實(shí)標(biāo)準(zhǔn)Joda-Time的影響力,Oracle決定在JAVA API中提供高質(zhì)量的日期和時(shí)間支持,這也就是整合了大部分Joda-Time特性的JDK 8新的時(shí)間類庫。(Joda-Time的作者實(shí)際參與開發(fā),并且實(shí)現(xiàn)了JSR310的全部內(nèi)容,新的API位于java.time下。常用的類有以下幾個(gè):LocalDate、LocalTime、Instant、Duration和Period。)

由于JDK 8 新的時(shí)間類庫大量借鑒了Joda-Time的設(shè)計(jì)思想乃至命名,因此如果你是Joda-Time的使用者,那你可以無學(xué)習(xí)成本的使用新的API(當(dāng)然,它們之間也存在些許差別需要注意到)。

3.2 使用方法

3.2.1 使用LocalDate 和LocalTime

首先是LocalDate,該類的實(shí)例是一個(gè)不可變對(duì)象,它只提供了簡單的日期,并不含當(dāng)天的時(shí)間信息。另外,它也不附帶任何與時(shí)區(qū)相關(guān)的信息。

  1. // 使用指定的日期創(chuàng)建LocalDate 
  2. LocalDate date = LocalDate.of(2019, 1, 1); 
  3. // 獲取當(dāng)前日期 
  4. LocalDate today = LocalDate.now(); 
  5. // 獲取今日的屬性 
  6. int year = date.getYear(); 
  7. Month month = date.getMonth(); 
  8. int day = date.getDayOfMonth(); 
  9. DayOfWeek dow = date.getDayOfWeek(); 
  10. int len = date.lengthOfMonth(); 
  11. boolean leap = date.isLeapYear(); 
  12. // 通過ChronoField的枚舉值獲取需要的屬性字段 
  13. int year = date.get(ChronoField.YEAR); 

 接著是LocalTime,它表示了一天內(nèi)的某個(gè)時(shí)刻。

  1. LocalTime time = LocalTime.of(18, 18, 18); 
  2. int hour = time.getHour(); 
  3. int minute = time.getMinute(); 
  4. int second = time.getSecond(); 

 LocalDate和LocalTime都可以通過使用靜態(tài)方法parse來解析字符串進(jìn)行創(chuàng)建。

  1. LocalDate date = LocalDate.parse("2019-01-01"); 
  2.  
  3. LocalTime time = LocalTime.parse("18:18:18"); 

 也可以向parse方法傳遞一個(gè)DateTimeFormatter,該類的實(shí)例定義了如何格式化一個(gè)日期或者時(shí)間對(duì)象。它其實(shí)是老版java.util.DateFormat的替代品。

3.2.2 LocalDateTime

  1. // 直接創(chuàng)建LocalDateTime 
  2. LocalDateTime dt1 = LocalDateTime.of(2019, Month.JANUARY, 1, 18, 18, 18); 
  3. // 合并日期和時(shí)間 
  4. LocalDate date = LocalDate.parse("2019-01-01"); 
  5. LocalTime time = LocalTime.parse("18:18:18"); 
  6. LocalDateTime dt2 = LocalDateTime.of(datetime); 
  7. LocalDateTime dt3 = date.atTime(18, 18, 18); 
  8. LocalDateTime dt4 = date.atTime(time); 
  9. LocalDateTime dt5 = time.atDate(date); 
  10. // 從LocalDateTime中提取LocalDate或者LocalTime 
  11. LocalDate date1 = dt1.toLocalDate(); 
  12. LocalTime time1 = dt1.toLocalTime(); 

 3.3.3 Instant

Instant類是為了方便計(jì)算機(jī)理解的而設(shè)計(jì)的,它表示一個(gè)持續(xù)時(shí)間段上某個(gè)點(diǎn)的單一大整型數(shù),實(shí)際上它是以Unix元年時(shí)間(傳統(tǒng)的設(shè)定為UTC時(shí)區(qū)1970年1月1日午夜時(shí)分)開始所經(jīng)歷的秒數(shù)進(jìn)行計(jì)算(最小計(jì)算單位為納秒)。

  1. // 傳遞一個(gè)秒數(shù)已創(chuàng)建該類的實(shí)例 
  2. Instant.ofEpochSecond(3); 
  3. // 傳遞一個(gè)秒數(shù)+納秒 2 秒之后再加上100萬納秒(1秒) 
  4. Instant.ofEpochSecond(2, 1_000_000_000); 

 3.3.4 Duration與Period

Duration是用于比較兩個(gè)LocalTime對(duì)象或者兩個(gè)Instant之間的時(shí)間差值。

  1. Duration d1 = Duration.between(time1, time2); 
  2. Duration d1 = Duration.between(dateTime1, dateTime2); 
  3. Duration d2 = Duration.between(instant1, instant2); 

 Period是用于對(duì)年月日的方式對(duì)多個(gè)時(shí)間進(jìn)行比較。

  1. Period tenDays = Period.between(LocalDate.of(2019, 1, 1), lcalDate.of(2019, 2, 2)); 

當(dāng)然,Duration和Period類都提供了很多非常方便的工廠類,直接創(chuàng)建對(duì)應(yīng)的實(shí)例。

  1. Duration threeMinutes = Duration.ofMinutes(3); 
  2. Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES); 
  3. Period tenDays = Period.ofDays(10); 
  4. Period threeWeeks = Period.ofWeeks(3); 
  5. Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1); 

 3.3.5 操作、解析和格式化日期

  1. // 直接使用withAttribute的方法修改 
  2. LocalDate date1 = LocalDate.of(2019, 1, 1); 
  3. LocalDate date2 = date1.withYear(2019); 
  4. LocalDate date3 = date2.withDayOfMonth(1); 
  5. LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 1); 

 所有聲明了Temporal接口的類LocalDate、LocalTime、LocalDateTime以及Instant,它們都使用get和with方法,將對(duì)象值的讀取和修改區(qū)分開,如果使用了不支持的字段訪問字段,會(huì)拋出一個(gè)UnsupportedTemporalTypeException異常。類似的,plus方法和minus方法都聲明于Temporal接口。通過這些方法,對(duì)TemporalUnit對(duì)象加上或者減去一個(gè)數(shù)字,我們能非常方便地將Temporal對(duì)象前溯或者回滾至某個(gè)時(shí)間段,通過ChronoUnit枚舉我們可以非常方便地實(shí)現(xiàn)TemporalUnit接口。

3.3.6 更多定制化的處理時(shí)間

向重載的with方法傳遞一個(gè)定制化的TemporalAdjuster對(duì)象,可以更加靈活地處理日期。時(shí)間和日期的API已經(jīng)提供了大量預(yù)定義的TemporalAdjuster,可以通過TemporalAdjuster類的靜態(tài)工廠方法訪問它們。這些方法的名稱非常直觀,方法名就是問題描述。某些情況下,如果你需要定義自己的TemporalAdjuster,只需要聲明TemporalAdjuster接口并且自己實(shí)現(xiàn)對(duì)應(yīng)的方法即可。

  1. LocalDate date1 = LocalDate.of(2014, 3, 18); 
  2. LocalDate date2 = date1.with(TemporalAdjuster.nextOrSame(DayOfWeek.SUNDAY)); 
  3. LocalDate date3 = date2.with(TemporalAdjuster.lastDayOfMonth()); 

 3.3.7 解析日期-時(shí)間對(duì)象

日常工作中,格式化以及解析日期-時(shí)間對(duì)象是另一個(gè)非常重要的功能,而新的java.time.format包就是特別為我們達(dá)到這個(gè)目的而設(shè)計(jì)的。這其中,最重要的類是DateTimeFormatter。所有的DateTimeFormatter實(shí)例都能用于以一定的格式創(chuàng)建代表特定日期或時(shí)間的字符串。(與老的java.util.DateFormat相比較,所有的DateTimeFormatter實(shí)例都是線程安全的)

  1. // 使用不同的格式器生成字符串 
  2. LocalDate date = LocalDate.of(2019, 1, 1); 
  3. String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); 
  4. String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); 
  5. // 生成LocalDate對(duì)象 
  6. LocalDate date1 = LocalDate.parse("20190101", DateTimeFormatter.BASIC_ISO_DATE); 
  7. LocalDate date2 = LocalDate.parse("2019-01-01", DateTimeFormatter.ISO_LOCAL_DATE); 

  1. // 使用特定的模式創(chuàng)建格式器 
  2. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); 
  3. LocalDate date1 = LocalDate.of(2019, 1, 1); 
  4. String formattedDate = date1.format(formatter); 
  5. LocalDate date2 = LocalDate.parse(formattedDate, formatter); 

 3.3.8 處理不同的時(shí)區(qū)和日歷系統(tǒng)

在新的日期-時(shí)間類庫中,為了最大程度上的減少在處理時(shí)區(qū)帶來的繁瑣和復(fù)雜而使用了新的java.time.ZoneId類(與其他日期和時(shí)間類一樣,ZoneId類也是無法修改的) 來替代老版的java.util.TimeZone。時(shí)區(qū)是按照一定的規(guī)則將區(qū)域劃分成標(biāo)準(zhǔn)時(shí)間相同的區(qū)間。在ZoneRules這個(gè)類中包含了40個(gè)這樣的實(shí)例。可以簡單地通過調(diào)用ZoneId的getRules()得到指定時(shí)區(qū)的規(guī)則。每個(gè)特定的ZoneId對(duì)象都由一個(gè)地區(qū)ID標(biāo)識(shí),地區(qū)ID都為“{區(qū)域}/{城市}”的格式。比如:

  1. ZoneId romeZone = ZoneId.of("Asia/Shanghai"); 

Java 8中在原先的TimeZone中加入了新的方法toZoneId,其作用是將一個(gè)老的時(shí)區(qū)對(duì)象轉(zhuǎn)換為ZoneId:

  1. ZoneId zoneId = TimeZone.getDefault().toZoneId(); 

得到的ZoneId對(duì)象后可以將它與LocalDate、LocalDateTime或者是Instant對(duì)象整合起來,構(gòu)造為一個(gè)ZonedDateTime實(shí)例,它代表了相對(duì)于指定時(shí)區(qū)的時(shí)間點(diǎn):

  1. LocalDate date = LocalDate.of(2019, Month.JANUARY, 1); 
  2. ZonedDateTime zdt1 = date.atStartOfDay(romeZone); 
  3. LocalDateTime dateTime = LocalDateTime.of(2019, Month.JANUARY, 18, 13, 45); 
  4. ZonedDateTime zdt2 = dateTime.atZone(romeZone); 
  5. Instant instant = Instant.now(); 
  6. ZonedDateTime zdt3 = instant.atZone(romeZone); 

 通過ZoneId,還可以將LocalDateTime轉(zhuǎn)換為Instant:

  1. LocalDateTime dateTime = LocalDateTime.of(2019, Month.JANUARY, 18, 13, 45); 
  2. Instant instantFromDateTime = dateTime.toInstant(romeZone); 

 同樣可以通過反向的方式得到LocalDateTime對(duì)象:

  1. Instant instant = Instant.now(); 
  2. LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone); 

 與Joda-Time所不同的是,Java8中的日期-時(shí)間類庫提供了4種其他的日歷系統(tǒng),這些日歷系統(tǒng)中的每一個(gè)都有一個(gè)對(duì)應(yīng)的日志類,分別是ThaiBuddhistDate、MinguoDate 、JapaneseDate 以及HijrahDate 。所有這些類以及LocalDate 都實(shí)現(xiàn)了ChronoLocalDate接口,能夠?qū)珰v的日期進(jìn)行建模。利用LocalDate對(duì)象,你可以創(chuàng)建這些類的實(shí)例。同樣的,利用它們提供的靜態(tài)工廠方法,你可以創(chuàng)建任何一個(gè)Temporal對(duì)象的實(shí)例。

  1. LocalDate date = LocalDate.of(2019, Month.JANUARY, 1); 
  2. JapaneseDate japaneseDate = JapaneseDate.from(date); 

 參考資料

Joda-Time 簡介 Joda Time項(xiàng)目和java8時(shí)間api

動(dòng)態(tài)計(jì)算時(shí)間段

需求:如現(xiàn)在是13:00,則時(shí)間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發(fā)時(shí)間為當(dāng)前時(shí)間+參數(shù)【2h10min】,最遲的時(shí)間段為開始時(shí)間在20點(diǎn)前結(jié)束時(shí)間在20點(diǎn)后的時(shí)間段),求解共有多少個(gè)時(shí)間段?

分析:

  1. 第一個(gè)時(shí)間段的開始時(shí)間:當(dāng)前時(shí)間+參數(shù)【2h10min】,中間的時(shí)間段是2h;
  2. 通過理解這句:最遲的時(shí)間段為開始時(shí)間在20點(diǎn)前結(jié)束時(shí)間在20點(diǎn)后的時(shí)間段,我們可以假設(shè)最大的時(shí)間變量為 max
  3. 假設(shè)當(dāng)前時(shí)間為now,總共有n個(gè)時(shí)間段,可以推導(dǎo)出公式:now + (2h * n) + 10min <= max;

注意:計(jì)算過程都轉(zhuǎn)換成毫秒

  1. public class Test { 
  2.     // 毫秒 
  3.     static final long slot = 130 * 60 * 1000; 
  4.  
  5.     private static List<TimeSelectItem> buildStartEndTime(Long now, Long max) { 
  6.         // now + (2h * n) + 10min  <= max
  7.  
  8.         Long n = (max - now - 60 * 1000) / (120 * 60 * 1000); 
  9.         System.out.println("max:" + max); 
  10.         System.out.println("now:" + now); 
  11.         System.out.println(" max - now:" + (max - now)); 
  12.         System.out.println("n:" + n); 
  13.  
  14.         List<TimeSelectItem> timeSelectItems = new ArrayList<>(); 
  15.  
  16.         Long startTimestamp = now + slot; 
  17.         Long endTimestamp = startTimestamp + 120 * 60 * 1000; 
  18.  
  19.         for (int i = 1; i <= n; i++) { 
  20.             // 起始時(shí)間 
  21.             // startTimestamp = startTimestamp + i * (120 * 60 * 1000); 
  22.             // 結(jié)束時(shí)間 
  23.             endTimestamp = startTimestamp + (120 * 60 * 1000); 
  24.  
  25.             System.out.println(startTimestamp); 
  26.             System.out.println(endTimestamp); 
  27.  
  28.             TimeSelectItem item = new TimeSelectItem(); 
  29.  
  30.             DateTime dt = new DateTime(startTimestamp); 
  31.             int hour = dt.hourOfDay().get(); 
  32.             int millis = dt.getMinuteOfHour(); 
  33.             String startTag = hour + ":" + millis; 
  34.  
  35.             DateTime dt1 = new DateTime(endTimestamp); 
  36.             int hour1 = dt1.hourOfDay().get(); 
  37.             long millis1 = dt1.getMinuteOfHour(); 
  38.             String enTag = hour1 + ":" + millis1; 
  39.  
  40.             item.setDisplayName(startTag + " - " + enTag); 
  41.  
  42.             item.setStartTimestamp(startTimestamp); 
  43.             item.setEndTimestamp(endTimestamp); 
  44.             timeSelectItems.add(item); 
  45.  
  46.             startTimestamp = endTimestamp; 
  47.         } 
  48.         return timeSelectItems; 
  49.     } 
  50.  
  51.     public static void main(String[] args) { 
  52.         Long start = DateTime.now().getMillis(); 
  53.         Calendar c = Calendar.getInstance(); 
  54.         c.setTime(new Date()); 
  55.         c.set(Calendar.HOUR_OF_DAY, 20); 
  56.         c.set(Calendar.MINUTE, 0); 
  57.         c.set(Calendar.SECOND, 0); 
  58.  
  59.  
  60.         DateTime dt = new DateTime(); 
  61.         dt.withHourOfDay(20); 
  62.         Long end = c.getTimeInMillis(); 
  63.         
  64.         // List<TimeSelectItem> list = buildStartEndTime(1614747600000L, 1614772800000L); 
  65.         List<TimeSelectItem> list = buildStartEndTime(1614834000000L, end); 
  66.         for (TimeSelectItem item : list ) { 
  67.             System.out.println(item); 
  68.         } 
  69.     } 

 【編輯推薦】

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2010-03-18 11:06:18

Python stuc

2014-12-22 10:14:31

Java8

2009-08-17 17:42:57

C#數(shù)據(jù)庫操作類

2025-04-25 10:28:40

2023-07-13 08:26:49

Java羅漢增強(qiáng)類

2023-04-10 09:11:27

HutoolJava工具

2016-12-13 14:03:54

JAVA操作工具

2011-12-07 15:58:25

JavaNIO

2020-10-15 17:38:00

Time Wheel

2021-09-29 11:15:56

PyAutoGUIPython鍵鼠操作

2019-11-20 08:56:51

Java工具類庫IO

2009-01-04 11:55:09

Java數(shù)組Java常用工具Java類

2009-07-22 16:27:24

iBATIS配置類iBATIS操作類

2011-12-12 10:33:47

JavaNIO

2011-12-12 10:19:00

JavaNIO

2012-04-17 11:21:50

Java

2009-07-31 16:45:23

ASP.NET數(shù)據(jù)庫操

2023-10-11 07:00:44

高可用程序客戶端

2010-07-05 10:44:35

SQL Server數(shù)

2010-04-30 14:39:03

Oracle數(shù)據(jù)庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)