Преобразование временной метки unix между разными часовыми поясами и другим летним временем в Java

ПРОБЛЕМА РЕШЕНА Внешнее устройство вычисляло и отправляло нестандартную отметку времени, сдвинутую на 2 часа, что сильно смутило меня и привело к созданию этой темы. ОТМЕТКА ВРЕМЕНИ САМ ПО СЕБЕ НЕ ВЛИЯЕТ НА ВРЕМЯ ЧАСОВЫХ ПОЯСОВ , часовые пояса применяются только при преобразовании в/из удобочитаемых форм.


У меня есть временная метка (секунды от эпохи unix) в часовом поясе UTC - без летнего времени (летнее время).

Мне нужна отметка времени (секунды от эпохи unix) в часовом поясе «Европа/Прага», в котором используется летнее время.

Раньше я думал, что временная метка unix не привязана к часовым поясам, что часовые пояса влияют только на процесс преобразования временной метки в удобочитаемый формат. Но это не похоже на это. И чем больше я пытаюсь его преобразовать (используя классы Calendar и TimeZone), тем больше я путаюсь и теряюсь.

этот код НЕ работает должным образом:

Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(ts*1000);
cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
return cal.getTimeInMillis()/1000;

person David162795    schedule 22.04.2013    source источник
comment
Что оно делает? Что происходит, когда вы распечатываете кал между каждой строкой кода?   -  person Peter Lawrey    schedule 22.04.2013
comment
Возможно, вам следует указать, заинтересованы ли вы в решениях Joda-Time, потому что я подозреваю, что вы начать их получать.   -  person Duncan Jones    schedule 22.04.2013
comment
@Peter для недавней метки времени «1366642620» вернул ту же самую - преобразования не произошло. Если я попытаюсь распечатать эту метку времени в PHP в часовых поясах UTC и Европы/Праги, я получу другое время: 14:57 и 16:57.   -  person David162795    schedule 22.04.2013
comment
Когда вы получаете TimeInMillis(), вы отбрасываете только что добавленный часовой пояс. Смотрите мой пример в моем ответе.   -  person Peter Lawrey    schedule 22.04.2013


Ответы (4)


Нет способа «преобразовать» временную метку, это всегда количество миллисекунд от эпохи.

Вы можете использовать DateFormat для форматирования метки времени в формате с примененным часовым поясом или использовать Calendar для просмотра часов, минут и секунд с примененным часовым поясом.

getTimeInMillis() возвращает отметку времени точно так же, как вы ее ввели, количество миллисекунд от эпохи: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#getTimeInMillis%28%29

person worpet    schedule 22.04.2013

Вот пример кода для преобразования эпохи между часовыми поясами.

public static long convertTimeZone(long lngDate, String fromTimeZone,
        String toTimeZone) {        
    Calendar fromTime = Calendar.getInstance();
    fromTime.setTimeZone(TimeZone.getTimeZone(fromTimeZone));
    fromTime.setTimeInMillis(lngDate);
    Calendar toTime = new GregorianCalendar(
            TimeZone.getTimeZone(toTimeZone));
    toTime.set(Calendar.DATE, fromTime.get(Calendar.DATE));
    toTime.set(Calendar.MONTH, fromTime.get(Calendar.MONTH));
    toTime.set(Calendar.YEAR, fromTime.get(Calendar.YEAR));
    toTime.set(Calendar.HOUR_OF_DAY, fromTime.get(Calendar.HOUR_OF_DAY));
    toTime.set(Calendar.MINUTE, fromTime.get(Calendar.MINUTE));
    toTime.set(Calendar.SECOND, fromTime.get(Calendar.SECOND));
    toTime.set(Calendar.MILLISECOND, fromTime.get(Calendar.MILLISECOND));
    LOG.debug("Converted " + fromTime.getTimeInMillis() + " to "
            + toTime.getTimeInMillis());
    SimpleDateFormat sdf = new SimpleDateFormat(
            "dd-MMM-yyyy HH:mm:ss.SSS z");      
    sdf.setTimeZone(TimeZone.getTimeZone(fromTimeZone));        
    SimpleDateFormat sdf1 = new SimpleDateFormat(
            "dd-MMM-yyyy HH:mm:ss.SSS z");      
    sdf1.setTimeZone(TimeZone.getTimeZone(toTimeZone));
    LOG.debug("Converted " + sdf.format(fromTime.getTime()) + " to " + sdf1.format(toTime.getTime()));
    return toTime.getTimeInMillis();
}

Вывод:

System.out.println(convertTimeZone(new Date().getTime(),"America/New_York","Asia/Singapore"));
Converted 1384514879944 to 1384468079944
Converted 15-Nov-2013 06:27:59.944 EST to 15-Nov-2013 06:27:59.944 SGT
person DeepaGanesh    schedule 15.11.2013
comment
я делал это в течение более 4 часов. и я, наконец, получил правильный результат. Кажется, это либо ошибка в java, либо добавленная вами строка, которая добавляет миллисекунды к объекту toTime, что приводит к разнице почти в 3 часа от utc до местного часового пояса. - person Ahad; 14.12.2016

Он ведет себя так, как я ожидал

public static void main(String... ignored) {
    long ts = System.currentTimeMillis() / 1000;
    Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
    printCalendar(cal);
    cal.setTimeInMillis(ts * 1000);
    printCalendar(cal);
    cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
    printCalendar(cal);
}

public static void printCalendar(Calendar calendar) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS ZZZ");
    sdf.setTimeZone(calendar.getTimeZone());
    System.out.println(sdf.format(calendar.getTime()));
}

отпечатки

2013/04/22 13:28:06.451 +0000
2013/04/22 13:28:06.000 +0000
2013/04/22 15:28:06.000 +0200
person Peter Lawrey    schedule 22.04.2013

Вы можете легко конвертировать между двумя часовыми поясами следующим образом:

1. Предположим, что это дата и время в часовом поясе EST

String value = "2006-11-28 09:45:12";  
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
df1.setTimeZone(TimeZone.getTimeZone("EST"));  

2. Анализирует значение и предполагает, что оно представляет дату и время в часовом поясе EST

Date d = df1.parse(value);     
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
df2.setTimeZone(TimeZone.getTimeZone("CET")); 

3. Форматирует дату в часовом поясе CET

System.out.println(df2.format(d)); 
person Shreyos Adikari    schedule 22.04.2013
comment
Я видел похожий пример, но он вводится в формате (часы, минуты, секунды), а не в метке времени unix. Суть моей проблемы в том, что я не знаю, как загрузить «метку времени unix» из другого часового пояса. Calendar.setTimeinMilis() ведет себя так, как будто он работает в системном часовом поясе, а не в часовом поясе, установленном в объекте календаря. - person David162795; 22.04.2013
comment
Как получить реальную дату вместо строки? - person Tulains Córdova; 02.05.2016