Upload
kenji-hasunuma
View
1.716
Download
9
Embed Size (px)
DESCRIPTION
Introduction to Date and Time API, 2nd edition #jjug #ccc_r21
Citation preview
Introduction to Date and Time API II
HASUNUMA Kenji GlassFish Community
[email protected]: @khasunuma
November 9, 2013#ccc_r21
Time?
Representation of Date/Time
java.util.DateANSI/ISO Cのtime_tと機能的に同等 現在は日付・時刻の表現のみに徹する ※java.sql.Date等のサブクラス
java.util.CalendarJavaの国際化対応(JDK 1.1)で導入 日付・時刻の作成・編集に用いる ※GregorianCalendar等のサブクラス
java.time.* (JSR 310)
JDK8~、Date/Calendar代替が当初の目標 日付・時刻を総合的に扱うフレームワーク ※規模はJDK8の新APIでも最大級
※その他、XML DOM APIのXMLGregorianCalendarがある
java.util.Dateの課題• フィールド操作が面倒
• 年フィールド+1900が実際の年
• 月が0から始まる (1月→0…12月→11)
• フィールドの直接操作が非推奨 (Calendarを使う)
• 日付部と時刻部が混在している
• 日付演算が貧弱、フォーマット機能も使い勝手に難
• JDK 1.1以降、一部例外を除きメンテナンスなし
java.util.Calendarの課題
• フィールド操作が面倒 (Dateよりは改善)
• 月が0から始まる →定数でお茶を濁す
• フィールド操作の使い勝手がイマイチ
• 日付演算が貧弱 … それでもDateよりは多少マシ
• 日付・時刻型として認識されないことも多い例: DateFormat → Dateとの相互変換を利用
java.util.Calendarの改善
JDK8よりCalendar.Builderを導入 →メソッドチェーン(1行)で日付・時刻を表せる
// 2013年11月9日を表すCalendar (since JDK8)Calendar calendar = new Calendar.Builder()
.setDate(2013, NOVEMBER, 9)
.setField(HOUR_OF_DAY, 9)
.build();
JSR 310 Date and Time API
JSR 310 : Date and Time API
• Date、Calendar、DateFormat等を置き換えることが目的
• ISO 8601形式の日付・時刻表現
• ImmutableかつスレッドセーフなAPI
• 設計思想はJoda-Timeに酷似
java.util.Date JSR 310
オブジェクト Mutable Immutable
精度 ミリ秒 ナノ秒
フィールド操作 Calendar経由 直接サポート
タイムゾーン サポート サポート
toString戻り値 Unix形式 ISO 8601形式
日付と時刻の分離 不可 可能
日付演算 比較のみ 様々な日付演算
関連クラス数 数個 たくさん
JSR 310のメリット
•月:1~12 (Date, Calendarは0~11)
• toStringでISO 8601形式を返す
•日付と時刻を分離することができる
•多様な日付演算機能を持つ
•スレッドセーフである
JSR 310のデメリット
• JDK8 APIの中でも最大規模(=複雑)
• 既存APIとの相互運用性はガン無視
• Dateとの相互変換は比較的最近に実現
•今後の展開が不明瞭
• JPAやJAXBへの展開は検討中?
• 少なくともJavaFX 8には間に合わず
参考: ISO 8601形式
•日付: yyyy-MM-dd
• 2013-11-09
•時刻: hh:mm:ss.SSSZ
• 04:05:00.000Z
•日時: yyyy-MM-dd’T’HH:mm:ss.SSSZ
• 2013-11-09T04:05:00.000Z
JSR 310 Essentials
マシン向けの表現(内部表現) • Instant• Duration• Clock
人間向けの表現(外部表現) • DateTime• Period• Chronology
マシン向けの表現(内部表現)
人間向けの表現(外部表現)
DateTime : 日付・時刻
• TemporalAccessor等の実装
• 現在日時または任意の日時から生成
• DateTimeの演算(plus/minus)および他のDateTimeからの変換をサポート
• Instantに対応する人間向け表現
主なDateTimeの実装
• LocalDate, LocalTime, LocalDateTime
• OffsetTime, OffsetDateTime
• ZonedDateTime
• 不足情報の追加または余剰情報の切り捨てにより相互に変換可
Date Time DateTime
Local年/月/日
!
時差情報なし
!
時/分/秒/未満 時差情報なし
年/月/日 時/分/秒/未満 時差情報なし
Offset N/A!
時/分/秒/未満 UTCからの時差
年/月/日 時/分/秒/未満 UTCからの時差
Zoned N/A N/A年/月/日
時/分/秒/未満 タイムゾーン
OffsetDateTime vs. ZonedDateTime
• OffsetDateTime - UTCからの時差のみ考慮
• ZonedDateTime - タイムゾーンを考慮
※タイムゾーン ≠ UTCからの時差
タイムゾーンは以下も考慮している:
• 夏時間(米国や西欧で多く導入)
• 時差の改訂(ごく稀に発生)
Chronology : 暦 (インタフェース)
Chronology暦そのものを表し、各種変換メソッドを提供
ChronoLocalDate 暦の情報を含むLocalDate
ChronoLocalDateTime<D extends ChronoLocalDate>
ChronoLocalDateに時刻を付加
ChronoZonedDateTime<D extends ChronoLocalDate>
ChronoLocalDateに時刻とタイムゾーンを付加
Era 暦の紀元(開始年)を表す ※和暦は開始・終了年月日
Chronologyの実装クラスIsoChronology/-Era
LocalDate ISO 8601(標準)
JapaneseChronology/-Era JapaneseDate 和暦(日本)
ThaiBuddistChronology/-Era ThaiBuddistDate 仏暦(タイ)
MinguoChronology/-EraMinguoDate 民国紀元(台湾)
HijirahChronology/-EraHijirahDate イスラム暦
日付・時刻演算• DateTime、Period、Instant、Durationはそれ自身が加算・減算・比較・判定・変換メソッドを持つ
• OpenJDK合流以前と比較して機能は大幅に削減されたものの、依然としてDate/Calendarより強力
• 昨年同時期と比較して、Chronologyの使い勝手は向上した模様 (インタフェースのdefaultメソッド乱用という悪しき前例を作ったが…)
• Immutableのため、演算結果がもとのオブジェクトに影響しないのも大きなメリット
日付・時刻の構成要素Year
「年」を表すクラス ※加減算・判定・各種変換メソッド
Month「月」を表す列挙型、月末日付も保持 ※加減算・各種変換メソッド
YearMonth「年月」を表すクラス ※加減算・判定・各種判定メソッド
MonthDay「月日」を表すクラス ※「年」を加えればLocalDateへ
DayOfWeek「曜日」を表す列挙型 ※DateTimeからの曜日取得も可
JSR 310のフォーマット機能• LocalDate等のtoStringメソッドは、ISO 8601形式でフォーマットしたものを返す
• 標準以外のフォーマット→DateTimeFormatter※DateTimeFormatterには使用頻度の高いフォーマットが定義済み
• フォーマットを新しく作成する場合は、DateTimeFomatterBuilderの使用を推奨※国内ではyyyy/MM/dd形式が普及しているため、欧米と比較してDateTimeFormatterBuilderの使用頻度は高いと思われる
• java.text.DateFormatはJSR 310では使用できない※逆にDateTimeFormatterはjava.text.DateFormatに変換可能
Interoperability
JSR 310⇔Date/Calendar変換重要 : JSR 310はDate/Calendarとの直接変換をサポートしない
• DateはInstantを介してJSR 310と相互変換が可能具体的にはDate.from() / Date.toInstant()を用いる
• CalendarはCalendar.toInstant()でInstantに変換可能、ただしその逆はできない
• Instant.toEpochMilli() / Instant.ofEpochMilli() でInstantをlong値に変換する方法もあり
ThreeTen backport• JSR 310からJDK8依存の部分を取り除き、JDK7で利用可能にした、JSR 310ライクなライブラリ (パッケージ名はjava.timeではなくorg.threeten.bp)
• Java SE 8リリース前にJSR 310を予習するための教材として最適
• Apache License 2.0のOSSとして配布https://github.com/ThreeTen/threetenbp
Examples
// 今日の日付を取得→date
LocalDate date = LocalDate.now();
// 2013年11月9日→date LocalDate date = LocalDate.of(2013, 11, 9);
// 今日の日付→d1 // 3日後の日付→d2
LocalDate d1 = LocalDate.now(); LocalDate d2 = d1.plusDays(3);
// 今日の日付→date // 今日の13時40分→dateTime LocalDate date = LocalDate.now(); LocalDateTime dateTime = date.atTime(13, 40);
// 今日の日時→dateTime // 今日の日付→date LocalDateTime dateTime = LocalDateTime.now(); LocalDate date = LocalDate.from(dateTime);
// date: 1992年10月8日 (うるう年) // → leap = true LocalDate date = LocalDate.of(1992, 10, 8); boolean leap = date.isLeapYear();
// 今日の日付→date // dateを標準出力へ LocalDate date = LocalDate.now(); System.out.println(date.toString());
2013-11-09
出力結果
// 今日の日付(和暦)→jdate // ThreeTen Backportでも結果自体は同じ JapaneseDate jdate = JapaneseDate.now(); System.out.println(jdate.toString);
H25-11-09
出力結果
応用 : JSR 310をJAXBに対応させてみるpublic class LocalDateXmlAdapter extends! XmlAdapter<XMLGregorianCalendar, LocalDate> {!! @Override! public LocalDate unmarshal(XMLGregorianCalendar value) throws Exception {! int timezone = value.getTimezone();! ZoneOffset offset = ZoneOffset.ofTotalSeconds(timezone * 60);! return OffsetDateTime.of(value.getYear(), value.getMonth(),! value.getDay(), 0, 0, 0, 0, offset).toLocalDate();! }!! @Override! public XMLGregorianCalendar marshal(LocalDate value) throws Exception {! ZoneOffset offset = OffsetDateTime.now().getOffset();! int timezone = offset.getTotalSeconds() / 60;! return DatatypeFactory.newInstance().newXMLGregorianCalendarDate(! value.getYear(), value.getMonthValue(), value.getDayOfMonth(),! timezone);! }!!}
Conclusion
JSR 310とは何なのか?
• JSR 310はjava.util.Dateの欠点をすべて解決しようとする野心的試み
•過去との互換性を断ち切ることで、日付・時刻APIの理想を追求した
•正直やり過ぎ感も否めないが、既存APIの問題点の多くを解決した点は評価
Date/Calendarの今後は?
• JSR 310が浸透するまで、当分の間はその位置づけに変化はないはず。
• Calendar.Builderは延命措置だが、短期的には効果大。
• 日付の操作ではJSR 310に遠く及ばないため、長期的にはフェードアウト?
JDK8時代の日付・時刻表現• お好きなAPIをどうぞ。
• Date/CalendarとJSR 310の相互変換については早いうちに準備するのがベター。
• 当初からJSR 310の使える箇所は、業務ロジックの日付処理、JAXBおよびそれに依存するJAX-RS/JAX-WS。
Introduction to Date and Time API II HASUNUMA Kenji [email protected]: @khasunuma