Java中,現有的與日期和時間相關的類存在諸多問題,其中有:
- Java的日期/時間類的定義并不一緻,在java.util和java.sql的包中都有日期類,此外用于格式化和解析的類在java.text包中定義。
- java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,将其納入java.sql包并不合理。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計。
- 對于時間、時間戳、格式化以及解析,并沒有一些明确定義的類。對于格式化和解析的需求,我們有java.text.DateFormat抽象類,但通常情況下,SimpleDateFormat類被用于此類需求。
- 所有的日期類都是可變的,是以他們都不是線程安全的,這是Java日期類最大的問題之一。
- 日期類并不提供國際化,沒有時區支援,是以Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題。
Java8日期/時間API包含以下相應的包:
- java.time包:這是新的Java日期/時間API的基礎包,所有的主要基礎類都是這個包的一部分,如:LocalDate,LocalTime,LocalDateTime,Instant,Period,Duration等等。所有這些類都是不可變的和線程安全的,在絕大多數情況下,這些類能夠有效地處理一些公共的需求。
- java.time.chrono包:這個包為非ISO的月曆系統定義了一些泛化的API,我們可以擴充AbstractChronology類來建立自己的月曆系統。
- java.time.format包:這個包包含能夠格式化和解析日期時間對象的類,在絕大多數情況下,我們不應該直接使用它們,因為java.time包中相應的類已經提供了格式化和解析的方法。
- java.time.temporal包:這個包包含一些時态對象,我們可以用其找出關于日期/時間對象的某個特定日期或時間,比如說,可以找到某月的第一天或最後一天。你可以非常容易地認出這些方法,因為它們都具有“withXXX”的格式。
- java.time.zone包:這個包包含支援不同時區以及相關規則的類。
Java8日期時間的預設格式如下:yyyy-MM-dd-HH-mm-ss.zzz
幾個主要的核心類:
- LocalDate:日期類
- LocalTime:時間類
- LocalDateTime:日期時間類
- ZonedDateTime:時區日期時間類
- OffsetDateTime:按UTC時間偏移來得到日期時間
- Instant:Unix時間
- Duration:兩個時間之間
- Period:兩個日期之間
- ZoneId:時區
- DateTimeFormatter:格式化輸出
- TemporalAdjusters:獲得指定日期時間等,如當月的第一天、今年的最後一天等等
//相容老API,Instant類是橋梁
@Test
public void testCompatibility() {
Date dt = Date.from(Instant.now());
Instant timestamp = new Date().toInstant();
LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("PST")));
Instant time = Calendar.getInstance().toInstant();
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
TimeZone tz = TimeZone.getTimeZone(defaultZone);
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
}
@Ignore
@Test
public void testFormat() {
LocalDate date = LocalDate.now();
System.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));
System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
LocalDateTime dt = LocalDateTime.parse("27::4::2014 21::39::48",
DateTimeFormatter.ofPattern("d::M::uuuu HH::mm::ss"));
System.out.println("Default format after parsing = " + dt);
}
@Ignore
@Test
public void testDateApi() {
LocalDate today = LocalDate.now();
System.out.println("Year " + today.getYear() + " is Leap Year? " + today.isLeapYear());
System.out.println("Today is before 01/01/2015? " + today.isBefore(LocalDate.of(, , )));
System.out.println("Current Time=" + today.atTime(LocalTime.now()));
System.out.println("10 days after today will be " + today.plusDays());
System.out.println("3 weeks after today will be " + today.plusWeeks());
System.out.println("20 months after today will be " + today.plusMonths());
System.out.println("10 days before today will be " + today.minusDays());
System.out.println("3 weeks before today will be " + today.minusWeeks());
System.out.println("20 months before today will be " + today.minusMonths());
System.out.println("First date of this month= " + today.with(TemporalAdjusters.firstDayOfMonth()));
LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
System.out.println("Last date of this year= " + lastDayOfYear);
Period period = today.until(lastDayOfYear);
System.out.println("Period Format= " + period);
System.out.println("Months remaining in the year= " + period.getMonths());
}
@Ignore
@Test
public void testInstant() {
Instant timestamp = Instant.now();
System.out.println("Current Timestamp = " + timestamp);
System.out.println(timestamp.toEpochMilli());
Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
System.out.println("Specific Time = " + specificTime);
Duration thirtyDay = Duration.ofDays();
System.out.println(thirtyDay);
}
@Ignore
@Test
public void testDateTime() {
LocalDateTime today = LocalDateTime.now();
System.out.println("Current DateTime=" + today);
today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("Current DateTime=" + today);
LocalDateTime specificDate = LocalDateTime.of(, Month.JANUARY, , , , );
System.out.println("Specific Date=" + specificDate);
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("Current Date in IST=" + todayKolkata);
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(, , ZoneOffset.UTC);
System.out.println("10000th second time from 01/01/1970= " + dateFromBase);
}
@Ignore
@Test
public void testTime() {
LocalTime time = LocalTime.now();
System.out.println("Current Time=" + time);
LocalTime specificTime = LocalTime.of(, , , );
System.out.println("Specific Time of Day=" + specificTime);
LocalTime timeKolkata = LocalTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("Current Time in IST=" + timeKolkata);
LocalTime specificSecondTime = LocalTime.ofSecondOfDay();
System.out.println("10000th second time= " + specificSecondTime);
}
@Ignore
@Test
public void testDate() {
LocalDate today = LocalDate.now();
System.out.println("Current Date=" + today);
LocalDate firstDay_2014 = LocalDate.of(, Month.JANUARY, );
System.out.println("Specific Date=" + firstDay_2014);
LocalDate todayKolkata = LocalDate.now(ZoneId.of("Asia/Kolkata"));
System.out.println("Current Date in IST=" + todayKolkata);
LocalDate dateFromBase = LocalDate.ofEpochDay();
System.out.println("365th day from base date= " + dateFromBase);
LocalDate hundredDay2014 = LocalDate.ofYearDay(, );
System.out.println("100th day of 2014=" + hundredDay2014);
}