5

Joda を使用して単純な Java プログラムで UTC タイムスタンプを取得しようとしています。

public Timestamp getCurrentUTC(LocalDateTime date, DateTimeZone srcTZ, DateTimeZone dstTZ, Locale l) {
    DateTime srcDateTime = date.toDateTime(srcTZ);
    DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);
    
    System.out.println("UTC Time:" + dstDateTime.getMillis());      
    System.out.println("UTC Time:" + new Timestamp(dstDateTime.getMillis()));
    
    return new Timestamp(dstDateTime.getMillis());
}

プログラムの出力は次のとおりです。

UTC Time:1378265162047
UTC Time:2013-09-03 23:26:02.047

ミリ秒の値は正しい UTC 時間です (つまり、GMT-4タイムゾーンで確認されます)。2 番目の値はESTタイムゾーンです。

私が必要とするのはjava.sql.Timestamp、データベースの書き込みのために、変更されていない (つまり、TZ に依存しない) UTC 値です。これは可能ですか?

編集 1

DateTime srcDateTime = date.toDateTime(srcTZ);

DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);

System.out.println("UTC Time:" + dstDateTime.getMillis());

srcDateTimeそれが現地の日付 (GMT-4) であり、dstDateTimeUTC (GMT-0)であることはわかっています。日付の出力値は次のとおりです。

Source Date:2013-09-04T09:10:43.683-04:00

Destination Date: 2013-09-04T13:10:43.683Z

すべての組み合わせを試して、UTC 値をdstDateTimejava.sql.TimeStamp として取得しようとしました。

System.out.println("UTC Time:" + dstDateTime.getMillis());
    
System.out.println("UTC Time:" + new Timestamp(srcDateTime.toDateTime(DateTimeZone.UTC).getMillis()));

System.out.println("UTC Time:" + new Timestamp(dstDateTime.toDateTime(DateTimeZone.UTC).getMillis()));

テスト用の印刷出力:

UTC Time:1378298760226 - Correct UTC

UTC Time:2013-09-04 08:46:00.226 - Incorrect Local Date Time instead of the Expected UTC

UTC Time:2013-09-04 08:46:00.226 - Incorrect Local Date Time instead of the Expected UTC

最初の印刷行は正しい UTC タイムスタンプです。必要なのは、タイプ java.sql.TimeStamp と同じ値だけです。私が試したものは、常にマシンのローカル日時を返しました。

編集 2

私は次のことを試しました:

System.out.println("UTC Timestamp:" + date.toDateTime(srcTZ).getMillis());
System.out.println("UTC Timestamp:" + new Timestamp(date.toDateTime(srcTZ).getMillis()));

出力は次のとおりです。

UTC Time:1378342856315 - Correct UTC Time
UTC Timestap:2013-09-04 21:00:56.315 - Local Time other than the expected UTC Time

TimeStamp に変換しようとすると、取得した有効な UTC 値が失われます。

メソッドのパラメーターに関しては、次のとおりです。

srcTZ = DateTimeZone.forTimeZone(TimeZone.getTimeZone("America/Montreal")
dstTZ = DateTimeZone.forTimeZone(TimeZone.getTimeZone("Etc/UTC"))
Local l = new Locale("en", "CA")

どんな助けでも大歓迎です。

ニック。

編集 3

マットさん、こんにちは。

ご回答ありがとうございます。私たちはあなたと同じ結果を得ています。印刷などについて知りませんでした。より具体的には:

System.out.println("UTC Timestamp:" + srcDateTime.toDateTime(dstTZ).getMillis());
System.out.println("UTC Timestamp:" + srcDateTime.toDateTime(dstTZ));
System.out.println("UTC Timestamp:" + new Timestamp(srcDateTime.toDateTime(dstTZ).getMillis()));

出力が得られます:

UTC Timestamp:1378389098468 - Correct UTC Timestap (Thu, 05 Sep 2013 13:51:38 GMT)
UTC Timestamp:2013-09-05T13:51:38.468Z - Correct UTC Time
UTC Timestamp:2013-09-05 09:51:38.468 - Local time is printed, UTC is expected

DB が UTC ではなく現地時間を格納していることに気付いたとき、この問題に気付きました。

+---------------------+
| effectivedate       |
+---------------------+
| 2013-09-05 09:34:11 |
+---------------------+

Mysql のタイムゾーンは「-00:00」に設定されています

mysql> SELECT CURRENT_TIMESTAMP;
+---------------------+
| CURRENT_TIMESTAMP   |
+---------------------+
| 2013-09-05 13:48:09 |
+---------------------+

Eclipse デバッガーを使用してアプリケーションをデバッグすると、ローカルの日時 (2013-09-05 09:51:38.468) が DB に渡されていることがわかりました (画像を投稿できない、ポイントが足りない...)。データ型はそのままの TimeStamp で、文字列操作はありません。EclipseデバッガーもString.println()関数を使用している可能性がありますが、わかりません..

アプリケーションのデバッグにご協力いただき、誠にありがとうございます。それほど多くの時間 (しゃれた意図はありません) と労力を費やしたくありませんでした...

敬具、

ニック。

4

5 に答える 5

24

これで誰かが 3 日間のでたらめを救ってくれることを願っています。コード内の論理的な場所にデフォルトのタイムゾーンを設定します。環境変数などを設定しなければならないことよりも移植性が高くなります。これを行うには、コード、コンストラクターなどに次の論理的な場所を追加します。

DateTimeZone.setDefault(DateTimeZone.UTC);

UTCを印刷したり、UTCを連結したりできます...

于 2013-09-06T17:14:39.217 に答える
6

この短いプログラムを試してみてください。何が起こっているかを示しているはずです:

LocalDateTime date = LocalDateTime.now();
DateTimeZone tz = DateTimeZone.getDefault();

System.out.println(date);
System.out.println(tz);
System.out.println("-----");
System.out.println(date.toDateTime(tz));
System.out.println(date.toDateTime(tz).toInstant());
System.out.println(date.toDateTime(tz).toDateTime(DateTimeZone.UTC));
System.out.println("-----");
System.out.println(date.toDateTime(tz).getMillis());
System.out.println(date.toDateTime(tz).toInstant().getMillis());
System.out.println(date.toDateTime(tz).toDateTime(DateTimeZone.UTC).getMillis());
System.out.println("-----");
System.out.println(new Timestamp(date.toDateTime(tz).getMillis()));
System.out.println(new Timestamp(date.toDateTime(tz).toInstant().getMillis()));
System.out.println(new Timestamp(date.toDateTime(tz).toDateTime(DateTimeZone.UTC).getMillis()));

私のコンピューターでは、次のように出力されます。

2013-09-04T19:08:35.111
America/Phoenix
-----
2013-09-04T19:08:35.111-07:00
2013-09-05T02:08:35.111Z
2013-09-05T02:08:35.111Z
-----
1378346915111
1378346915111
1378346915111
-----
2013-09-04 19:08:35.111
2013-09-04 19:08:35.111
2013-09-04 19:08:35.111

.toInstant()ご覧のとおり、 または を使用して UTC 時刻に到達できます.toDateTime(DateTimeZone.UTC)。ただし、これらのどちらも呼び出さない場合でも、 を呼び出すと UTC 値が取得されますgetMillis()

したがって、問題は JodaTime にはありません。問題は、結果をどのように評価するかです。

を作成するjava.sql.Timestampと、1970 年 1 月 1 日 UTC からミリ秒単位で渡されます。結果にローカル タイム ゾーンが適用されるのは、それを表示するときだけです。

それを としてデータベースに渡し、Timestamp中間文字列表現を行わないと仮定すると、問題ないはずです。を呼び出したときにローカル時間のように見えるからといってSystem.out.println、内部的にローカル時間であるとは限りません。

java.sql.Timestampクラスが拡張されますjava.util.Date- これは、この動作を取得する場所です。

于 2013-09-05T02:10:27.960 に答える
0

UTC 値が必要ですか、それとも単に Timestamp.toString() メソッドを使用できますか? これにより、SQL ステートメントで使用するフォーマットされた時間文字列が得られます。

于 2013-09-04T05:05:09.840 に答える
0

LocalDateTimeすでにタイムゾーンを除外しています。つまり、ユーザーが「自分の」時間を入力する現地時間を文字通り意味するか (たとえば、葬儀の招待状の場合、常に現地時間になります)、事前に計画している場合はすでに UTC になっています。 .

dateがすでに にあるsrcTZDateTimeZone、としてロードされている場合LocalDateTimeは、戻る必要があります。

new Timestamp(date.toDateTime(srcTZ).toDateTime(DateTimeZone.UTC).getMillis());

dateまたは、が既に UTC (GMT+0) であることが確実な場合は、戻ることができます。

new Timestamp(date.toDateTime(DateTimeZone.UTC).getMillis());

最後に、ほとんどのデータベースは、タイムスタンプを ISO 形式の文字列として受け入れます。これがデフォルトのtoString出力です。

date/*.toDateTime(srcTZ)*/.toDateTime(DateTimeZone.UTC).toString()
于 2013-09-04T05:23:47.710 に答える