成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java時間操作類庫-Joda-Time

開發 前端
上一周在做一個產品的需求的時候有個動態計算時間段(如現在是13:00,則時間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發時間為當前時間+參數【2h10min】,最遲的時間段為開始時間在20點前結束時間在20點后的時間段),期間大量使用到了日期時間類庫,本著熟悉日期時間類庫才有了這篇文章,文章最后我會把我如何實現的這個需求的一個算法貼出來。

 前言

上一周在做一個產品的需求的時候有個動態計算時間段(如現在是13:00,則時間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發時間為當前時間+參數【2h10min】,最遲的時間段為開始時間在20點前結束時間在20點后的時間段),期間大量使用到了日期時間類庫,本著熟悉日期時間類庫才有了這篇文章,文章最后我會把我如何實現的這個需求的一個算法貼出來。

一、JDK8以前版本中的時間類庫

1.1 原始時間類庫存在的缺陷與不足

我們在使用Java8之前的類庫時,都會在處理日期-時間的時候總是不爽,這其中包括且不限于以下的槽點:

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

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

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

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

1.2 關于SimpleDateFormat 線程不安全的原因

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

  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 為每個線程都創建一個線程獨享 SimpleDateFormat 變量;
  2. 需要的時候創建局部變量;
  3. 使用 org.apacle.commons.lang3.time.DateFormatUtils
  4. 使用Joda-Time (后面介紹)

二、Joda-Time 日期時間類庫

2.1 簡介

Joda-Time 是Joda提供的一個遵循Apache2.0 開源協議的 JDK以外的優質日期和時間開發庫。

  1. Joda除Joda-Time之外的項目有Joda-Money、Joda-Beans、Joda-Convert、Joda-Collect Joda官網 

2.1.1 為什么使用Joda-Time

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

2.1.2 Joda-Time 的關鍵優點

  1. LocalDate:只包含日期
  2. LocalTime:只包含時間
  3. Instant:時間軸上的時間點
  4. DateTime:時區中完整的日期和時間
  5. DateTimeZone:更好的時區
  6. Duration和Period:持續時間
  7. Interval:兩個時間點之間的時間
  8. 全面并且靈活的時間格式化與轉換

正因為Joda-Time 與 Java8 之前的時間類庫相比,具備了如此多的優點,所以 Joda-Time 成為事實上的標準的Java日期和時間庫。

2.2 特性解讀

2.2.1 Joda-Time和JDK的互操作性

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

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的關鍵日期/時間概念理解

Joda 使用了以下概念,使得它們可以應用到任何日期/時間庫:

不可變性(Immutability)

Joda-Time與java.lang.String類似,它們的實例均無法修改(因為任意對其值改變的操作都會生成新的對象),這也代表了它們是線程安全的。

瞬時性(Instant)

如接口 org.joda.time.ReadableInstant 中所表示的那樣,Instant 表示的是一個精確的時間點,是從 epoch:1970-01-01T00:00:00Z 開始計算的毫秒數,這也的設計也使得其子類都可以與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)

瞬時性表達的是與epoch相對的時間上的一個精確時刻,而一個局部時間指的是一個時間的一部分片段,其可以通過一些方法使得時間產生變動(本質上還是生成了新的類),這樣可以把它當做重復周期中的一點,用到多個地方。

年表(Chronology)

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

  • ISO(默認) - 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

以上的每一種年表都可以作為特定日歷系統的計算引擎,是可插拔的實現。

時區(Time zone)

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

2.3 具體使用方法

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

2.3.1 創建 Joda-Time 對象

瞬時性-ReadableInstant

  1. // 1.使用系統時間 
  2. DateTime dateTime1 = new DateTime(); 
  3. // 2.使用jdk中的date 
  4. Date jdkDate1 = new Date(); 
  5. DateTime dateTime2 = new DateTime(jdkDate1); 
  6. // 3.使用毫秒數指定 
  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.使用多個字段指定一個瞬間時刻(局部時間片段) 
  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.由一個DateTime生成另一個DateTime 
  17. DateTime dateTime6 = new DateTime(dateTime1); 
  18. // 7.有時間字符串生成DateTime 
  19. String timeString = "2019-01-01T00:00:00-06:00"
  20. DateTime dateTime7 = DateTime.parse(timeString); 

 局部性-ReadablePartial

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

  1. // 顯示地提供所含的每個字段 
  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。(均已被標注為過時狀態)。

時間跨度

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

Duration

這個類表示以毫秒為單位的絕對精度,提供標準數學轉換的方法,同時把時間跨度轉換為標準單位。

Period

這個類表示以年月日單位表示。

Interval

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

2.3.2 使用Joda-Time的方法處理時間

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

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

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

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

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

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

判斷DateTime對象大小狀態的一些操作方法

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

2.3.3 以Joda-Time的方式格式化時間

  1. // 傳入的格式化模板只需與JDK SimpleDateFormat兼容的格式字符串即可 
  2. public static String convert(Date date,String dateFormat){ 
  3.     return new DateTime(date).toString(dateFormat); 
  4. // 將JDK中的Date轉化為UTC時區的DateTime 
  5. DateTime dateTime = new DateTime(new Date(), DateTimeZone.UTC); 
  6. // 將String轉換為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.  } 

 更多使用方法請參考官方文檔。

三、JAVA 8中新的時間類庫

3.1 簡介

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

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

3.2 使用方法

3.2.1 使用LocalDate 和LocalTime

首先是LocalDate,該類的實例是一個不可變對象,它只提供了簡單的日期,并不含當天的時間信息。另外,它也不附帶任何與時區相關的信息。

  1. // 使用指定的日期創建LocalDate 
  2. LocalDate date = LocalDate.of(2019, 1, 1); 
  3. // 獲取當前日期 
  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,它表示了一天內的某個時刻。

  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都可以通過使用靜態方法parse來解析字符串進行創建。

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

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

3.2.2 LocalDateTime

  1. // 直接創建LocalDateTime 
  2. LocalDateTime dt1 = LocalDateTime.of(2019, Month.JANUARY, 1, 18, 18, 18); 
  3. // 合并日期和時間 
  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類是為了方便計算機理解的而設計的,它表示一個持續時間段上某個點的單一大整型數,實際上它是以Unix元年時間(傳統的設定為UTC時區1970年1月1日午夜時分)開始所經歷的秒數進行計算(最小計算單位為納秒)。

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

 3.3.4 Duration與Period

Duration是用于比較兩個LocalTime對象或者兩個Instant之間的時間差值。

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

 Period是用于對年月日的方式對多個時間進行比較。

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

當然,Duration和Period類都提供了很多非常方便的工廠類,直接創建對應的實例。

  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方法,將對象值的讀取和修改區分開,如果使用了不支持的字段訪問字段,會拋出一個UnsupportedTemporalTypeException異常。類似的,plus方法和minus方法都聲明于Temporal接口。通過這些方法,對TemporalUnit對象加上或者減去一個數字,我們能非常方便地將Temporal對象前溯或者回滾至某個時間段,通過ChronoUnit枚舉我們可以非常方便地實現TemporalUnit接口。

3.3.6 更多定制化的處理時間

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

  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 解析日期-時間對象

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

  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對象 
  6. LocalDate date1 = LocalDate.parse("20190101", DateTimeFormatter.BASIC_ISO_DATE); 
  7. LocalDate date2 = LocalDate.parse("2019-01-01", DateTimeFormatter.ISO_LOCAL_DATE); 

  1. // 使用特定的模式創建格式器 
  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 處理不同的時區和日歷系統

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

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

Java 8中在原先的TimeZone中加入了新的方法toZoneId,其作用是將一個老的時區對象轉換為ZoneId:

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

得到的ZoneId對象后可以將它與LocalDate、LocalDateTime或者是Instant對象整合起來,構造為一個ZonedDateTime實例,它代表了相對于指定時區的時間點:

  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轉換為Instant:

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

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

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

 與Joda-Time所不同的是,Java8中的日期-時間類庫提供了4種其他的日歷系統,這些日歷系統中的每一個都有一個對應的日志類,分別是ThaiBuddhistDate、MinguoDate 、JapaneseDate 以及HijrahDate 。所有這些類以及LocalDate 都實現了ChronoLocalDate接口,能夠對公歷的日期進行建模。利用LocalDate對象,你可以創建這些類的實例。同樣的,利用它們提供的靜態工廠方法,你可以創建任何一個Temporal對象的實例。

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

 參考資料

Joda-Time 簡介 Joda Time項目和java8時間api

動態計算時間段

需求:如現在是13:00,則時間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發時間為當前時間+參數【2h10min】,最遲的時間段為開始時間在20點前結束時間在20點后的時間段),求解共有多少個時間段?

分析:

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

注意:計算過程都轉換成毫秒

  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.             // 起始時間 
  21.             // startTimestamp = startTimestamp + i * (120 * 60 * 1000); 
  22.             // 結束時間 
  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.     } 

 【編輯推薦】

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2010-03-18 11:06:18

Python stuc

2014-12-22 10:14:31

Java8

2009-08-17 17:42:57

C#數據庫操作類

2025-04-25 10:28:40

2023-07-13 08:26:49

Java羅漢增強類

2016-12-13 14:03:54

JAVA操作工具

2023-04-10 09:11:27

HutoolJava工具

2020-10-15 17:38:00

Time Wheel

2011-12-07 15:58:25

JavaNIO

2021-09-29 11:15:56

PyAutoGUIPython鍵鼠操作

2019-11-20 08:56:51

Java工具類庫IO

2009-01-04 11:55:09

Java數組Java常用工具Java類

2009-07-22 16:27:24

iBATIS配置類iBATIS操作類

2011-12-12 10:33:47

JavaNIO

2012-04-17 11:21:50

Java

2011-12-12 10:19:00

JavaNIO

2023-10-11 07:00:44

高可用程序客戶端

2009-07-31 16:45:23

ASP.NET數據庫操

2010-04-30 14:39:03

Oracle數據庫

2010-07-05 10:44:35

SQL Server數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品一区二区久久 | 看av网| 中文字幕日韩欧美 | 亚洲一区二区三区在线免费 | 久久国品片 | 亚洲国产精品一区二区三区 | 日本一区二区三区视频在线 | 中文字幕国产视频 | 国产激情视频在线 | 91丨九色丨国产在线 | 日韩精品一区二区三区四区 | 久久久久无码国产精品一区 | 精品一区久久 | 国产九九av | 国产精品激情 | 国产精品三级久久久久久电影 | 午夜电影网站 | 精品国产黄a∨片高清在线 成人区精品一区二区婷婷 日本一区二区视频 | 激情五月婷婷在线 | 亚洲国产高清高潮精品美女 | 久久一区视频 | 91在线观 | 亚洲韩国精品 | cao视频| 狠狠视频 | 亚洲三级av | 99re6在线视频 | 在线一区视频 | 99久久精品一区二区毛片吞精 | 久久久蜜桃 | 精品视频一区二区三区四区 | 亚洲人精品 | 免费观看av | 久久久精品网站 | 青青草原综合久久大伊人精品 | 一级片免费在线观看 | 国产有码 | 欧美成人精品一区二区男人看 | 亚洲精品久久久久久首妖 | 一区二区三区国产好 | 日本一区二区三区四区 |