Преобразование локальной метки времени к UTC устанавливает метку времени в Java

У меня есть метка времени milliseconds-since-local-epoch, которую я хотел бы преобразовать в метку времени milliseconds-since-UTC-epoch. От быстрого взгляда до документов похоже, что что-то вроде этого работало бы:

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

Существует ли лучший способ сделать это?

15
задан Jeremy Logan 9 April 2010 в 16:59
поделиться

3 ответа

Используйте Календарь , чтобы узнать, какое смещение было в локальной Эпохе, затем добавьте это к метке времени локальной эпохи.

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
ответ дан 1 December 2019 в 03:04
поделиться

Нет, это точно не сработает - летнее время не учитывается. Вы также не можете просто использовать getOffset (oldTime) , поскольку летнее время могло измениться между двумя ...

Вы можете использовать getOffset (oldTime) , чтобы получить начальное угадайте метку времени, затем проверьте getOffset (utcTime) , чтобы узнать, совпадают они или нет. По сути, это доставляет удовольствие.

Joda Time должен поддерживать это, используя DateTimeZone.getOffsetFromLocal , но это слегка нарушено (IMO) при переходах на летнее время.

Все это действительно зависит от того, что вы подразумеваете под «миллисекундами с местной эпохи». Если вы на самом деле имеете в виду миллисекунды, прошедшие с местного 1970 года, вы можете просто узнать смещение на эту дату и применить его независимо. Обычно (IME) «локальное» значение в миллисекундах не совсем этого означает - оно означает «количество миллисекунд, необходимое для перехода к определенной дате и времени (например, 9 апреля 2010 г., 18:06 вечера) по всемирному координированному времени, но в отношении другой часовой пояс ». Другими словами, он может представлять неоднозначные или невозможные комбинации даты и времени на основе переходов на летнее время.

2
ответ дан 1 December 2019 в 03:04
поделиться

К сожалению, это, кажется, лучший способ сделать это:

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's ответ неверный.)

9
ответ дан 1 December 2019 в 03:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: