素早い回答
最初の文字列は日付形式とローカル タイム ゾーンを使用して正しく解析されますが、2 番目の文字列はそれを尊重しないため、SimpleDateFormat
ミリ秒を持たない既定のオブジェクトによって解析されます ("yyyy-MM-dd'T'HH:mm:ss' Z' は解析形式) であり、UTC タイムゾーンを使用して時間部分の「シフト」を提供します。
完全な答え
あなたの質問に完全に答えるには、Gson のソース コードに飛び込む必要があります。特に、DefaultDateTypeAdapter
日付の解析に使用されるコードを確認する必要があります。このコードはすべてリンクにありますが、簡単に参照できるように、最も関連性の高い部分をここにコピーします。
ビルダーでこれを呼び出すと、次のようになります。
gb.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
この方法で DefaultDateTypeAdapter を初期化しています。
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
this.enUsFormat = enUsFormat;
this.localFormat = localFormat;
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
}
どこ:
enUsFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
と
localFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)
ビルダーに渡した文字列から。
Locale.US
これはタイムゾーンではなく、ミリ秒がなくても UTC タイムゾーンがiso8601Format
ある場合と同じであることに注意してください。enUsFormat
解析はdeserializeToDate
メソッドで行われます:
private Date deserializeToDate(JsonElement json) {
synchronized (localFormat) {
try {
return localFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return enUsFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return iso8601Format.parse(json.getAsString());
} catch (ParseException e) {
throw new JsonSyntaxException(json.getAsString(), e);
}
}
}
ここでは、3 つの日付形式すべてがウォーターフォール アプローチで使用されています。
最初の Json 文字列: "2011-11-02T02:50:12.208Z"。ミリ秒単位なので、すぐに解析されlocalFormat
、タイムゾーンを使用して期待する結果が得られます。
2 番目の Json 文字列: "1899-12-31T16:00:00Z"。ミリ秒がないため解析されないため、ロケールを除いて同じパターンlocalFormat
である enUsFormat が 2 番目のチャンスです。したがって、同じように失敗します。
解析する最後のチャンス: iso8601Format
、ミリ秒はありませんが、構築のために UTC タイムゾーンとしても使用されるため、日付を UTC として解析し、他の人はあなたのタイムゾーンを使用して解析します。