web-dev-qa-db-ja.com

Java)でローカルタイムスタンプをUTCタイムスタンプに変換する

ミリ秒-since-local-Epochタイムスタンプをミリ秒-since-UTC-Epochタイムスタンプに変換したいのですが。ドキュメントを一目見ただけで、次のように機能するように見えます。

int offset = TimeZone.getDefault().getRawOffset();
long newTime = oldTime - offset;

これを行うためのより良い方法はありますか?

15
Jeremy Logan

Calendarを使用して、ローカルエポックでのオフセットを取得し、それをローカルエポックタイムスタンプに追加します。

public static long getLocalToUtcDelta() {
    Calendar local = Calendar.getInstance();
    local.clear();
    local.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
    return local.getTimeInMillis();
}

public static long converLocalTimeToUtcTime(long timeSinceLocalEpoch) {
    return timeSinceLocalEpoch + getLocalToUtcDelta();
}
7
leedm777

悲しいことに、これはこれを行うための最良の方法のようです:

public static Date convertLocalTimestamp(long millis)
{
    TimeZone tz = TimeZone.getDefault();
    Calendar c = Calendar.getInstance(tz);
    long localMillis = millis;
    int offset, time;

    c.set(1970, Calendar.JANUARY, 1, 0, 0, 0);

    // Add milliseconds
    while (localMillis > Integer.MAX_VALUE)
    {
        c.add(Calendar.MILLISECOND, Integer.MAX_VALUE);
        localMillis -= Integer.MAX_VALUE;
    }
    c.add(Calendar.MILLISECOND, (int)localMillis);

    // Stupidly, the Calendar will give us the wrong result if we use getTime() directly.
    // Instead, we calculate the offset and do the math ourselves.
    time = c.get(Calendar.MILLISECOND);
    time += c.get(Calendar.SECOND) * 1000;
    time += c.get(Calendar.MINUTE) * 60 * 1000;
    time += c.get(Calendar.HOUR_OF_DAY) * 60 * 60 * 1000;
    offset = tz.getOffset(c.get(Calendar.ERA), c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.DAY_OF_WEEK), time);

    return new Date(millis - offset);
}

(これは投稿日から数か月後のことですが、Androidでテキストメッセージを操作するときに解決するのに非常に役立つ問題です。daveの答えは間違っています。)

9
Ross Light

実はクリス・ラーチャーが頭に釘を打ったのですが、短いコメントでしかできなかったので、さらに詳しく説明したいと思いました。

2つのストップウォッチを想像してみてください。 1つはUTCが1970年1月1日の現地時間であり、もう1つのストップウォッチはお住まいの地域の現地時間です(UTCの5時間後のニューヨークにあるとしましょう)。 1970年1月1日のUTC真夜中に、UTCストップウォッチが開始されます。 5時間後、ローカルストップウォッチが開始されます。これらの2つのストップウォッチ時間は、ある程度異なりますTCと1970年1月1日の現地時間現地時間との差によってのみ決定されます。それ以来、夏時間のシェナニガンは、これらのストップウォッチの違いとは関係ありません。したがって、現在の時間または変換中の時間のDST修正は関係ありません。 必要なのは、1970年1月1日にローカルストップウォッチが開始されてからどれくらい後かです。

クリスが指摘したように、これはただ:getOffset(0L)なので、次のようになります。

int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;

...正常に動作するはずです。 ただし..。

これを実際に把握しやすくするために、getOffset()の「0L」はUTCエポック(唯一のrealエポック)からのミリ秒であることに注意してください。したがって、オフセット変数には、UTCの午前0時(つまり、ニューヨークで1969年12月31日の19:00だったとき)のオフセットの秒数が含まれます。 local深夜前の最後の数時間に現地時間が夏時間に切り替えられた場合、getOffset(0L)は正しくありません。 UTCの深夜ではなく、local深夜の夏時間のステータスを知る必要があります。

これがどこにでも当てはまるとしたら、私は驚きます(つまり、1970年1月1日の現地の深夜とUTCの深夜の間にDSTとの間で変更されたタイムゾーン)。ただし、楽しみのために、これを防ぐための安価なハックは、その時間内にオフセットが変更されたかどうかを確認することです。

// Offset at UTC midnight
int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;
// Offset at Local midnight
int localMidnightOffset = TimeZone.getDefault().getOffset(-offset);

ここで、localMidnightOffsetは、1970年のUTC午前0時からミリ秒後のタイムゾーンオフセットでした。DSTの変更が発生しなかった場合、localMidnightOffsetはoffsetと等しくなり、完了です。 DSTの変更didが発生した場合は、探し回る必要があるかもしれません...おそらく

localMidnightOffset = TimeZone.getDefault().getOffset(-localMidnightOffset)

それが変化しなくなるまで...そしてあなたが無限ループに巻き込まれないことを願っています。誰かが保証された収束ソリューションを持っているかどうかを知りたいです。

ちょっと、世界がフラットだったらいいのにと思いますよね?

3
Jemenake

Joda Timeを使用すると、次のようになります。

DateTime dt = new DateTime(year, month, day, hour, minute, 0, 0, DateTimeZone.forID("local");

dt.getMillis();

編集:申し訳ありませんが、これは正しいバージョンです:

DateTime dt = new DateTime(timestamp, DateTimeZone.forID("local");

dt.getMillis();
3
lisak

いいえ、それは間違いなく機能しません。DSTは考慮されていません。 DSTが2つの間で変更された可能性があるため、getOffset(oldTime)だけを使用することもできません...

getOffset(oldTime)を使用してタイムスタンプの初期推定値を取得し、getOffset(utcTime)をチェックしてそれらが同じかどうかを確認できます。基本的には楽しくなります。

Joda TimeshouldDateTimeZone.getOffsetFromLocal しかし、それは わずかに壊れています (IMO)DST遷移の周りです。

これはすべて、「ローカルエポックからのミリ秒」の意味によって異なります。 reallyがローカル1970からの経過ミリ秒を意味する場合、その日付のオフセットを見つけて、それに関係なく適用できます。通常(IME)の「ローカル」ミリ値は、それを意味するわけではありません。UTCで特定の日時(2010年4月9日、午後18時6分など)に到達するためのミリ数を意味しますが、別のタイムゾーン」。つまり、DST遷移に基づいて、あいまいまたは不可能な日付/時刻の組み合わせを表すことができます。

2
Jon Skeet
static final long localTimeZoneoffset = TimeZone.getDefault().getOffset(0L);
static final long dstOffset = TimeZone.getDefault().getDSTSavings();

long offsetOftime = TimeZone.getDefault().getOffset(time.getTime());
long timeinmilli = 0L; 
if(offsetOftime != localTimeZoneoffset)
   timeinmilli = time.getTime()+localTimeZoneoffset+dstOffset;
else
   timeinmilli = time.getTime()+localTimeZoneoffset;
return new Timestamp(timeinmilli);

これは私がUTCに変換するのに役立ちました。

0
Wilson

これは私がこの方法を試したのに役立つかもしれません。現地時間をUTCタイムスタンプに変換するための最良かつ最適化された方法がある場合はコメントしてください。

_String mDate= "Jul 21,2016 1:23 PM";
String mDateFormat =""MMM d,yyyy h:mm a";
_

呼び出し:getConvertedTimeToUTC(mDate,mDateFormat);

_     public String getConvertedTimeToUTC(String ourDate, String mDateFormat) {
            try {
                SimpleDateFormat fmt = new SimpleDateFormat(mDateFormat);
                fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
                Date value = fmt.parse(ourDate);
                if (value != null)
                    return String.valueOf(value.getTime() / 1000);
                else
                    return null;
            } catch (Exception e) {
                ourDate = "00-00-0000 00:00";
            }
            return ourDate;
        }
_

結果は次のとおりです: (参照:変換を確認)

_Result 1469107380
GMT: Thu, 21 Jul 2016 13:23:00 GMT
Your time zone: Thursday 21 July 2016 06:53:00 PM IST GMT+5:30
_
0
Chintan Khetiya