2

Android 用の JodaTime ライブラリで ISO 形式の日付を解析しようとすると、間違ったタイムゾーン オフセットが取得されます。

String dateString = "1990-05-03T20:00:00.000Z";
DateTimeFormatter inputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.UTC);
DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.getDefault());
DateTime dt = inputFormatter.parseDateTime(dateString);
String result = outputFormatter.print(dt); 

デフォルトの timeZone は「Europe/Moscow」ですが、結果は「1990-05-03T23:00:00.000+0300」であるはずが「1990-05-04T00:00:00.000+0400」になります。Android版はキットカットです。

私は何を間違えましたか?

4

1 に答える 1

4

過去のタイムスタンプを表示するために実際のモスクワ ゾーン オフセットのみを使用する場合は、次のコードを使用できます。

String dateString = "1990-05-03T20:00:00.000Z";
DateTimeFormatter inputFormatter =
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(DateTimeZone.UTC);
DateTime dt = inputFormatter.parseDateTime(dateString);
System.out.println(dt); // 1990-05-03T20:00:00.000Z

// only use actual offset for Moscow
DateTimeZone zoneOffset =
    DateTimeZone.forOffsetMillis(
        DateTimeZone.forID("Europe/Moscow").getOffset(DateTime.now())
    );
DateTimeFormatter outputFormatter =
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").withZone(zoneOffset);
String result = outputFormatter.print(dt);
System.out.println(result); // 1990-05-03T23:00:00.000+0300

探しているフォームのオフセットと現地時間の部分が異なるだけで、同じ瞬間です。

サーバーからUTC時間を解析する方法についてのコメントについて:

String input = "2016-12-10T13:40:38.595";
DateTime utc =
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").parseLocalDateTime(input)
    .toDateTime(DateTimeZone.UTC);
System.out.println(utc); // 2016-12-10T13:40:38.595Z

デバイスデータが間違っている場合、現在のデバイス時間を UTC としてサーバーに送信する方法は?

最初に言うと、サーバーはクライアントメッセージを受信するときにタイムスタンプを登録するために独自のクロックを使用する必要があるため、現在のクライアントタイムスタンプをサーバーに送信する必要がない場合でも、より良い設計だと思います。これにより、偽のクライアントが無意味な時間を送信するのを効果的に防ぎます。

それ以外の場合、tz-data とデバイス クロック (経由System.currentTimeMillis()) の両方が間違っているが、コメントに示されているようにローカル デバイスのタイムスタンプがまだ正しい場合 (年-月-日-時-分の有効なフィールド値)、次のように適用できます。回避策:

// incorrect platform data from device clock or outdated tz-data
long platformMillis = System.currentTimeMillis();
int offsetMillis = TimeZone.getDefault().getOffset(platformMillis);
DateTimeZone tzPlatform = DateTimeZone.forOffsetMillis(offsetMillis); // +04 on your device

// we assume correct local time if the errors of platform data compensate each other
LocalDateTime ldt = new LocalDateTime(new Date(platformMillis), tzPlatform);

// now we combine local timestamp with the tz-data of Joda-Time (hopefully up-to-date)
long utcMillis = ldt.toDateTime(DateTimeZone.getDefault()).getMillis();

補足: 私のライブラリTime4Aは、より短いソリューションを可能にします。

Moment now = SystemClock.inPlatformView().now().inStdTimezone();
long utcMillis = TemporalType.MILLIS_SINCE_UNIX.from(now);
于 2016-12-10T12:35:06.117 に答える