Java8 time3. Date
•雖然叫 Date, 但實際上是 timestamp,
#toString 又帶有 time zone
•存取麻煩
•年是1900 + ?
•月份從 0 開始
•不支援國際化
•Unix time
5. Calendar.Builder
Calendar cal1 = new Calendar.Builder()
.setDate(2014, Calendar.MARCH, 29)
.build();
•Java 8 新增,讓建立和變更能方便一點
Calendar cal2 = new Calendar.Builder()
.setCalendarType("japanese")
.setFiled(YEAR, 1, DAY_OF_YEAR, 1)
.build();
11. Instant
Instant now = Instant.now();
//2014-03-29T14:23:25.223Z
now.toString();
//2014-03-29T14:23:28.223Z
now.plusSeconds(3);
//2014-03-27T14:23:25.223Z
now.minus(2, ChronoUnit.DAYS);
12. Duration
•顯示時間的量
•使用 seconds 和 nanoseconds 表示
•toString 結果會是 PTnHnMnS
•顯示時可以用 hours,minutes,seconds
和 nanoseconds
•用 of 建立
Duration.ofHours(2);
Duration.ofDays(1);
13. •從兩個 Temporal 取得
!
•有 Day 相關的方法,但 邊的 Day 就是 24
Hours 的意思
// 兩個參數都必須支援 ChronoUnit.SECONDS
Duration.between(LocalDateTime.now(),
LocalDateTime.now().plusDays(2));
!
!
!
// 現在時間加 24
LocalDateTime.now().plus(
Duration.ofDays(1));
17. LocalDate
LocalDate now = LocalDate.now();
now.toString(); // 2014-03-29
now.getDayOfWeek(); // SATURDAY
now.getDayOfMonth(); // 29
now.isLeapYear(); // false
// 2014-04-10
now.plusDays(12).toString();
18. LocalTime
LocalTime now = LocalTime.now();
now.toString(); // 14:20:42.270
now.getHour(); // 14
now.getMinute(); // 20
LocalTime.MIDNIGHT; // 00:00
20. •LocalDate <=> LocalDateTime
Local 之間的轉換
LocalDate localDate =
LocalDate.now();
// LocalDate to LocalDateTime
LocalDateTime localDateTime =
localDate.atTime(14, 20, 20);
// LocalDateTime to LocalDate
localDate =
localDateTime.toLocalDate();
21. •LocalTime <=> LocalDateTime
LocalTime localTime =
LocalTime.now();
// LocalTime to LocalDateTime
LocalDateTime localDateTime =
localTime.atDate(
LocalDate.of(2014, 3, 29));
// LocalDateTime to LocalTime
localTime =
localDateTime.toLocalTime();
23. ZonedDateTime dateTime =
ZonedDateTime.of(
LocalDate.of(1975, 3, 31),
LocalTime.of(23, 0),
ZoneId.of("Asia/Taipei"));
!
//1975-03-31T23:00+08:00[Asia/Taipei]
dateTime.toString();
//1975-04-01T01:00+09:00[Asia/Taipei]
dateTime.plusHours(1);
•台灣1975日光節約時間爲4月1日到9月30日
24. ZonedDateTime dateTime =
ZonedDateTime.of(
LocalDate.of(1979, 6, 30),
LocalTime.of(23, 0),
ZoneId.of("Asia/Taipei"));
!
//1979-06-30T23:00+09:00[Asia/Taipei]
dateTime.toString();
•台灣1979日光節約時間爲7月1日到9月30日
26. Time zone data
•tz database 有世界時區的分類和命名
•IANA Time Zone Database (TZDB)
•$JDK_HOME/jre/lib/tzdb.dat
•透過 ZoneRulesProvider 讀取
•一直有更新,所以記得要持續更新 JRE 或透
過 Oracle 提供的工具更新
28. public static boolean refresh() {
boolean changed = false;
for (ZoneRulesProvider provider : PROVIDERS) {
changed |= provider.provideRefresh();
}
return changed;
}
•ZoneRulesProvider.refresh
29. public static boolean refresh() {
boolean changed = false;
for (ZoneRulesProvider provider : PROVIDERS) {
changed |= provider.provideRefresh();
}
return changed;
}
•ZoneRulesProvider.refresh
•回傳的 boolean 可以讓應用程式知道有沒有更新
•系統預設的 provider#provideRefresh 是回傳 false
31. DateTime 之間的轉換
•LocalDateTime, LocalDate, LocalTime
•OffsetDateTime, OffsetTime
•ZonedDateTime
•補足需要的資 或拿掉多餘的資 就可以彼此
間轉換
ZonedDateTime zdt = LocalDateTime.now()
.atZone(ZoneId.of(“Asia/Taipei”));
LocalDateTime ldt = zdt.toLocalDateTime();
33. // 兩個參數都是 LocalDate
Period.between(localDate1, LocalDate.now());
!
!
// 會是1975-04-01T23:00+09:00[Asia/Taipei]
// 如果是 Duration, 則會是加上 24 小時
ZonedDateTime.of(
LocalDate.of(1975, 3, 31),
LocalTime.of(23, 0),
ZoneId.of("Asia/Taipei"))
.plus(Period.ofDays(1));
•從兩個 LocalDate 取得
!
!
•用在 ZonedDateTime 時有考慮到 DST
35. ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10,
SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.toFormatter(ResolverStyle.STRICT,
IsoChronology.INSTANCE);
!
LocalDate ld = LocalDate.parse("2011-12-03",
ISO_LOCAL_DATE);
36. Parsing
•Instant, Date 和 Time 類別都用一樣方式
parse
•Period, Duration 用 ISO-8601格式
Instant.parse("…", dateTimeFormatter);
LocalDate.parse("…", dateTimeFormatter);
//1 Year 2 months 3days
Period.parse("P1Y2M3D");
//2 days 3 hours 2.21 seconds
Duration.parse("P2DT3H2.21S");
37. •有些格式變得比較嚴格
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern(
"yyyy/MM/dd");
//ok
LocalDate.parse("2014/03/02", formatter);
// error, DateTimeParseException
//LocalDate.parse("2014/3/2", formatter);
//ok
new SimpleDateFormat("yyyy/MM/dd")
.parse("2014/3/2");
38. Clock
•透過 Inject 便於測試
•可以建立多種類型的 Clock
•讓測試可以獨立於 time zone
private Clock clock; // dependency inject
public void process(LocalDate event) {
if(event.isBefore(LocalDate.now(clock)){
...
46. plus, minus
•Adds/Subtracts an amount to an object
LocalDate.now().plusDays(4)
.plusYear(2);
LocalTime.now().plusMinutes(30)
.plusHours(4)
.minusSeconds(30);
48. until, between
•Amount of time until another
LocalDate.of(2014, 12, 3).until(
LocalDate.of(2014, 12, 7),
ChronoUnit.WEEKS);
ChronoUnit.DAYS.between(
LocalDate.of(2014, 12, 3),
LocalDate.of(2014, 12, 7));
51. 與 Date 的轉換
•LocalDate 和 LocalTime 本身沒有 Instant
值,所以必須要先轉換成能取得 Instant
•從 LocalDateTime 到 Date
LocalDate now = LocalDate.now();
Instant instant =
now.atZone(ZoneId.systemDefault())
.toInstant();
Date date = Date.from(instant);
52. •從 Date 到 LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime =
LocalDateTime.ofInstant(
instant,
ZoneId.systemDefault());
59. LocalDateTime << SQL
ResultSet rs = …;
…
java.sql.Time time = rs.getTime(…);
LocalTime lt = time.toLocalTime();
java.sql.Date date = rs.getDate(…);
LocalDate ld = date.toLocalDate();
java.sql.Timestamp ts = rs.getTimeStamp(…);
LocalDateTime ldt =
ts.toLocalDateTime();
60. LocalDateTime >> SQL
PreparedStatement pstmt = …;
pstmt.setTime(1,
Time.valueOf(LocalTime.now()));
pstmt.setDate(2,
Date.valueOf(LocalDate.now()));
pstmt.setTimestamp(3,
Timestamp.valueOf(LocalDateTime.now()));
61. 總結 JSR 310 的好處
•良好的命名和 API 設計
•日期和時間的分別處理
•Immutable
•精確到奈秒
•多樣化的操作
•存取各種 filed 方便