LoginSignup
0
0

More than 1 year has passed since last update.

JavaのDateTimeFormatterのタイムゾーン部分の扱いメモ

Posted at

久しぶりにJavaのコードを書いていて、タイムゾーンを含む文字列のパース・整形のルールが分かりにくかったので調べた結果をメモに残します。

課題

以下のような日時文字列それぞれパースするとき、また出力したいとき DateTimeFormatter として何を使えばよいのか?

  • ISO_DATE_TIME ISO_ZONED_DATE_TIME ISO_OFFSET_DATE_TIME のどれかでよいのか
  • パターンとして yyyy-MM-dd'T'HH:mm:ssZ の最後の Z の部分を指定するならば何?
2023-01-02T04:05:06Z
2023-01-02T04:05:06+0900
2023-01-02T04:05:06+09:00

結論

  • パースするときは、登場する可能性がある形式が以下のどちらかなのかでで判定してパターンを切り替える

    • +09:00 or Z ならば ZZZZZ または ISO_* を使う(どれでもよい)
      • ただし +0900 がくると扱いがややこしい
    • +0900 or Z ならば X を使う
      • こちらを採用しておき、+09:00 の対応のために「入力の末尾が : ならそれを削除する」という前処理がよさそう
  • 整形するとき

    • +0900 と出したい時だけ Z、それ以外は ZZZZZ または ISO_*
      • ただし Z を使うと UTCは Zではなく+0000 になる
      • つまり元の日時のタイムゾーンによって +0900Z を出し分けて出力することはできない

その他

  • ZZZZZZZ を出力につかうと GMT が出現したりする (JST と出すことはむつかしそう)

検証コードと結果

Main.java
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class Main {

    SortedMap<String, DateTimeFormatter> patterns = new TreeMap<>(Map.of(
            "z", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ"),
            "zz", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZ"),
            "zzz", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZ"),
            "zzzz", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZZ"),
            "zzzzz", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZZZ"),
            "x", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX"),
            "iso", DateTimeFormatter.ISO_DATE_TIME,
            "iso_zoned", DateTimeFormatter.ISO_ZONED_DATE_TIME,
            "iso_offset", DateTimeFormatter.ISO_OFFSET_DATE_TIME));

    List<String> inputs = List.of(
            "2023-01-02T04:05:06",
            "2023-01-02T04:05:06Z",
            "2023-01-02T04:05:06+0900",
            "2023-01-02T04:05:06+09:00");

    String testParse() {

        var result = "";
        for (var i : inputs) {
            result += i + " for\n";
            for (var e : patterns.entrySet()) {
                result += "  " + e.getKey() + " => ";
                try {
                    result += ZonedDateTime.parse(i, e.getValue());
                } catch (Exception ex) {
                    result += ex.toString();
                }
                result += "\n";
            }
            result += "\n";
        }

        return result;
    }

    String testFormat() {
        var utc = ZonedDateTime.parse("2023-01-02T04:05:06+00:00");
        var jst = ZonedDateTime.parse("2023-01-02T04:05:06+09:00");
        var inputs = List.of(utc, jst);

        var result = "";

        for (var i : inputs) {
            result += i + ":\n";
            for (var e : patterns.entrySet()) {
                result += "  " + e.getKey() + " => " + i.format(e.getValue()) + "\n";
            }
        }

        return result;
    }

    public static void main(String[] args) {
        System.out.println(new Main().testParse());
        System.out.println(new Main().testFormat());
    }
}

結果

2023-01-02T04:05:06 for
  iso => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {},ISO resolved to 2023-01-02T04:05:06 of type java.time.format.Parsed
  iso_offset => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  iso_zoned => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  x => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  z => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  zz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  zzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  zzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19
  zzzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06' could not be parsed at index 19

2023-01-02T04:05:06Z for
  iso => 2023-01-02T04:05:06Z
  iso_offset => 2023-01-02T04:05:06Z
  iso_zoned => 2023-01-02T04:05:06Z
  x => 2023-01-02T04:05:06Z
  z => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06Z' could not be parsed at index 19
  zz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06Z' could not be parsed at index 19
  zzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06Z' could not be parsed at index 19
  zzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06Z' could not be parsed at index 19
  zzzzz => 2023-01-02T04:05:06Z

2023-01-02T04:05:06+0900 for
  iso => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+0900' could not be parsed, unparsed text found at index 19
  iso_offset => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+0900' could not be parsed, unparsed text found at index 22
  iso_zoned => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+0900' could not be parsed, unparsed text found at index 22
  x => 2023-01-02T04:05:06+09:00
  z => 2023-01-02T04:05:06+09:00
  zz => 2023-01-02T04:05:06+09:00
  zzz => 2023-01-02T04:05:06+09:00
  zzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+0900' could not be parsed at index 19
  zzzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+0900' could not be parsed at index 19

2023-01-02T04:05:06+09:00 for
  iso => 2023-01-02T04:05:06+09:00
  iso_offset => 2023-01-02T04:05:06+09:00
  iso_zoned => 2023-01-02T04:05:06+09:00
  x => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+09:00' could not be parsed, unparsed text found at index 22
  z => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+09:00' could not be parsed at index 19
  zz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+09:00' could not be parsed at index 19
  zzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+09:00' could not be parsed at index 19
  zzzz => java.time.format.DateTimeParseException: Text '2023-01-02T04:05:06+09:00' could not be parsed at index 19
  zzzzz => 2023-01-02T04:05:06+09:00


2023-01-02T04:05:06Z:
  iso => 2023-01-02T04:05:06Z
  iso_offset => 2023-01-02T04:05:06Z
  iso_zoned => 2023-01-02T04:05:06Z
  x => 2023-01-02T04:05:06Z
  z => 2023-01-02T04:05:06+0000
  zz => 2023-01-02T04:05:06+0000
  zzz => 2023-01-02T04:05:06+0000
  zzzz => 2023-01-02T04:05:06GMT
  zzzzz => 2023-01-02T04:05:06Z
2023-01-02T04:05:06+09:00:
  iso => 2023-01-02T04:05:06+09:00
  iso_offset => 2023-01-02T04:05:06+09:00
  iso_zoned => 2023-01-02T04:05:06+09:00
  x => 2023-01-02T04:05:06+09
  z => 2023-01-02T04:05:06+0900
  zz => 2023-01-02T04:05:06+0900
  zzz => 2023-01-02T04:05:06+0900
  zzzz => 2023-01-02T04:05:06GMT+09:00
  zzzzz => 2023-01-02T04:05:06+09:00
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0