本篇內(nèi)容主要講解“如何使用Java時間操作類庫Joda-Time”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何使用Java時間操作類庫Joda-Time”吧!
創(chuàng)新互聯(lián)建站服務(wù)項目包括廣宗網(wǎng)站建設(shè)、廣宗網(wǎng)站制作、廣宗網(wǎng)頁制作以及廣宗網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,廣宗網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到廣宗省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
一、JDK8以前版本中的時間類庫
1.1 原始時間類庫存在的缺陷與不足
我們在使用Java8之前的類庫時,都會在處理日期-時間的時候總是不爽,這其中包括且不限于以下的槽點:
在Java 1.0版本中,對時間、日期的操作完全依賴于 java.util.Data 類,只能以毫秒的精度表示時間,無法表示日期。
在易用性方面有著很大的缺陷,年份的起始時間選擇是1900年,月份是從0開始。
toString 方法返回值不直觀,帶有時區(qū)。
在Java1.1 版本中,廢棄了很多Date 類中的很多方法,并且新增了 java.util.Calendar。但是與Date相同,Calendar 類也有類似的問題和設(shè)計缺陷,導(dǎo)致在使用這些類寫出的代碼也很容易出錯。
月份依然是從0開始計算。
常用的日期、時間操作需要同時使用Date、Canendar、SimpleDateFormat,比較繁瑣。
部分特性只存在于某一個類(解析和格式化日期或時間的DateFormat方法只存在于Date類中)。
DateFormat 不是線程安全的,如果兩個線程嘗試使用同一個formatter 解析日期,可能會得到無法預(yù)期的結(jié)果。
Date 和 Canendar 都是可變的。
1.2 關(guān)于SimpleDateFormat 線程不安全的原因
由于 parse 方法使用的貢獻(xiàn)變量 calendar 不是線程安全的。在 format (subFormat) 方法中進(jìn)行了 calendar 的賦值,在 parse 進(jìn)行了值得處理,因此在并發(fā)的情況下會造成 calendar 清理不及時,值被覆蓋的情況。
/** * The {@link Calendar} instance used for calculating the date-time fields * and the instant of time. This field is used for both formatting and * parsing. * *Subclasses should initialize this field to a {@link Calendar} * appropriate for the {@link Locale} associated with this *
DateFormat
. * @serial */ protected Calendar calendar; @Override public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos){ pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); } // Called from Format after creating a FieldDelegate private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); // At this point the fields of Calendar have been set. Calendar // will fill in default values for missing fields when the time // is computed. pos.index = start; Date parsedDate; try { parsedDate = calb.establish(calendar).getTime(); // If the year value is ambiguous, // then the two-digit year == the default start year if (ambiguousYear[0]) { if (parsedDate.before(defaultCenturyStart)) { parsedDate = calb.addYear(100).establish(calendar).getTime(); } } } }
1.3 如何解決上述線程不安全問題?
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
使用ThreadLocal 為每個線程都創(chuàng)建一個線程獨享 SimpleDateFormat 變量;
需要的時候創(chuàng)建局部變量;
使用 org.apacle.commons.lang3.time.DateFormatUtils
使用Joda-Time (后面介紹)
二、Joda-Time 日期時間類庫
2.1 簡介
Joda-Time 是Joda提供的一個遵循Apache2.0 開源協(xié)議的 JDK以外的優(yōu)質(zhì)日期和時間開發(fā)庫。
Joda除Joda-Time之外的項目有Joda-Money、Joda-Beans、Joda-Convert、Joda-Collect Joda官網(wǎng)
2.1.1 為什么使用Joda-Time
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
使用方便:Calendar 訪問“正常的”日期困難,并且缺乏簡單的防腐,Joda-Time 擁有簡單的字段訪問,比如獲得年的 getYear() 和 獲得星期 中的天 getDayOfWeek() 。
易于擴(kuò)展:JDK支持通過使用子類實現(xiàn)多個日歷系統(tǒng),但是這是非常笨重的,并且在實現(xiàn)中很難選出另一個日歷系統(tǒng)。Joda-Time 支持基于 Chronology 類實現(xiàn)多個可插拔的日歷系統(tǒng)。
功能全面:Joda-Time 提供了所有的日期和時間計算的必須功能,它提供了即裝即用的特性。
最新的時區(qū)計算:時區(qū)的實現(xiàn)基于公共時區(qū)信息數(shù)據(jù)庫,每年更新數(shù)次。新版本的Joda-Time 包括了這個數(shù)據(jù)庫的所有更改,應(yīng)盡早進(jìn)行必要的更新,手動更新區(qū)域數(shù)據(jù)很容易。
日歷支持:提供了8種日歷系統(tǒng)。
互通性:內(nèi)部使用毫秒進(jìn)行標(biāo)識,這與JDK或者其他公共的時間表示相一致。
性能良好:支持針對所有訪問的域進(jìn)行最小的計算。
良好的測試覆蓋率:有全方位的測試人員保證庫的質(zhì)量、
具有完整文檔:有一個完整的用戶指南,該指南提供了一個概述,涵蓋常見的使用場景。javadoc 非常詳細(xì),涵蓋API的其余部分。
發(fā)展:自2002年以來積極發(fā)展,是一個成熟的可靠的代碼庫,一些相關(guān)的項目目前也是可用的。
開源:遵循Apache 2.0開源協(xié)議發(fā)布。
2.1.2 Joda-Time 的關(guān)鍵優(yōu)點
LocalDate:只包含日期
LocalTime:只包含時間
Instant:時間軸上的時間點
DateTime:時區(qū)中完整的日期和時間
DateTimeZone:更好的時區(qū)
Duration和Period:持續(xù)時間
Interval:兩個時間點之間的時間
全面并且靈活的時間格式化與轉(zhuǎn)換
正因為Joda-Time 與 Java8 之前的時間類庫相比,具備了如此多的優(yōu)點,所以 Joda-Time 成為事實上的標(biāo)準(zhǔn)的Java日期和時間庫。
2.2 特性解讀
2.2.1 Joda-Time和JDK的互操作性
互操作性是指:Joda 類能夠生成 java.util.Date 的實例(以及Calendar),這可以讓我們保留現(xiàn)有對JDK的依賴,又能夠使用Joda處理復(fù)雜的日期/時間計算。
Date To Joda-Time
Date date = new Date(); DateTime dateTime = new DateTime(date);
Canendar To Joda-Time
Calendar calendar = Calendar.getInstance(); DateTime dateTime = new DateTime(calendar);
Joda-Time To Date
Date date = new Date(); DateTime dateTime = new DateTime(date); Date date2 = dateTime.toDate();
Joda-Time To Calendar
Calendar calendar = Calendar.getInstance(); dateTime = new DateTime(calendar); Calendar calendar2 = dateTime.toCalendar(Locale.CHINA);
2.2.2 Joda的關(guān)鍵日期/時間概念理解
Joda 使用了以下概念,使得它們可以應(yīng)用到任何日期/時間庫:
不可變性(Immutability)
Joda-Time與java.lang.String類似,它們的實例均無法修改(因為任意對其值改變的操作都會生成新的對象),這也代表了它們是線程安全的。
瞬時性(Instant)
如接口 org.joda.time.ReadableInstant 中所表示的那樣,Instant 表示的是一個精確的時間點,是從 epoch:1970-01-01T00:00:00Z 開始計算的毫秒數(shù),這也的設(shè)計也使得其子類都可以與JDK Date 以及 Calendar 類兼容。
/** * Defines an instant in the datetime continuum. * This interface expresses the datetime as milliseconds from 1970-01-01T00:00:00Z. ** The implementation of this interface may be mutable or immutable. * This interface only gives access to retrieve data, never to change it. *
* Methods in your application should be defined using
ReadableInstant
* as a parameter if the method only wants to read the instant without needing to know * the specific datetime fields. ** The {@code compareTo} method is no longer defined in this class in version 2.0. * Instead, the definition is simply inherited from the {@code Comparable} interface. * This approach is necessary to preserve binary compatibility. * The definition of the comparison is ascending order by millisecond instant. * Implementors are recommended to extend {@code AbstractInstant} instead of this interface. * * @author Stephen Colebourne * @since 1.0 */ public interface ReadableInstant extends Comparable
{ /** * Get the value as the number of milliseconds since * the epoch, 1970-01-01T00:00:00Z. * * @return the value as milliseconds */ long getMillis(); ······ }
局部性(Partial)
瞬時性表達(dá)的是與epoch相對的時間上的一個精確時刻,而一個局部時間指的是一個時間的一部分片段,其可以通過一些方法使得時間產(chǎn)生變動(本質(zhì)上還是生成了新的類),這樣可以把它當(dāng)做重復(fù)周期中的一點,用到多個地方。
年表(Chronology)
Joda-Time的設(shè)計核心就是年表(org.joda.time.Chronology),從根本上將,年表是一種日歷系統(tǒng),是一種計算時間的特殊方式,并且在其中執(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)的計算引擎,是可插拔的實現(xiàn)。
時區(qū)(Time zone)
具體定義詳見百科解釋,在實際編碼過程中任何嚴(yán)格的時間計算都必須涉及時區(qū)(或者相對于GMT),Joda-Time中對應(yīng)的核心類為org.joda.time.DateTimeZone,雖然日常的使用過程中,并未涉及到對時區(qū)的操作,但是DateTimeZone如何對DateTime產(chǎn)生影響是比較值得注意的,此處不進(jìn)行贅述。
2.3 具體使用方法
上面介紹我完了Joda-Time的一些概念,接下來具體使用我們來進(jìn)行說明:
2.3.1 創(chuàng)建 Joda-Time 對象
瞬時性-ReadableInstant
// 1.使用系統(tǒng)時間 DateTime dateTime1 = new DateTime(); // 2.使用jdk中的date Date jdkDate1 = new Date(); DateTime dateTime2 = new DateTime(jdkDate1); // 3.使用毫秒數(shù)指定 Date jdkDate2 = new Date(); long millis = jdkDate.getTime(); DateTime dateTime3 = new DateTime(millis); // 4.使用Calendar Calendar calendar = Calendar.getInstance(); DateTime dateTime4 = new DateTime(calendar); // 5.使用多個字段指定一個瞬間時刻(局部時間片段) // year month day hour(midnight is zero) minute second milliseconds DateTime dateTime5 = new DateTime(2000, 1, 1, 0, 0, 0, 0); // 6.由一個DateTime生成另一個DateTime DateTime dateTime6 = new DateTime(dateTime1); // 7.有時間字符串生成DateTime String timeString = "2019-01-01T00:00:00-06:00"; DateTime dateTime7 = DateTime.parse(timeString);
局部性-ReadablePartial
當(dāng)程序中處理的日期、時間并不需要是完整時刻的時候,可以創(chuàng)建一個局部時間,比如只希望專注于年/月/日, 或者一天中的時間,或者是一周中的某天。Joda-Time中有表示這些時間的是org.joda.time.ReadablePartial接口,實現(xiàn)它的兩個類LocalDate和LocalTime是分別用來表示年/月/日和一天中的某個時間的。
// 顯示地提供所含的每個字段 LocalDate localDate = new LocalDate(2019, 1, 1); // 6:30:06 PM LocalTime localTime = new LocalTime(18, 30, 6, 0);
LocalDate是替代了早期Joda-Time版本中使用的org.joda.time.YearMonthDay,LocalTime是替代早期版本的org.joda.time.TimeOfDay。(均已被標(biāo)注為過時狀態(tài))。
時間跨度
Joda-Time提供了三個類用于表示時間跨度(在某些業(yè)務(wù)需求中,它們可能會非常有用)。
Duration
這個類表示以毫秒為單位的絕對精度,提供標(biāo)準(zhǔn)數(shù)學(xué)轉(zhuǎn)換的方法,同時把時間跨度轉(zhuǎn)換為標(biāo)準(zhǔn)單位。
Period
這個類表示以年月日單位表示。
Interval
這個類表示一個特定的時間跨度,使用一個明確的時刻界定這段時間跨度的范圍。Interval 為半開 區(qū)間,所以由其封裝的時間跨度包括這段時間的起始時刻,但是不包含結(jié)束時刻。
2.3.2 使用Joda-Time的方法處理時間
DateTime today = new DateTime(); // 獲取777秒之前的時間 DateTime dateTime1 = today.minus(777 * 1000); // 獲取明天的時間 DateTime tomorrow = today.plusDays(1); // 獲取當(dāng)月第一天的日期 DateTime dateTime2 = today.withDayOfMonth(1); // 獲取當(dāng)前時間三個月后的月份的最后一天 DateTime dateTime3 = today.plusMonths(3).dayOfMonth().withMaximumValue();
下面列出部分DateTime方法列表: plus/minus開頭的方法(比如:plusDay, minusMonths):用來返回在DateTime實例上增加或減少一段時間后的實例
plus(long duration) 增加指定毫秒數(shù)并返回
plusYears(int years) 增加指定年份并返回
plusMonths(int months) 增加指定月份并返回
plusWeeks(int weeks) 增加指定星期并返回
plusDays(int days) 增加指定天數(shù)并返回
plusHours(int hours) 增加指定小時并返回
plusMinutes(int minutes) 增加指定分鐘并返回
plusSeconds(int seconds) 增加指定秒數(shù)并返回
plusMillis(int millis) 增加指定毫秒并返回
與之相反的是minus前綴的 plus是增加 minus是減少
with開頭的方法:用來返回在DateTime實例更新指定日期單位后的實例
withCenturyOfEra(int centuryOfEra) 更新時間世紀(jì)單位并返回
withYearOfCentury(int yearOfCentury)更新世紀(jì)年并返回
withYear(int year) 更新時間年并返回
withWeekyear(int weekyear) 更新時間周數(shù)并返回
withMonthOfYear(int monthOfYear)更新時間月份并返回
withDayOfYear(int dayOfYear) 更新時間天數(shù)并返回
withDayOfMonth(int dayOfMonth) 更新時間天數(shù)并返回
withDayOfWeek(int dayOfWeek) 更新時間天數(shù)并返回
withHourOfDay(int hour) 更新時間小時并返回
withMinuteOfHour(int minute) 更新時間分鐘并返回
withSecondOfMinute(int second) 更新時間秒數(shù)并返回
withMillisOfSecond(int millis) 更新時間毫秒并返回
withMillisOfDay(int millis) 更新時間毫秒并返回
withTimeAtStartOfDay() 獲取當(dāng)天最早時間
判斷DateTime對象大小狀態(tài)的一些操作方法
compareTo(DateTime d) 比較兩時間大小 時間大于指定時間返回 1 時間小于指定時間返回-1 相等返回0
equals(DateTime d) 比較兩時間是否相等
isAfter(long instant) 判斷時間是否大于指定時間
isAfterNow() 判斷時間是否大于當(dāng)前時間
isBefore(long instant) 判斷時間是否小于指定時間
isBeforeNow() 判斷時間是否小于當(dāng)前時間
isEqual(long instant) 判斷時間是否等于指定時間
isEqualNow() 判斷時間是否等于當(dāng)前時間
2.3.3 以Joda-Time的方式格式化時間
// 傳入的格式化模板只需與JDK SimpleDateFormat兼容的格式字符串即可 public static String convert(Date date,String dateFormat){ return new DateTime(date).toString(dateFormat); } // 將JDK中的Date轉(zhuǎn)化為UTC時區(qū)的DateTime DateTime dateTime = new DateTime(new Date(), DateTimeZone.UTC); // 將String轉(zhuǎn)換為DateTime public static Date convertUTC2Date(String utcDate){ DateTime dateTime =DateTime.parse(utcDate, DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); return dateTime.toDate(); }
更多使用方法請參考官方文檔。
三、JAVA 8中新的時間類庫
3.1 簡介
由于JDK之前版本的類庫的缺陷和糟糕的使用體驗,再加上已經(jīng)成為事實標(biāo)準(zhǔn)Joda-Time的影響力,Oracle決定在JAVA API中提供高質(zhì)量的日期和時間支持,這也就是整合了大部分Joda-Time特性的JDK 8新的時間類庫。(Joda-Time的作者實際參與開發(fā),并且實現(xiàn)了JSR310的全部內(nèi)容,新的API位于java.time下。常用的類有以下幾個:LocalDate、LocalTime、Instant、Duration和Period。)
由于JDK 8 新的時間類庫大量借鑒了Joda-Time的設(shè)計思想乃至命名,因此如果你是Joda-Time的使用者,那你可以無學(xué)習(xí)成本的使用新的API(當(dāng)然,它們之間也存在些許差別需要注意到)。
3.2 使用方法
3.2.1 使用LocalDate 和LocalTime
首先是LocalDate,該類的實例是一個不可變對象,它只提供了簡單的日期,并不含當(dāng)天的時間信息。另外,它也不附帶任何與時區(qū)相關(guān)的信息。
// 使用指定的日期創(chuàng)建LocalDate LocalDate date = LocalDate.of(2019, 1, 1); // 獲取當(dāng)前日期 LocalDate today = LocalDate.now(); // 獲取今日的屬性 int year = date.getYear(); Month month = date.getMonth(); int day = date.getDayOfMonth(); DayOfWeek dow = date.getDayOfWeek(); int len = date.lengthOfMonth(); boolean leap = date.isLeapYear(); // 通過ChronoField的枚舉值獲取需要的屬性字段 int year = date.get(ChronoField.YEAR);
接著是LocalTime,它表示了一天內(nèi)的某個時刻。
LocalTime time = LocalTime.of(18, 18, 18); int hour = time.getHour(); int minute = time.getMinute(); int second = time.getSecond();
LocalDate和LocalTime都可以通過使用靜態(tài)方法parse來解析字符串進(jìn)行創(chuàng)建。
LocalDate date = LocalDate.parse("2019-01-01"); LocalTime time = LocalTime.parse("18:18:18");
也可以向parse方法傳遞一個DateTimeFormatter,該類的實例定義了如何格式化一個日期或者時間對象。它其實是老版java.util.DateFormat的替代品。
3.2.2 LocalDateTime
// 直接創(chuàng)建LocalDateTime LocalDateTime dt1 = LocalDateTime.of(2019, Month.JANUARY, 1, 18, 18, 18); // 合并日期和時間 LocalDate date = LocalDate.parse("2019-01-01"); LocalTime time = LocalTime.parse("18:18:18"); LocalDateTime dt2 = LocalDateTime.of(date, time); LocalDateTime dt3 = date.atTime(18, 18, 18); LocalDateTime dt4 = date.atTime(time); LocalDateTime dt5 = time.atDate(date); // 從LocalDateTime中提取LocalDate或者LocalTime LocalDate date1 = dt1.toLocalDate(); LocalTime time1 = dt1.toLocalTime();
3.3.3 Instant
Instant類是為了方便計算機(jī)理解的而設(shè)計的,它表示一個持續(xù)時間段上某個點的單一大整型數(shù),實際上它是以Unix元年時間(傳統(tǒng)的設(shè)定為UTC時區(qū)1970年1月1日午夜時分)開始所經(jīng)歷的秒數(shù)進(jìn)行計算(最小計算單位為納秒)。
// 傳遞一個秒數(shù)已創(chuàng)建該類的實例 Instant.ofEpochSecond(3); // 傳遞一個秒數(shù)+納秒 2 秒之后再加上100萬納秒(1秒) Instant.ofEpochSecond(2, 1_000_000_000);
3.3.4 Duration與Period
Duration是用于比較兩個LocalTime對象或者兩個Instant之間的時間差值。
Duration d1 = Duration.between(time1, time2); Duration d1 = Duration.between(dateTime1, dateTime2); Duration d2 = Duration.between(instant1, instant2);
Period是用于對年月日的方式對多個時間進(jìn)行比較。
Period tenDays = Period.between(LocalDate.of(2019, 1, 1), lcalDate.of(2019, 2, 2));
當(dāng)然,Duration和Period類都提供了很多非常方便的工廠類,直接創(chuàng)建對應(yīng)的實例。
Duration threeMinutes = Duration.ofMinutes(3); Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES); Period tenDays = Period.ofDays(10); Period threeWeeks = Period.ofWeeks(3); Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
3.3.5 操作、解析和格式化日期
// 直接使用withAttribute的方法修改 LocalDate date1 = LocalDate.of(2019, 1, 1); LocalDate date2 = date1.withYear(2019); LocalDate date3 = date2.withDayOfMonth(1); LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 1);
所有聲明了Temporal接口的類LocalDate、LocalTime、LocalDateTime以及Instant,它們都使用get和with方法,將對象值的讀取和修改區(qū)分開,如果使用了不支持的字段訪問字段,會拋出一個UnsupportedTemporalTypeException異常。類似的,plus方法和minus方法都聲明于Temporal接口。通過這些方法,對TemporalUnit對象加上或者減去一個數(shù)字,我們能非常方便地將Temporal對象前溯或者回滾至某個時間段,通過ChronoUnit枚舉我們可以非常方便地實現(xiàn)TemporalUnit接口。
3.3.6 更多定制化的處理時間
向重載的with方法傳遞一個定制化的TemporalAdjuster對象,可以更加靈活地處理日期。時間和日期的API已經(jīng)提供了大量預(yù)定義的TemporalAdjuster,可以通過TemporalAdjuster類的靜態(tài)工廠方法訪問它們。這些方法的名稱非常直觀,方法名就是問題描述。某些情況下,如果你需要定義自己的TemporalAdjuster,只需要聲明TemporalAdjuster接口并且自己實現(xiàn)對應(yīng)的方法即可。
LocalDate date1 = LocalDate.of(2014, 3, 18); LocalDate date2 = date1.with(TemporalAdjuster.nextOrSame(DayOfWeek.SUNDAY)); LocalDate date3 = date2.with(TemporalAdjuster.lastDayOfMonth());
3.3.7 解析日期-時間對象
日常工作中,格式化以及解析日期-時間對象是另一個非常重要的功能,而新的java.time.format包就是特別為我們達(dá)到這個目的而設(shè)計的。這其中,最重要的類是DateTimeFormatter。所有的DateTimeFormatter實例都能用于以一定的格式創(chuàng)建代表特定日期或時間的字符串。(與老的java.util.DateFormat相比較,所有的DateTimeFormatter實例都是線程安全的)
// 使用不同的格式器生成字符串
LocalDate date = LocalDate.of(2019, 1, 1);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
// 生成LocalDate對象
LocalDate date1 = LocalDate.parse("20190101", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2019-01-01", DateTimeFormatter.ISO_LOCAL_DATE);
// 使用特定的模式創(chuàng)建格式器 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); LocalDate date1 = LocalDate.of(2019, 1, 1); String formattedDate = date1.format(formatter); LocalDate date2 = LocalDate.parse(formattedDate, formatter);
3.3.8 處理不同的時區(qū)和日歷系統(tǒng)
在新的日期-時間類庫中,為了最大程度上的減少在處理時區(qū)帶來的繁瑣和復(fù)雜而使用了新的java.time.ZoneId類(與其他日期和時間類一樣,ZoneId類也是無法修改的) 來替代老版的java.util.TimeZone。時區(qū)是按照一定的規(guī)則將區(qū)域劃分成標(biāo)準(zhǔn)時間相同的區(qū)間。在ZoneRules這個類中包含了40個這樣的實例。可以簡單地通過調(diào)用ZoneId的getRules()得到指定時區(qū)的規(guī)則。每個特定的ZoneId對象都由一個地區(qū)ID標(biāo)識,地區(qū)ID都為“{區(qū)域}/{城市}”的格式。比如:
ZoneId romeZone = ZoneId.of("Asia/Shanghai");
Java 8中在原先的TimeZone中加入了新的方法toZoneId,其作用是將一個老的時區(qū)對象轉(zhuǎn)換為ZoneId:
ZoneId zoneId = TimeZone.getDefault().toZoneId();
得到的ZoneId對象后可以將它與LocalDate、LocalDateTime或者是Instant對象整合起來,構(gòu)造為一個ZonedDateTime實例,它代表了相對于指定時區(qū)的時間點:
LocalDate date = LocalDate.of(2019, Month.JANUARY, 1); ZonedDateTime zdt1 = date.atStartOfDay(romeZone); LocalDateTime dateTime = LocalDateTime.of(2019, Month.JANUARY, 18, 13, 45); ZonedDateTime zdt2 = dateTime.atZone(romeZone); Instant instant = Instant.now(); ZonedDateTime zdt3 = instant.atZone(romeZone);
通過ZoneId,還可以將LocalDateTime轉(zhuǎn)換為Instant:
LocalDateTime dateTime = LocalDateTime.of(2019, Month.JANUARY, 18, 13, 45); Instant instantFromDateTime = dateTime.toInstant(romeZone);
同樣可以通過反向的方式得到LocalDateTime對象:
Instant instant = Instant.now(); LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);
與Joda-Time所不同的是,Java8中的日期-時間類庫提供了4種其他的日歷系統(tǒng),這些日歷系統(tǒng)中的每一個都有一個對應(yīng)的日志類,分別是ThaiBuddhistDate、MinguoDate 、JapaneseDate 以及HijrahDate 。所有這些類以及LocalDate 都實現(xiàn)了ChronoLocalDate接口,能夠?qū)珰v的日期進(jìn)行建模。利用LocalDate對象,你可以創(chuàng)建這些類的實例。同樣的,利用它們提供的靜態(tài)工廠方法,你可以創(chuàng)建任何一個Temporal對象的實例。
LocalDate date = LocalDate.of(2019, Month.JANUARY, 1); JapaneseDate japaneseDate = JapaneseDate.from(date);
參考資料
Joda-Time 簡介 Joda Time項目和java8時間api
動態(tài)計算時間段
需求:如現(xiàn)在是13:00,則時間段為15:10-17:10、17:10-19:10、19:10-21:10;即最早的出發(fā)時間為當(dāng)前時間+參數(shù)【2h20min】,最遲的時間段為開始時間在20點前結(jié)束時間在20點后的時間段),求解共有多少個時間段?
分析:
第一個時間段的開始時間:當(dāng)前時間+參數(shù)【2h20min】,中間的時間段是2h;
通過理解這句:最遲的時間段為開始時間在20點前結(jié)束時間在20點后的時間段,我們可以假設(shè)最大的時間變量為 max
假設(shè)當(dāng)前時間為now,總共有n個時間段,可以推導(dǎo)出公式:now + (2h * n) + 10min <= max;
注意:計算過程都轉(zhuǎn)換成毫秒
public class Test { // 毫秒 static final long slot = 130 * 60 * 1000; private static ListbuildStartEndTime(Long now, Long max) { // now + (2h * n) + 10min <= max; Long n = (max - now - 60 * 1000) / (120 * 60 * 1000); System.out.println("max:" + max); System.out.println("now:" + now); System.out.println(" max - now:" + (max - now)); System.out.println("n:" + n); List timeSelectItems = new ArrayList<>(); Long startTimestamp = now + slot; Long endTimestamp = startTimestamp + 120 * 60 * 1000; for (int i = 1; i <= n; i++) { // 起始時間 // startTimestamp = startTimestamp + i * (120 * 60 * 1000); // 結(jié)束時間 endTimestamp = startTimestamp + (120 * 60 * 1000); System.out.println(startTimestamp); System.out.println(endTimestamp); TimeSelectItem item = new TimeSelectItem(); DateTime dt = new DateTime(startTimestamp); int hour = dt.hourOfDay().get(); int millis = dt.getMinuteOfHour(); String startTag = hour + ":" + millis; DateTime dt1 = new DateTime(endTimestamp); int hour1 = dt1.hourOfDay().get(); long millis1 = dt1.getMinuteOfHour(); String enTag = hour1 + ":" + millis1; item.setDisplayName(startTag + " - " + enTag); item.setStartTimestamp(startTimestamp); item.setEndTimestamp(endTimestamp); timeSelectItems.add(item); startTimestamp = endTimestamp; } return timeSelectItems; } public static void main(String[] args) { Long start = DateTime.now().getMillis(); Calendar c = Calendar.getInstance(); c.setTime(new Date()); c.set(Calendar.HOUR_OF_DAY, 20); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); DateTime dt = new DateTime(); dt.withHourOfDay(20); Long end = c.getTimeInMillis(); // List list = buildStartEndTime(1614747600000L, 1614772800000L); List list = buildStartEndTime(1614834000000L, end); for (TimeSelectItem item : list ) { System.out.println(item); } } }
到此,相信大家對“如何使用Java時間操作類庫Joda-Time”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!