web-dev-qa-db-ja.com

JacksonによるDateTimeデシリアライゼーションのデフォルトのタイムゾーン(Joda-Timeモジュール)

この質問は、Joda-TimeDateTimejackson-datatype-joda module forジャクソン。日付文字列がデシリアライズされるデフォルトのタイムゾーンはありますか?もしそうなら、それは何ですか? [〜#〜] utc [〜#〜]

JacksonのドキュメントはJoda-Time DateTimeに固有のものではないため、これを尋ねる必要があります。この記事( http://wiki.fasterxml.com/JacksonFAQDateHandling )で、ジャクソンが[〜#〜] gmt [〜#〜]Java.util.DateまたはJava.util.Calendarにデシリアライズするためのデフォルトのタイムゾーンとして。ただし、このドキュメントにはJoda-Timeデータ型に関する言及はありません。さらに、GMTではなく[〜#〜] utc [〜#〜]タイムゾーンを使用して、DateTimeオブジェクトに逆シリアル化する文字列が特に必要です。ゾーンは非常に似ており、いくつかの小さな違いがあるため、GMTは私にとって実現不可能です。

ありがとうございました。

17
ecbrodie

DateTimeDeserializer のソースコードは、逆シリアル化中にDeserializationContextによって提供されるObjectMapperのタイムゾーンを使用することを示しています。 ObjectMapper APIを見ると、タイムゾーンを設定するメソッドがあることがわかります。

_public ObjectMapper setTimeZone(TimeZone tz)
_

したがって、このメソッドを使用してObjectMapperを構成し、タイムゾーンを正しいものに設定できます。

デフォルト値に関係するものについては、Javadocは1つのことを言っているようですが、コードは別のことを示しています。

ObjectMapper.setTimeZone(TimeZone tz)のJavadoc:

_/**
  * Method for overriding default TimeZone to use for formatting.
  * Default value used is {@link TimeZone#getDefault()}.
  */
_

ただし、コードは明示的にタイムゾーンを設定します:

_protected final static BaseSettings DEFAULT_BASE = new BaseSettings(
    ...
    // TimeZone.getDefault()
    TimeZone.getTimeZone("GMT"),
    ...
_

したがって、どうやら、実際にはデフォルトのJVMデフォルトではなくGMTを使用しています。

おそらく最良の選択はこれに依存せず、自分でObjectMapper.setTimeZone(TimeZone tz)に設定することだと思います。

24
Redder

UTC対GMT

ビジネスアプリの場合、 [〜#〜] utc [〜#〜][〜#〜] gmt [〜#〜] の間に実際的な違いはありません。唯一の違いは、1秒未満の解像度と、数年ごとに追加される うるう秒 に関連しています。科学、天文学、衛星追跡などのアプリの場合、違いは大きいかもしれませんが、それはまれです。

ジャクソンのデフォルトはUTC/GMT

わからないJacksonしかし、リンクしたドキュメントを見ると、(a)1970年1月1日からのミリ秒数、UTC、または(b)文字列形式(デフォルトは ISO 8601 形式:「1970-01-01T00:00:00.000 + 0000」。したがって、タイムゾーンに関する質問に答えるために、デフォルトでは、ジャクソンは常に正しい方法であるUTC(タイムゾーンオフセットなし)を使用してシリアル化するように聞こえます。そのときに使用されていたタイムゾーンを気にする場合は、その事実(タイムゾーン)を別のフィールドに記録する必要があります。

ジャクソン↔Java.util.Date/Calendar↔Joda-Time

これらのシリアル化された値(ミリ秒とISO 8601文字列)は両方とも、Joda-Time DateTime インスタンスのコンストラクターで使用できます。

String dateTimeString = "2013-11-22T18:37:55.645+0000";
org.joda.time.DateTime myDateTime = org.joda.time.format.ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime( dateTimeString );

そして…

Long millisSinceEpoch = 1385495462L;
org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( millisSinceEpoch );

Joda-Time DateTimeコンストラクターにフィードするこれらのシリアル化された値に直接アクセスできない場合は、ジャクソンにJava.util.Date/Calendarオブジェクトをインスタンス化させます。これらのJava.util.Date/CalendarオブジェクトをJoda-Timeにフィードして、DateTimeオブジェクトをインスタンス化してさらに処理します。 Joda-Timeユーザーはこれを一般的に行います。

org.joda.time.DateTime myDateTime = new org.joda.time.DateTime( someJavaUtilDateFromJackson );

toDateTime() メソッドを呼び出して目的のタイムゾーンを渡すことにより、そのUTC時間をJoda-Timeの他のタイムゾーンに簡単に変換できます。

org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );
org.joda.time.DateTime dateTimeInKolkata = myDateTime.toDateTime( kolkataTimeZone ); 

Joda-Timeは toDate メソッドを使用して簡単にJava.util.Dateに変換します。したがって、ほとんどの作業はJoda-Timeで行い、Java.util.Dateに変換してJacksonと通信します。また、ジャクソンに戻るとき、ちょうど良い測定のためにDateTimesをUTCに戻します。

myDateTime.toDateTime( org.joda.time.DateTimeZone.UTC )

StackOverflow.comで、前述のJoda-Time操作の多くの例を見つけることができます。

早くやれよ

あなたは少し心配しすぎていて、十分なコーディングをしていないと思います。ジャクソンとジョダタイムに値を出し入れする小さな実験をいくつか試してみてください。すぐに理解できます。デフォルトでやりたいことは何でもジャクソンにさせてから、Joda-Timeで操作することをお勧めします。 Joda-Timeは日付時刻の厄介な問題のために構築されていますが、Jacksonはおそらくそうではありません。 Joda-Timeには、必要に応じてタイムゾーンを調整するコンストラクタとメソッドの両方があります。

より明るい未来

In Java 8、 JSR 310:Date and Time API は、Joda-TimeライクなクラスをJavaプラットフォームに組み込みます。 Jacksonのようなフレームワークを参照して、いJava.util.Date/Calendarクラスを非推奨にしつつ、これらの新しいクラスで直接動作するように更新しました。

jackson-datatype-joda project は、Joda-Timeにそのような便利さをもたらしようとしているようです。しかし、それは私には必要ではないようです。上記のように、Java.util.Date/CalendarとJoda-Timeの間で変換するだけで済みます。

追伸そのプロジェクトのドキュメントの「Wiki」リンクは失敗します。だから私は彼らの文書を見ることができませんでした。

17
Basil Bourque

また、日付の形式に苦労し、最終的に解決策を見つけました。 ISO 8601であり、JavaScript Date オブジェクトで使用されるため、フォーマット_"2016-02-08T12:49:22.876Z"_を使用したかった。また、常にUTCタイムゾーンを使用したいと考えました。

これは次のコードを使用して実行できることがわかりました。

_final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(dateFormat);

System.out.println(objectMapper.writeValueAsString(new Date()));
_

フォーマット文字列のX文字に注意してください。 Java 7からサポートされ、ISO 8601でタイムゾーンを指定します。 SimpleDateFormat で文書化されているように、(代わりにZ of _+00:00_)タイムゾーンオフセットが0(UTC)の場合。

4
Vojta

シンプルなコードから、ジャクソンが文字列からDateオブジェクトにデシリアライズするとき、タイムゾーンが言及されていない場合はUTCを与えるが、直接インスタンス化されると デフォルトのタイムゾーンを与える つまりマシンのタイムゾーンを発見した。

DateTime date = new DateTime(2013, 1, 2, 0, 0) //gives local timezone

以下はUTCを与えます

ObjectMapper mapper = new ObjectMapper();
DateTime dt = new DateTime(2013, 1, 2, 0, 0);
String serialized = mapper.writeValueAsString(dt);
DateTime dt1 = mapper.readValue(serialized, DateTime.class); //gives UTC
1
Neil