51
Introduction to Date and Time API II HASUNUMA Kenji GlassFish Community [email protected] Twitter: @khasunuma November 9, 2013 #ccc_r21

Introduction to Date and Time API, 2nd edition

Embed Size (px)

DESCRIPTION

Introduction to Date and Time API, 2nd edition #jjug #ccc_r21

Citation preview

Page 1: Introduction to Date and Time API, 2nd edition

Introduction to Date and Time API II

HASUNUMA Kenji GlassFish Community

[email protected]: @khasunuma

November 9, 2013#ccc_r21

Page 2: Introduction to Date and Time API, 2nd edition

Time?

Page 3: Introduction to Date and Time API, 2nd edition
Page 4: Introduction to Date and Time API, 2nd edition
Page 5: Introduction to Date and Time API, 2nd edition
Page 6: Introduction to Date and Time API, 2nd edition
Page 7: Introduction to Date and Time API, 2nd edition
Page 8: Introduction to Date and Time API, 2nd edition
Page 9: Introduction to Date and Time API, 2nd edition
Page 10: Introduction to Date and Time API, 2nd edition

Representation of Date/Time

Page 11: Introduction to Date and Time API, 2nd edition

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がある

Page 12: Introduction to Date and Time API, 2nd edition

java.util.Dateの課題• フィールド操作が面倒

• 年フィールド+1900が実際の年

• 月が0から始まる (1月→0…12月→11)

• フィールドの直接操作が非推奨 (Calendarを使う)

• 日付部と時刻部が混在している

• 日付演算が貧弱、フォーマット機能も使い勝手に難

• JDK 1.1以降、一部例外を除きメンテナンスなし

Page 13: Introduction to Date and Time API, 2nd edition

java.util.Calendarの課題

• フィールド操作が面倒 (Dateよりは改善)

• 月が0から始まる →定数でお茶を濁す

• フィールド操作の使い勝手がイマイチ

• 日付演算が貧弱 … それでもDateよりは多少マシ

• 日付・時刻型として認識されないことも多い例: DateFormat → Dateとの相互変換を利用

Page 14: Introduction to Date and Time API, 2nd edition

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();

Page 15: Introduction to Date and Time API, 2nd edition

JSR 310 Date and Time API

Page 16: Introduction to Date and Time API, 2nd edition

JSR 310 : Date and Time API

• Date、Calendar、DateFormat等を置き換えることが目的

• ISO 8601形式の日付・時刻表現

• ImmutableかつスレッドセーフなAPI

• 設計思想はJoda-Timeに酷似

Page 17: Introduction to Date and Time API, 2nd edition

java.util.Date JSR 310

オブジェクト Mutable Immutable

精度 ミリ秒 ナノ秒

フィールド操作 Calendar経由 直接サポート

タイムゾーン サポート サポート

toString戻り値 Unix形式 ISO 8601形式

日付と時刻の分離 不可 可能

日付演算 比較のみ 様々な日付演算

関連クラス数 数個 たくさん

Page 18: Introduction to Date and Time API, 2nd edition

JSR 310のメリット

•月:1~12 (Date, Calendarは0~11)

• toStringでISO 8601形式を返す

•日付と時刻を分離することができる

•多様な日付演算機能を持つ

•スレッドセーフである

Page 19: Introduction to Date and Time API, 2nd edition

JSR 310のデメリット

• JDK8 APIの中でも最大規模(=複雑)

• 既存APIとの相互運用性はガン無視

• Dateとの相互変換は比較的最近に実現

•今後の展開が不明瞭

• JPAやJAXBへの展開は検討中?

• 少なくともJavaFX 8には間に合わず

Page 20: Introduction to Date and Time API, 2nd edition

参考: 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

Page 21: Introduction to Date and Time API, 2nd edition

JSR 310 Essentials

Page 22: Introduction to Date and Time API, 2nd edition

マシン向けの表現(内部表現) • Instant• Duration• Clock

人間向けの表現(外部表現) • DateTime• Period• Chronology

Page 23: Introduction to Date and Time API, 2nd edition

マシン向けの表現(内部表現)

Page 24: Introduction to Date and Time API, 2nd edition

人間向けの表現(外部表現)

Page 25: Introduction to Date and Time API, 2nd edition

DateTime : 日付・時刻

• TemporalAccessor等の実装

• 現在日時または任意の日時から生成

• DateTimeの演算(plus/minus)および他のDateTimeからの変換をサポート

• Instantに対応する人間向け表現

Page 26: Introduction to Date and Time API, 2nd edition

主なDateTimeの実装

• LocalDate, LocalTime, LocalDateTime

• OffsetTime, OffsetDateTime

• ZonedDateTime

• 不足情報の追加または余剰情報の切り捨てにより相互に変換可

Page 27: Introduction to Date and Time API, 2nd edition

Date Time DateTime

Local年/月/日

!

時差情報なし

!

時/分/秒/未満 時差情報なし

年/月/日 時/分/秒/未満 時差情報なし

Offset N/A!

時/分/秒/未満 UTCからの時差

年/月/日 時/分/秒/未満 UTCからの時差

Zoned N/A N/A年/月/日

時/分/秒/未満 タイムゾーン

Page 28: Introduction to Date and Time API, 2nd edition

OffsetDateTime vs. ZonedDateTime

• OffsetDateTime - UTCからの時差のみ考慮

• ZonedDateTime - タイムゾーンを考慮

※タイムゾーン ≠ UTCからの時差

タイムゾーンは以下も考慮している:

• 夏時間(米国や西欧で多く導入)

• 時差の改訂(ごく稀に発生)

Page 29: Introduction to Date and Time API, 2nd edition

Chronology : 暦 (インタフェース)

Chronology暦そのものを表し、各種変換メソッドを提供

ChronoLocalDate 暦の情報を含むLocalDate

ChronoLocalDateTime<D extends ChronoLocalDate>

ChronoLocalDateに時刻を付加

ChronoZonedDateTime<D extends ChronoLocalDate>

ChronoLocalDateに時刻とタイムゾーンを付加

Era 暦の紀元(開始年)を表す ※和暦は開始・終了年月日

Page 30: Introduction to Date and Time API, 2nd edition

Chronologyの実装クラスIsoChronology/-Era

LocalDate ISO 8601(標準)

JapaneseChronology/-Era JapaneseDate 和暦(日本)

ThaiBuddistChronology/-Era ThaiBuddistDate 仏暦(タイ)

MinguoChronology/-EraMinguoDate 民国紀元(台湾)

HijirahChronology/-EraHijirahDate イスラム暦

Page 31: Introduction to Date and Time API, 2nd edition

日付・時刻演算• DateTime、Period、Instant、Durationはそれ自身が加算・減算・比較・判定・変換メソッドを持つ

• OpenJDK合流以前と比較して機能は大幅に削減されたものの、依然としてDate/Calendarより強力

• 昨年同時期と比較して、Chronologyの使い勝手は向上した模様 (インタフェースのdefaultメソッド乱用という悪しき前例を作ったが…)

• Immutableのため、演算結果がもとのオブジェクトに影響しないのも大きなメリット

Page 32: Introduction to Date and Time API, 2nd edition

日付・時刻の構成要素Year

「年」を表すクラス ※加減算・判定・各種変換メソッド

Month「月」を表す列挙型、月末日付も保持 ※加減算・各種変換メソッド

YearMonth「年月」を表すクラス ※加減算・判定・各種判定メソッド

MonthDay「月日」を表すクラス ※「年」を加えればLocalDateへ

DayOfWeek「曜日」を表す列挙型 ※DateTimeからの曜日取得も可

Page 33: Introduction to Date and Time API, 2nd edition

JSR 310のフォーマット機能• LocalDate等のtoStringメソッドは、ISO 8601形式でフォーマットしたものを返す

• 標準以外のフォーマット→DateTimeFormatter※DateTimeFormatterには使用頻度の高いフォーマットが定義済み

• フォーマットを新しく作成する場合は、DateTimeFomatterBuilderの使用を推奨※国内ではyyyy/MM/dd形式が普及しているため、欧米と比較してDateTimeFormatterBuilderの使用頻度は高いと思われる

• java.text.DateFormatはJSR 310では使用できない※逆にDateTimeFormatterはjava.text.DateFormatに変換可能

Page 34: Introduction to Date and Time API, 2nd edition

Interoperability

Page 35: Introduction to Date and Time API, 2nd edition

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値に変換する方法もあり

Page 36: Introduction to Date and Time API, 2nd edition

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

Page 37: Introduction to Date and Time API, 2nd edition

Examples

Page 38: Introduction to Date and Time API, 2nd edition

// 今日の日付を取得→date

LocalDate date = LocalDate.now();

Page 39: Introduction to Date and Time API, 2nd edition

// 2013年11月9日→date LocalDate date = LocalDate.of(2013, 11, 9);

Page 40: Introduction to Date and Time API, 2nd edition

// 今日の日付→d1 // 3日後の日付→d2

LocalDate d1 = LocalDate.now(); LocalDate d2 = d1.plusDays(3);

Page 41: Introduction to Date and Time API, 2nd edition

// 今日の日付→date // 今日の13時40分→dateTime LocalDate date = LocalDate.now(); LocalDateTime dateTime = date.atTime(13, 40);

Page 42: Introduction to Date and Time API, 2nd edition

// 今日の日時→dateTime // 今日の日付→date LocalDateTime dateTime = LocalDateTime.now(); LocalDate date = LocalDate.from(dateTime);

Page 43: Introduction to Date and Time API, 2nd edition

// date: 1992年10月8日 (うるう年) // → leap = true LocalDate date = LocalDate.of(1992, 10, 8); boolean leap = date.isLeapYear();

Page 44: Introduction to Date and Time API, 2nd edition

// 今日の日付→date // dateを標準出力へ LocalDate date = LocalDate.now(); System.out.println(date.toString());

2013-11-09

出力結果

Page 45: Introduction to Date and Time API, 2nd edition

// 今日の日付(和暦)→jdate // ThreeTen Backportでも結果自体は同じ JapaneseDate jdate = JapaneseDate.now(); System.out.println(jdate.toString);

H25-11-09

出力結果

Page 46: Introduction to Date and Time API, 2nd edition

応用 : 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);!    }!!}

Page 47: Introduction to Date and Time API, 2nd edition

Conclusion

Page 48: Introduction to Date and Time API, 2nd edition

JSR 310とは何なのか?

• JSR 310はjava.util.Dateの欠点をすべて解決しようとする野心的試み

•過去との互換性を断ち切ることで、日付・時刻APIの理想を追求した

•正直やり過ぎ感も否めないが、既存APIの問題点の多くを解決した点は評価

Page 49: Introduction to Date and Time API, 2nd edition

Date/Calendarの今後は?

• JSR 310が浸透するまで、当分の間はその位置づけに変化はないはず。

• Calendar.Builderは延命措置だが、短期的には効果大。

• 日付の操作ではJSR 310に遠く及ばないため、長期的にはフェードアウト?

Page 50: Introduction to Date and Time API, 2nd edition

JDK8時代の日付・時刻表現• お好きなAPIをどうぞ。

• Date/CalendarとJSR 310の相互変換については早いうちに準備するのがベター。

• 当初からJSR 310の使える箇所は、業務ロジックの日付処理、JAXBおよびそれに依存するJAX-RS/JAX-WS。

Page 51: Introduction to Date and Time API, 2nd edition

Introduction to Date and Time API II HASUNUMA Kenji [email protected]: @khasunuma