Java Date and Time API¶
はじめに¶
Java Date and Times APIは、Java SE 8から標準化された日時に関する新しいAPIです。
コンピューター(UNIX系OSを中心に)では、1970年1月1日の00:00:00(UTC)を起点とする経過時間を管理し、この経過時間を年月日時分秒に変換して人間が普段使う日付・時刻を表現していました。しかし、人間が普段使う日付・時刻は、国や地域で大小さまざまに異なっています。国が違うと時差があり、また太陽暦だけでなく太陰暦を扱うこともあり、また夏時間、冬時間を持つ国・地域があり、年も西暦だけでなく元号など様々な年が存在します。
JavaのDate and Times APIでは、それまでのjava.util.Dateクラスおよびjava.util.Calendarクラスを刷新し、これらの概念を取り込んで扱うことを目的としています。
使い方メモ¶
ローカルタイムのみを扱う場合¶
時差や、サマータイム制などを考慮しなくてもいい場合は、LocalDate、LocalTime、またはLocalDateTimeを使って日付、時刻を扱うことができます。
主にOSのデフォルトロケールで扱う時刻帯における年月日時分秒を扱います。
LocalDate¶
時分秒は含まず日付(年月日)を表現します。誕生日とか記念日、開催日などで時分秒を問わない情報を表現するのに有用です。
生成¶
LocalDate today = LocalDate.now(); // プログラムを実行した日
LocalDate theDay = LocalDate.of(2016, 1, 6); // 2016年1月6日
LocalDate theOtherDay = LocalDate.of(2015, Month.DECEMBER, 25); // 2015年12月25日、月をenum型で指定
LocalDateはイミュータブルオブジェクトとして設計されています。一度インスタンスを生成したらその値を変えることができません。
年、月、日の値の取り出し¶
int year = today.getYear(); // 年の値の取り出し
int monthValue = today.getMonthValue(); // 月の値の取り出し
int day = today.getDayOfMonth(); // 日の値の取り出し
Month month = today.getMonth(); // enum型で月を取り出し
LocalTime¶
日付は含まず時分秒を表現します。秒は、ナノ秒単位まで保持可能です。
生成¶
LocalTime now = LocalTime.now(); // このメソッドを実行した時刻(OSのロケールで示される国・地域での時刻)
LocalTime theTime = LocalTime.of(19, 30, 21); // 時分秒を指定して生成
int hour = now.getHour(); // 時の値の取り出し
int minute = now.getMinute(); // 分の値の取り出し
int second = now.getSeocnd(); // 秒の値の取り出し
int nano = now.getNano(); // 秒以下のナノ秒単位での値を取り出し
LocalDateTime¶
日付と時分秒を表現します。
LocalDateTime now = LocalDateTime.now(); // このメソッドを実行した日付・時刻(OSのロケールで示される国・地域での時刻)
LocalDateTime theDateTime = LocalDateTime.of(2024, 1, 3, 19, 30, 21); // 年月日時分秒を指定して生成
LocalDate date = LocalDate.of(2024, 1, 3);
LocalTime time = LocalTime.of(19, 30, 21);
LocalDateTime datetime = LocalDateTime.of(date, time); // LocalDateとLocalTimeを渡して生成
int hour = now.getHour(); // 時の値の取り出し
int minute = now.getMinute(); // 分の値の取り出し
int second = now.getSeocnd(); // 秒の値の取り出し
int nano = now.getNano(); // 秒以下のナノ秒単位での値を取り出し
2つの日付の間の長さ¶
期間¶
年、月、日単位である時刻と別な時刻との間の長さを表すPeriodを使います。
Period period = Period.between(theOtherDay, theDay);
int days = period.getDays();
時間¶
ある時刻(時分秒)と、別な時刻との間の長さをChronoUnitで表現します。
長さを時間単位で表現する場合は、ChronoUnit.HOURS を使います。
LocalDateTime now = LocalDateTime.now();
LocalDateTime closing = LocalDateTime.of(2016, 1, 9, 23, 59);
long hours = ChronoUnit.HOURS.between(now, closing);
各国で使用する時刻を扱う場合¶
時刻は、たいてい国ごと、あるいは地域ごとにそれぞれの標準時を定めています。日本であれば、日本標準時がそれにあたります。
UTC(協定世界時)と地方時との時差(オフセット)や、夏時間などの考慮が含まれるタイムゾーンを用いて地域ごとの標準時を扱います。
- UTCからの時差のみで扱うOffsetDateTime、OffsetTimeクラス
- タイムゾーンを扱うZonedDateTimeクラス
時差とタイムゾーン¶
- 時差とタイムゾーンを扱うZoneIdクラス
- 時差を扱うZoneOffset
タイムゾーンを扱うZoneIdクラス¶
tz databaseで扱う地域名/地名でタイムゾーンを表します。
日本標準時のタイムゾーンは、地域名/地名に "Asia/Tokyo"を指定してZonedDateTimeインスタンスを生成します。
var tokyo = ZoneId.of("Asia/Tokyo");
var time = ZonedDateTime.of(2023, 9, 18, 17, 45, 0, tokyo); // 年月日時分秒、ナノ秒とタイムゾーンを指定
日本時間ではサマータイムが今はないので、時差のみを扱うZoneOffsetと大きな差異はありませんが、夏時間を採用している欧米などの時刻を扱うときは、このZoneIdが必要になります。
地域名/地名の指定以外に、3文字のタイムゾーンコード(例:JST、BST、PST)を指定する方法もあります。var tokyo = ZoneId.of("JST", ZoneId.SHORT_IDS);
時差を扱うZoneOffsetクラス¶
UTCからの時差のみを扱います。var tokyo = ZoneOffset.of("+09:00");
UTCそのものを指定する、ZoneOffset.UTC
もあります。
OffsetDateTimeクラス¶
時差を扱う日付時刻クラスです。
ZonedDateTimeクラス¶
生成¶
- デフォルトのタイムゾーンにおける現在日時を取得します。
var current = ZonedDateTime.now(); // 例)2024-03-31T22:14:31.515069+09:00[Asia/Tokyo]
2つの日時の間の長さ¶
UTCとのオフセットで時刻を扱う場合¶
UTCとの時刻差を考慮した時刻を扱う場合に、OffsetDateTime、OffsetTimeクラスが使えます。
Instantクラス¶
時刻系の上の単一点を表現します。
エポック(1970-01-01T00:00:00Z)を起点とする経過秒数と、ナノ秒を保持します。UTC時刻とほぼ同じとなります。
使用例¶
- 今の瞬間の Instant 生成
Instant.now()
- テキスト文字から Instant 生成
Instant.parse("2023-09-17T09:00:00Z")
- LocalDateTimeから Instant 生成
LocalDateTimeはUTCに対するオフセット情報を持たないので、変換メソッドにゾーンオフセットを追加指定します。var now = LocalDateTime.now(); var instant = now.toInstant(ZoneOffset.of("+09:00"));
- エポック(1970-01-01T00:00:00Z)からの経過時間から Instant 生成
Instant.ofEpochMilli(経過ミリ秒)
Instant.ofEpochSecond(経過秒数)
Instant.ofEpochSecond(経過秒数, 秒数のナノ秒部分)
文字列化¶
toString()メソッドで、2023-09-17T09:00:00Z
のような文字列を生成します。
文字列からDate/DateTimeへ変換¶
DateTimeFormatterでパターンを定義し、そのパターンに基づき文字列からDate、TimeあるいはDateTimeに変換します。
LocalDate¶
文字列から年月日をもつLocalDateオブジェクトを生成します。
パターンは、事前定義されたもの、あるいはプログラムで任意に定義したものを適用できます。
- java.time.format.DateTimeFormatter
事前定義された定数 | 書式 |
---|---|
BASIC_ISO_DATE |
20111203 |
ISO_LOCAL_DATE |
2011-12-03 |
ISO_OFFSET_DATE |
2011-12-03+01:00 |
ISO_DATE |
ISO_LOCAL_DATE または ISO_OFFSET_DATE |
ISO_ORDINAL_DATE |
2012-337 |
ISO_WEEK_DATE |
2012-W48-6 |
プログラムで定義する例
var formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
文字列からLocalDateの生成例
var date1 = LocalDate.parse("2023-12-24", DateTimeFormatter.ISO_DATE);
var date2 = LocalDate.parse("2023/12/25", formatter);
- 注1) 年月日が揃った定義が必要。年だけ、とかではparseが例外を出します。
LocalDateTime¶
文字列から年月日時分秒をもつLocalDateTimeオブジェクトを生成します。
パターンは、事前定義されたもの、あるいはプログラムで任意に定義したものを適用できます。
- java.time.format.DateTimeFormatter
事前定義された定数 | 書式 |
---|---|
ISO_LOCAL_DATE_TIME |
2011-12-03T10:15:30 |
ISO_OFFSET_DATE_TIME |
2011-12-03T10:15:30+01:00 |
ISO_ZONED_DATE_TIME |
2011-12-03T10:15:30+01:00[Europe/Paris] |
ISO_DATE_TIME |
|
ISO_INSTANT |
2011-12-03T10:15:30Z |
RFC_1123_DATE_TIME |
Tue, 3 Jun 2008 11:05:30 GMT |
プログラムで定義する例
var formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
文字列からLocalDateTimeの生成例
var date1 = LocalDate.parse("2023-12-24T07:30:45", DateTimeFormatter.ISO_LOCAL_DATE_TIME);
var date2 = LocalDate.parse("2023/12/25 07:30:45", formatter);
- 注1)DateTiimeFormatter.ofPatternで、パターン文字列に
T
を使用するときは、シングルクォートで囲う必要あります。"yyyy-DDD'T'HH:mm:ss.SSS"
これは、[A-Za-z]がパターン文字として予約されているため、エスケープが必要なためです。
パターン定義のパターン文字¶
抜粋
記号 | 意味 | 例 |
---|---|---|
y | 年 | 2023; 23 |
D | 年の通算日 | 189 |
M | 月 | 7; 07 |
d | 日 | 15 |
H | 時(0-23) | |
m | 分 | |
s | 秒 | |
S | 秒の小数点以下(ミリ秒) | |
V | タイムゾーンID | America/Los_Angels; Z; +09:00 |
- 年については、'y'の他に'u'の指定があります。'y'は、特定の暦(西暦、和暦、ヒジュラ暦、タイ仏暦、民国暦)における年を指し、STRICTモードでは暦の指定が必須となるようです。
APIいろいろ¶
列挙(enum)¶
月(Month)¶
java.time.Month
- 次の列挙子が定義されています。
JANUARY, FEBURARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER
- getValue()メソッドで、月を表すint値(1-12)を返却
曜日(DayOfWeek)¶
java.time.DayOfWeek
- 次の列挙子が定義されています。
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
- getValue()メソッドで、曜日を表すint値(1-7、1:月曜日、7:日曜日)
APIの実装¶
Instant¶
Instant.now¶
Instant.now() Cloclk.systemUTC() new SystemClock(ZoneOffset.UTC) SystemClock#instant() SystemClock#millis() System.currentTimeMillis() *1 Instant.ofEpochMillis(*1) Math.floorDiv *2 Math.floorMod *3 Instant#create(*2, *3) new Instant(*2, *3)
LocalTime¶
LocalTime.now¶
LocalTime.now() Clock.systemDefaultZone() ZoneId.systemDefault() TimeZone.getDefault() TimeZone.getDefaultRf() Timezone#clone() TimeZone#toZoneId() ZoneId.of(*, ZoneId.SHORT_IDS) new SystemClock(*) LocalTime.now(*) Clock.system(*) new SystemClock(*) LocalTime.now(*) Clock#instant() Clock#getZone() getRules() getOffset(*) Math.floorMod ofNanoOfDay()