ちょっとだけJavaでRFC3339の日付フォーマットを使う機会があったのでメモしておきます。
目次
概要
基本的な流れは以下となります。
文字列→日付型 (parse)
日付の文字列から、日付型(OffsetDateTime
)に変換します。
OffsetDateTime.parse(<日付文字列>, <日付フォーマット>); // => 戻りはOffsetDateTimeクラスのインスタンス
OffsetDateTime
クラスのparse
メソッドを使います。RFC3339
の日付フォーマットはDateTimeFormatter.ISO_OFFSET_DATE_TIME
を指定します。
日付フォーマット型→文字列 (format)
日付型(OffsetDateTime
)から、日付の文字列変換します。
<日付フォーマット型>.format(<日付フォーマット>); // => 戻りはString
OffsetDateTime
インスタンスのformat
メソッドを使います。- 出力用の日付フォーマットのインスタンスは
DateTimeFormatter.ofPattern
で作成できます。
例: DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")
時差変換
ある日付(日付型)のタイムゾーンを変換します。
<日付フォーマット型>.withOffsetSameInstant(<変換先のタイムゾーンオフセット>); // => 戻りは時差変換されたOffsetDateTimeクラスのインスタンス
OffsetDateTime
インスタンスのwithOffsetSameInstant
メソッドを使います。- 変換先のタイムゾーンオフセットには
ZoneOffset
のインスタンスを指定します。
例: ZoneOffset.ofHours(9) これはJSTのタイムゾーンオフセット
例: ZoneOffset.UTC これはUTCのタイムゾーンオフセット
ポイント
java.time.OffsetDateTime
クラスのparse
メソッドで文字列をOffsetDateTime
のインスタンスに変換します。java.time.OffsetDateTime
のインスタンスのformat
メソッドにjava.time.format.DateTimeFormatter
クラスのインスタンスを渡して文字列に変換します。java.time.format.DateTimeFormatter
は日付フォーマットを表現しているクラスです。1java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME
というインスタンスがRFC3339
に対応しています。java.time.format.DateTimeFormatter
のofPattern
メソッドにJavaの日付フォーマット文字列を指定すると、独自のフォーマットが作成可能です。
例: "yyyy/MM/dd HH:mm:ss.SSSSSSS"
- タイムゾーンオフセットを変換する場合(UTC→JSTなど)は、
java.time.OffsetDateTime
のwithOffsetSameInstance
メソッドにjava.time.ZoneOffset
のインスタンスを渡します。
例: UTC→JST utcDateTime.withOffsetSameInstance(ZoneOffset.ofHours(9))
例: JST→UTC jstDateTime.withOffsetSameInstance(ZoneOffset.UTC) ※UTCは定数があります。
詳しくはサンプルコードを御覧ください。
サンプルコード
ソース構成
. └── src/ └── main/ └── java/ └── com/ └── example/ └── app/ ├── Main.java └── Rfc3339DateTimeConverter.java
ソース
Main.java
package com.example.app; import java.time.OffsetDateTime; import java.time.ZoneOffset; public class Main { private Rfc3339DateTimeConverter converter; Main() { this.converter = new Rfc3339DateTimeConverter(); } private void test(String dateString) { OffsetDateTime dateTime = this.converter.parse(dateString); String resultString = this.converter.format(dateTime, "yyyy/MM/dd HH:mm:ss.SSSSSSS"); // UTCに変換 OffsetDateTime utcDateTime = this.converter.changeTimeZoneOffset(dateTime, ZoneOffset.UTC); String resultStringUTC = this.converter.format(utcDateTime, "yyyy/MM/dd HH:mm:ss.SSSSSSS"); // 日本時間(JST)に変換 OffsetDateTime jstDateTime = this.converter.changeTimeZoneOffset(dateTime, ZoneOffset.ofHours(9)); String resultStringJST = this.converter.format(jstDateTime, "yyyy/MM/dd HH:mm:ss.SSSSSSS"); System.out.println("元:" + dateString + " => 無加工:" + resultString + " (UTCに変換:" + resultStringUTC + ") (日本時間に変換:" + resultStringJST + ")"); } public static void main(String[] args) { Main main = new Main(); System.out.println("1. 標準"); main.test("2023-05-17T00:12:34Z"); main.test("2023-05-17T00:12:34.100Z"); System.out.println("2. 末尾の0省略"); main.test("2023-05-17T00:12:34.1Z"); main.test("2023-05-17T00:12:34.12Z"); main.test("2023-05-17T00:12:34.123Z"); main.test("2023-05-17T00:12:34.1234Z"); main.test("2023-05-17T00:12:34.12345Z"); main.test("2023-05-17T00:12:34.123456Z"); main.test("2023-05-17T00:12:34.1234567Z"); main.test("2023-05-17T00:12:34.1000000Z"); System.out.println("3. タイムゾーンオフセットを数値で表す"); main.test("2023-05-17T00:12:34+09:00"); main.test("2023-05-17T00:12:34.100+09:00"); System.out.println("4. 末尾の0省略"); main.test("2023-05-17T00:12:34.1+09:00"); main.test("2023-05-17T00:12:34.12+09:00"); main.test("2023-05-17T00:12:34.123+09:00"); main.test("2023-05-17T00:12:34.1234+09:00"); main.test("2023-05-17T00:12:34.12345+09:00"); main.test("2023-05-17T00:12:34.123456+09:00"); main.test("2023-05-17T00:12:34.1234567+09:00"); main.test("2023-05-17T00:12:34.1000000+09:00"); System.out.println("5. タイムゾーンずらし"); main.test("2023-04-10T22:00:00Z"); main.test("2023-04-10T23:00:00Z"); main.test("2023-05-17T00:00:00Z"); main.test("2023-05-17T01:00:00Z"); main.test("2023-05-17T02:00:00Z"); main.test("2023-05-17T03:00:00Z"); main.test("2023-05-17T04:00:00Z"); main.test("2023-05-17T05:00:00Z"); main.test("2023-05-17T06:00:00Z"); main.test("2023-05-17T07:00:00Z"); main.test("2023-05-17T08:00:00Z"); main.test("2023-05-17T09:00:00Z"); // 以下エラーパターン // main.test("2023-05-17T00:12:34"); // タイムゾーンオフセット指定がないとエラー // main.test("2023-05-17T00:12:34+0900"); // +09:00 のようにコロンが入らないとエラー } }
Rfc3339DateTimeConverter.java
package com.example.app; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; public class Rfc3339DateTimeConverter { private DateTimeFormatter formatter; public Rfc3339DateTimeConverter() { this.formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; } /** * RFC3339形式の文字列パースして、OffsetDateTime型を返却 * @param dateString * @return */ public OffsetDateTime parse(String dateString) { OffsetDateTime dateTime = OffsetDateTime.parse(dateString, this.formatter); return dateTime; } /** * OffsetDateTime型を指定フォーマットの文字列に変換 * @param dateTime * @param outPattern * @return */ public String format(OffsetDateTime dateTime, String outPattern) { DateTimeFormatter outFormatter = DateTimeFormatter.ofPattern(outPattern); return dateTime.format(outFormatter); } /** * タイムゾーンオフセットを変更 * @param toTimeZoneOffset * @return */ public OffsetDateTime changeTimeZoneOffset(OffsetDateTime dateTime, ZoneOffset toTimeZoneOffset) { OffsetDateTime newDateTime = dateTime.withOffsetSameInstant(toTimeZoneOffset); return newDateTime; } }
実行結果
1. 標準 元:2023-05-17T00:12:34Z => 無加工:2023/05/17 00:12:34.0000000 (UTCに変換:2023/05/17 00:12:34.0000000) (日本時間に変換:2023/05/17 09:12:34.0000000) 元:2023-05-17T00:12:34.100Z => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/17 00:12:34.1000000) (日本時間に変換:2023/05/17 09:12:34.1000000) 2. 末尾の0省略 元:2023-05-17T00:12:34.1Z => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/17 00:12:34.1000000) (日本時間に変換:2023/05/17 09:12:34.1000000) 元:2023-05-17T00:12:34.12Z => 無加工:2023/05/17 00:12:34.1200000 (UTCに変換:2023/05/17 00:12:34.1200000) (日本時間に変換:2023/05/17 09:12:34.1200000) 元:2023-05-17T00:12:34.123Z => 無加工:2023/05/17 00:12:34.1230000 (UTCに変換:2023/05/17 00:12:34.1230000) (日本時間に変換:2023/05/17 09:12:34.1230000) 元:2023-05-17T00:12:34.1234Z => 無加工:2023/05/17 00:12:34.1234000 (UTCに変換:2023/05/17 00:12:34.1234000) (日本時間に変換:2023/05/17 09:12:34.1234000) 元:2023-05-17T00:12:34.12345Z => 無加工:2023/05/17 00:12:34.1234500 (UTCに変換:2023/05/17 00:12:34.1234500) (日本時間に変換:2023/05/17 09:12:34.1234500) 元:2023-05-17T00:12:34.123456Z => 無加工:2023/05/17 00:12:34.1234560 (UTCに変換:2023/05/17 00:12:34.1234560) (日本時間に変換:2023/05/17 09:12:34.1234560) 元:2023-05-17T00:12:34.1234567Z => 無加工:2023/05/17 00:12:34.1234567 (UTCに変換:2023/05/17 00:12:34.1234567) (日本時間に変換:2023/05/17 09:12:34.1234567) 元:2023-05-17T00:12:34.1000000Z => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/17 00:12:34.1000000) (日本時間に変換:2023/05/17 09:12:34.1000000) 3. タイムゾーンオフセットを数値で表す 元:2023-05-17T00:12:34+09:00 => 無加工:2023/05/17 00:12:34.0000000 (UTCに変換:2023/05/16 15:12:34.0000000) (日本時間に変換:2023/05/17 00:12:34.0000000) 元:2023-05-17T00:12:34.100+09:00 => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/16 15:12:34.1000000) (日本時間に変換:2023/05/17 00:12:34.1000000) 4. 末尾の0省略 元:2023-05-17T00:12:34.1+09:00 => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/16 15:12:34.1000000) (日本時間に変換:2023/05/17 00:12:34.1000000) 元:2023-05-17T00:12:34.12+09:00 => 無加工:2023/05/17 00:12:34.1200000 (UTCに変換:2023/05/16 15:12:34.1200000) (日本時間に変換:2023/05/17 00:12:34.1200000) 元:2023-05-17T00:12:34.123+09:00 => 無加工:2023/05/17 00:12:34.1230000 (UTCに変換:2023/05/16 15:12:34.1230000) (日本時間に変換:2023/05/17 00:12:34.1230000) 元:2023-05-17T00:12:34.1234+09:00 => 無加工:2023/05/17 00:12:34.1234000 (UTCに変換:2023/05/16 15:12:34.1234000) (日本時間に変換:2023/05/17 00:12:34.1234000) 元:2023-05-17T00:12:34.12345+09:00 => 無加工:2023/05/17 00:12:34.1234500 (UTCに変換:2023/05/16 15:12:34.1234500) (日本時間に変換:2023/05/17 00:12:34.1234500) 元:2023-05-17T00:12:34.123456+09:00 => 無加工:2023/05/17 00:12:34.1234560 (UTCに変換:2023/05/16 15:12:34.1234560) (日本時間に変換:2023/05/17 00:12:34.1234560) 元:2023-05-17T00:12:34.1234567+09:00 => 無加工:2023/05/17 00:12:34.1234567 (UTCに変換:2023/05/16 15:12:34.1234567) (日本時間に変換:2023/05/17 00:12:34.1234567) 元:2023-05-17T00:12:34.1000000+09:00 => 無加工:2023/05/17 00:12:34.1000000 (UTCに変換:2023/05/16 15:12:34.1000000) (日本時間に変換:2023/05/17 00:12:34.1000000) 5. タイムゾーンずらし 元:2023-04-10T22:00:00Z => 無加工:2023/04/10 22:00:00.0000000 (UTCに変換:2023/04/10 22:00:00.0000000) (日本時間に変換:2023/04/11 07:00:00.0000000) 元:2023-04-10T23:00:00Z => 無加工:2023/04/10 23:00:00.0000000 (UTCに変換:2023/04/10 23:00:00.0000000) (日本時間に変換:2023/04/11 08:00:00.0000000) 元:2023-05-17T00:00:00Z => 無加工:2023/05/17 00:00:00.0000000 (UTCに変換:2023/05/17 00:00:00.0000000) (日本時間に変換:2023/05/17 09:00:00.0000000) 元:2023-05-17T01:00:00Z => 無加工:2023/05/17 01:00:00.0000000 (UTCに変換:2023/05/17 01:00:00.0000000) (日本時間に変換:2023/05/17 10:00:00.0000000) 元:2023-05-17T02:00:00Z => 無加工:2023/05/17 02:00:00.0000000 (UTCに変換:2023/05/17 02:00:00.0000000) (日本時間に変換:2023/05/17 11:00:00.0000000) 元:2023-05-17T03:00:00Z => 無加工:2023/05/17 03:00:00.0000000 (UTCに変換:2023/05/17 03:00:00.0000000) (日本時間に変換:2023/05/17 12:00:00.0000000) 元:2023-05-17T04:00:00Z => 無加工:2023/05/17 04:00:00.0000000 (UTCに変換:2023/05/17 04:00:00.0000000) (日本時間に変換:2023/05/17 13:00:00.0000000) 元:2023-05-17T05:00:00Z => 無加工:2023/05/17 05:00:00.0000000 (UTCに変換:2023/05/17 05:00:00.0000000) (日本時間に変換:2023/05/17 14:00:00.0000000) 元:2023-05-17T06:00:00Z => 無加工:2023/05/17 06:00:00.0000000 (UTCに変換:2023/05/17 06:00:00.0000000) (日本時間に変換:2023/05/17 15:00:00.0000000) 元:2023-05-17T07:00:00Z => 無加工:2023/05/17 07:00:00.0000000 (UTCに変換:2023/05/17 07:00:00.0000000) (日本時間に変換:2023/05/17 16:00:00.0000000) 元:2023-05-17T08:00:00Z => 無加工:2023/05/17 08:00:00.0000000 (UTCに変換:2023/05/17 08:00:00.0000000) (日本時間に変換:2023/05/17 17:00:00.0000000) 元:2023-05-17T09:00:00Z => 無加工:2023/05/17 09:00:00.0000000 (UTCに変換:2023/05/17 09:00:00.0000000) (日本時間に変換:2023/05/17 18:00:00.0000000)
補足(OKの形式、エラーになる形式)
OKの形式
"2023-05-17T00:12:34Z" // OK(Z=UTC, 秒以下なし) "2023-05-17T00:12:34.100Z" // OK(ミリ秒まで指定) "2023-05-17T00:12:34.1Z" // OK(1/10秒まで指定) "2023-05-17T00:12:34.1234567Z" // OK(秒以下7桁もOK) "2023-05-17T00:12:34+09:00" // OK(Zではなく、タイムゾーンで指定) "2023-05-17T00:12:34.100+09:00" // OK(Zではなく、タイムゾーンで指定、ミリ秒まで指定)
エラーの形式
"2023-05-17T00:12:34" // NG(タイムゾーンオフセット指定がないとエラー) "2023-05-17T00:12:34+0900" // NG(+09:00のようにコロンが入らないとエラー)
参考
参照
参考サイト
Special thanks
-
日付フォーマットはSimpleDateFormatと同様のものが使えるものと思われます。 ↩︎