2017-07-05 14 views
3

Java DataTimeFormmaterに問題があります。 私は何かを逃したと感じますが、正確に何が分かりません。DateTimeFormatterでカスタム日付書式が解析されない

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'zxxx"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); 

String date = "2017-07-05T12:28:36.4TGMT+03:00"; 

System.out.println(formatter.format(ZonedDateTime.now())); 
System.out.println(formatter.parse(date)); 

上記のコードは、現在のZonedDateTimeの文字列を生成し、同じ日付フォーマッタと日時文字列を解析することを試みます。それが成功し2017-07-05T06:07:51.0TCDT-05:00を生産するが、私の目標は2017-07-05T12:28:36.4TGMT+03:00を解析し、適切なDateTimeFormatterを思い付くことです2017-07-05T12:28:36.4TGMT+03:00

解析に失敗 結果。 zzz全体GMT+03:00一部または単にゾーンの短い名前(例えばCDTをなど)、およびxxxパースのどちらかを解析することができますので、

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'[zzz][xxx]"; 

両方[zzz][xxx]はオプションのセクションにあります。

+1

これは奇妙なフォーマットです。可能であれば、標準の[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)フォーマットに固執してください。 –

答えて

3

あなたはに書式を変更する必要がありますオフセット部分のみ(-05:00など - GMT+03:00が見つかる場合は不要です)。

formatter.parse(date)は、TemporalAccessorオブジェクトを返します。

System.out.println(ZonedDateTime.parse(date, formatter)); // 2017-07-05T12:28:36.400+03:00[GMT+03:00] 

PS:あなたが特定のタイプを作成する場合、それはクラスのそれぞれのparseメソッドを使用する方が良いでしょうをこのフォーマッタを持つ唯一の問題は、書式設定するとき、それはすべてのオプションを印刷し、ということですセクション。あなたはこのような何かを行うのであれば、:

String date = "2017-07-05T12:28:36.4TGMT+03:00"; 
ZonedDateTime z = ZonedDateTime.parse(date, formatter); 
System.out.println(formatter.format(z)); 

は、出力は次のようになります。

2017-07-05T12:28:36.4TGMT + 03:00 + 03:00

GMT+03:00zzzの結果であり、2番目の+03:00xxxの結果であるからです。あなたがこれを望まないなら、私は2種類の異なるDateTimeFormatter(構文解析のためのもの、フォーマットのためのもの)を使用して推薦します。

か(「醜い」アプローチ)、2つの異なるフォーマッタを使用します。次に

DateTimeFormatter noGMT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'zzzxxx"); 
DateTimeFormatter gmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'TGMT'xxx"); 

は、あなたが最初に解析しよう - あなたは例外を取得する場合、第二にしてみてください(またはあなたがいるかどうかをチェック入力にはGMTが含まれています)。

私は個人的にはこれが好きではありません。GMTはゾーン名の一部であり、リテラルとして扱われるべきではないからです。しかし最終的には、正しいオフセットでZonedDateTimeが得られるので、このアプローチがどれほど間違っているか分かりません。


タイムゾーンの略語

彼らはambiguous and not standardているので、あなたが(CDTまたはなど)3文字の略称を使用して(可能な限り)避けなければならないことに注意してください。 CDTは、Central Daylight Time(UTC-05:00)、Cuba Daylight Time(UTC-04:00)またはChina Daylight Time(UTC + 09:00)のいずれでもかまいません。

可能であれば、IANA timezones names(常にAmerica/Sao_PauloまたはEurope/Berlinのような形式Continent/City)を使用することをお勧めします。そのリストに基づいて、CDTの省略形を使用する(または過去に使用した)40以上のタイムゾーンがあります。

CDTこのような場合には省略時の値が設定されている可能性がありますが、これはおそらく互換性の理由によるものですが、すべての場合に頼ってはいけません。

タイムゾーンの略語が常に機能するようにするには(使用できない場合に備えて)、優先ゾーンのセットを使用するフォーマッタを作成します。この場合、私は(そう、CSTまたはCDTはシカゴのタイムゾーンとして解析されます)America/Chicagoを使用しています:

Set<ZoneId> preferedZones = new HashSet<>(); 
preferedZones.add(ZoneId.of("America/Chicago")); 
DateTimeFormatter formatter = new DateTimeFormatterBuilder() 
    // append first part of pattern (before timezone) 
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'") 
    // append zone name, use prefered zones (optional) 
    .optionalStart().appendZoneText(TextStyle.SHORT, preferedZones).optionalEnd() 
    // offset (optional) 
    .appendPattern("[xxx]") 
    // create formatter 
    .toFormatter(); 

このフォーマッタが(ととGMTなし)の両方ご入力に対して、上記と同じように動作し、 CDTが入力されている場合は、デフォルトのタイムゾーンとしてAmerica/Chicagoを使用します。ユースケースに応じて、セット内に必要な数のゾーンを追加できます。

上記のように、このフォーマッタは出力に関して同じ問題があることを思い出してください(すべてのオプションセクションを出力します)。

+2

もタイムゾーンに 'OOOO'を使用することができますが、Java 8で修正されました。[JDK-8154050](http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8154050) –

+0

@CarlosHeuberger確かに!私は 'OOOO'で試してみましたが、フォーマットのためにのみ動作します。 –

+0

これは正しいですが、コードは間違っています。第2行目 'int pos = position; int end = pos + text.length(); 'endはStringIndexOutOfBoundsExceptionの原因となるStringの長さよりも大きいです(positionは、タイムゾーンを探す場所です) –

2

TL; DR

OffsetDateTime.parse(
    "2017-07-05T12:28:36.4TGMT+03:00".replace("TGMT" , "") 
) 

詳細

あなたのフォーマットが標準ISO 8601形式の奇妙な誤解や破損のような、奇妙です。すべての入力が最後の部分に「TGMT」を持っている場合

、ISOに準拠することを取り除く8601

。だから、必要に文字列を生成していない/解析するときjava.timeクラスは、デフォルトでは標準フォーマットを使用これらは、標準化されていないない実際のタイムゾーンです。CMTEST、およびISTのような3-4 letter擬似タイムゾーンを使用し

OffsetDateTime odt = OffsetDateTime.parse("2017-07-05T12:28:36.4TGMT+03:00".replace("TGMT" , "")) ; 

そして。フォーマットパターンを決して定義していない、とノー一意でも(!)。リアルタイムゾーン名は、America/MontrealまたはPacific/Aucklandのようなcontinent/regionの形式です。

関連する問題