日期和API
Java1.0對日期和時間的支持只能依賴java.util.Date類,年份的起始選擇是1900你那,月份的起始是從0開始計算的。它的返回值中包含了JVM的默認市區CET,即中歐時間。在Java1.1中使用java.util.Calendar類替代Date。同時格式化和解析日期的DateFormat也只存在於Date中,並且線程不安全。Date和Calendar都是可變的。Java8在java.time中整合了很多Joda-Time的特性。
java.time提供了LocalDate,LocalTime,Instant,Duration和Period。
LocalDate和LocalTime
LocalDate和LocalTime的實例都是一個不可變對象,LocalDate只提供了簡單的日期,並不包含當天的時間信息,它也不附帶任何跟時區相關任何信息。LocalTime只提供了時間。
TemporalField是一個接口,它可以定義訪問temporal對象某個字段的值。ChronoField枚舉實現了這個接口,可以使用LocalDate.get(ChronoField)獲取某個枚舉元素的值。
int year = LocalDate.now().get(ChronoField.YEAR);
LocalDate和LocalTime都可以通過parse()方法解析代表它們的字符串創建。也可以向parse()方法傳遞一個DateTimeFormatter,它是替換java.util.DateFormat的替代品。一旦傳遞的字符串參數無法被解析為合法的LocalDate或LocalTime對象,這兩個parse方法都會拋出DateTimeParseException異常。
LocalDate date = LocalDate.parse("2017-07-24");
LocalTime time = LocalTime.parse("12:25:05");
LocalDateTime
LocalDateTime是LocalDate和LocalTime的合體,表示了日期和時間,但不帶有時區。可以LocalDate和LocalTime可以通過atTime()和atDate()方法創建一個LocalDateTime對象,也可調用LocalDateTime的toLocalDate()和toLocalTime()方法生成LocalDate和LocalTime對象。
LocalDateTime dateTime = LocalDateTime.of(2017, Month.JULY, 24, 11, 11, 11);
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime1 = LocalDateTime.of(date, time);
LocalDateTime dateTime2 = date.atTime(11, 11);
LocalDateTime dateTime3 = date.atTime(time);
LocalDateTime dateTime4 = time.atDate(date);
LocalDate date1 = dateTime.toLocalDate();
LocalTime time1 = dateTime1.toLocalTime();
從計算機的角度來看,建模時間最自然的格式是表示一個持續時間段上某個點的單一大整型數。java.time.Instant類對時間建模的方式是以Unix元年時間開始所經歷的秒數進行計算。可以通過靜態工廠方法ofEpochSecond傳遞一個代表描述的值創建一個該類的實例,它也可以接收第二個以秒為單位的參數值,對傳入作為描述的參數進行調整。重載的版本會調整納秒參數,確保保存的納秒分片在0到999999傳入作為秒數的參數進行調整。Instant類支持靜態工廠方法now,它能夠幫你獲取當前時刻的時間戳。
Instant.ofEpochSecond(3);
Instant.ofEpochSecond(2, 1000000000); //2s後再加上1s
Instant.ofEpochSecond(2, -1000000000); //2s之前1s
Duration或Period
Temporal接口定義了如何讀取和操縱為時間建模的對象的值。Duration類的靜態工廠between可以計算兩個Temporal對象之間的duration。
Duration d1 = Duration.between(time1, time2);
Duration d2 = Duration.between(datetime1, datetime2);
Duration d3 = Duration.between(instant1, instant1);
若試圖在Instant和LocalDateTime對象之間創建duration,會觸發DateTimeException異常。
若需要以年,月或日的方式對多個時間建模,可以用Period類。
Period tenDays = Period.between(LocalDate.of(2014, 3, 18), LocalDate.of(2014, 3, 18));
static between 創建兩個時間點之間的interval
static from 由一個臨時時間點創建interval
static of 由它的組成部分創建interval實例
static parse 由字符串創建interval的實例
addTo 創建該interval的副本,並將其疊加到某個指定的temporal對象
get 讀取該interval的副本,並將其疊加到某個指定的temporal對象
isNegative 檢查該interval是否為負值,不包含0
isZero 檢查該interval的時常是否為0
minus 通過減去一定的時間創建該interval的副本
multipliedPlay 將interval的值乘以某個標量創建該interval的副本
negated 以忽略某個時長的方式創建該interval副本
plus 以增加某個指定的時長的方式創建該interval的副本
substractFrom 從指定的temporal對象中減去該interval
創建一個LocalDate對象的修改版,最簡單的方式withAttribute方法。withAttribute方法對創建對象的一個副本,並按照需要修改它的屬性。通過使用get和with方法,可以將Temporal對象值讀取和修改區分開。若Temporal對象不支持請求訪問的字段,它會拋出一個UnsupportedTemporalTypeException異常。
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.withYear(2011);
LocalDate date3 = date2.withDayOfMonth(25);
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);
表示時間點的日期-時間類的通用方法
static from 依據傳入的Temporal對象創建對象實例
static now 依據系統時鐘創建Temporal對象
static of 由Temporal鍍錫愛過你的某個部分創建該對象的實例
static parse 由字符串創建Temporal對象的實例
atOffset 將Temporal對象和某個時區偏移相結合
atZone 將Temporal對象和某個時區相結合
format 使用某個指定的格式將Temporal對象轉換為字符串
get 讀取Temporal對象的某一部分的值
minus 創建Temporal對象的一個副本,通過將當前的Temporal對象的值減去一定時長創建該副本
plus 創建Temporal對象的一個副本,通過將當前的Temporal對象的值加上一頂時長創建該副本
with 以該Temporal對象為模板,對某些狀態進行修改創建該對象的副本
TemporalAdjuster
LocalDate的with方法可以接受一個TemporalAdjuster對象。
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
TemporalAdjuster類中的工廠方法
dayOfWeekInMonth 創建一個新的日期,它的值為同一個月中每一周的第幾天
firstDayOfMonth 創建一個新的日期,它的值為當月的第一天
firstDayOfNextMonth 創建一個新的日期,它的值為下月的第一天
firstDayOfNextYear 創建一個新的日期,它的值為明年的第一天
firstDayOfYear 創建一個新的日期,它的值為當年的第一天
firstInMonth 創建一個新的日期,它的值為當月的第一天
lastDayOfMonth 創建一個新的日期,它的值為當月的最後一天
lastDayOfNextMonth 創建一個新的日期,它的值為下個月的最後一天
lastDayOfNextYear 創建一個新的日期,它的值為明年的最後一天
lastDayOfYear 創建一個新的日期,它的值為今年最後一天
lastInMonth 創建一個新的日期,它的值為同一個月中,最後一個符合星期幾要求的值
next/previous 創建一個新的日期,並將其設定為日期調整後或者調整前,第一個符合指定星期內要求的日期
nextOrSame/previousOrSame 創建一個新的日期,並將其值設定為日期調整後或調整前,第一個符合指定星期幾要求的日期,若該日期已經符合要求,直接返回該對象
[email protected]
public interface TemporalAdjuster{
Temporal adjustInto(Temporal temporal);
}
public class NextWorkingDay implements TemproalAdjuster{ public Temporal adjustInto(Temporal temporal){ DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); int dayOfAdd = 1; if( dow == DayOfWeek.FRIDAY) dayOfAdd = 3; else if( dow == DayOfWeek.SATURDAY){ dayOfAdd = 2; } return temporal.plus(dayToAdd, ChronoUnit.DAYS); } } date = date.with( temporal -> { public Temporal adjustInto(Temporal temporal){ DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); int dayOfAdd = 1; if( dow == DayOfWeek.FRIDAY) dayOfAdd = 3; else if( dow == DayOfWeek.SATURDAY){ dayOfAdd = 2; } return temporal.plus(dayToAdd, ChronoUnit.DAYS); }); TemporalAdjuster nextWorkingDay = TemporalAdjuster.ofDateAdjust( temporal -> { DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); int dayOfAdd = 1; if( dow == DayOfWeek.FRIDAY) dayOfAdd = 3; else if( dow == DayOfWeek.SATURDAY){ dayOfAdd = 2; } return temporal.plus(dayToAdd, ChronoUnit.DAYS); }); date = date.with(nextWorkingDay)
java.time.format用於格式化及解析日期-時間。DateTimeFormatter實例用於以一定的格式創建代表特定日期或時間的字符串,並且線程安全。
LocalDate date = LocalDate.of(2017, 8, 9);
String s1 = data.format(DateTimeFormatter.BASIC_ISO_DATE); //20170809
String s2 = data.format(DateTimeFormatter.ISO_LOCAL_DATE); //2017-08-09
LocalDate date1 = LocalDate.parse("20170809", DateTimeFormatter.BASIC_ISO_DATE);
DateTimeFormatter.ofPattern()方法可以按照某個特定的模式創建格式器,ofPattern()方法還可以創建某個Locale的格式器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
DateTimeFormatter italianFormatter = DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.ITALIAN);
java.time.ZoneId的目的是讓你無需為時區處理復雜和繁瑣操心。通過調用ZoneId.getRules()得到指定的市區規則。每個特定的ZoneId對象都由一個地區ID標識。
ZoneId romeZone = ZoneId.of("Europe/Rome");
地區ID都為“區域/城市”的格式,這些地區集合的設定都由英特網編號分配機構IANA的時區數據庫提供。可以通過toZoneId將一個老時區對象轉換為ZoneId。ZoneId與LocalDate,LocalDateTime或Instant整合可以得到ZonedDateTime實例
ZoneId zoneId = ZoneId.getDefault().toZoneId();
LocalDate date = LocalDate.of(2014, Month.MARCH, 10);
ZonedDateTime zdt = date.atStartOfDay(zoneId);
LocalDateTime datetime = LocalDateTime.of(2014, Month.MARCH, 10, 18, 13, 45);
zdt = datetime.atZone(romeZone);
Instant instant = Instant.now();
zdt = instant.atZone(romeZone);
Instant instantFromDateTime = dateTime.toInstant(romeZone);
LocalDateTime dateTimeFromInstant = LocalDateTime.ofInstant(instant, romeZone);
ISO-8601日歷系統是世界文明日歷系統的實施標準。Java8還提供呢了4種其它的日歷系統。分別是ThaiBuddhistDate,MinguoDate,JapaneseDate以及HijrahDate。這些類及LocalDate都實現了ChronoLocalDate接口。
LocalDate date = LocalDate.of(2014, Month.MARCH, 10);
JapeneseDate jDate = JapeneseDate.from(date);
Chronology japaneseChronology = Chronology.ofLocale(Locale.JANPAN);
ChronoLocalDate now = japaneseChronology.dateNow();
日期和API