Преобразование местного времени во время UTC или наоборот с учетом перехода на летнее время

Я знаю, как преобразовать местное время во время UTC и наоборот. Но я очень смущен обработкой летнего времени (DST) при этом.

Итак, кто-нибудь может ответить на следующие вопросы:
1. Обрабатывает ли Java летнее время при преобразовании между часовыми поясами?
2. Что мне нужно делать при преобразовании между часовыми поясами?
3. Любая хорошая статья, объясняющая это понятнее?

Заранее спасибо.


person Newbie    schedule 14.05.2011    source источник
comment
Чтобы преобразовать между часовыми поясами, вам нужно указать, какой у вас часовой пояс и часовой пояс, в который вы хотите преобразовать. Date использует UTC, поэтому метод getDate() будет UTC. Часовой пояс с переходом на летнее время будет обрабатывать летнее время.   -  person Peter Lawrey    schedule 14.05.2011
comment
Я использую объект календаря. Кроме того, мой вопрос: должен ли я обрабатывать что-либо, связанное с летним временем, при выполнении преобразования??   -  person Newbie    schedule 14.05.2011


Ответы (3)


Вы уверены, что знаете, как конвертировать даты в UTC и обратно? Правильно?
Боюсь, сомневаюсь.

  1. да.
  2. Вам не нужно конвертировать, вам просто нужно назначить правильный часовой пояс.
  3. Для чего нужна статья? Хорошо, я работаю над этим, но пока позвольте мне ответить здесь.

Первым делом. Ваша программа должна хранить дату (или календарь) в UTC TimeZone внутри. Ну, на самом деле в GMT, потому что в Java нет високосных секунд, но это уже другая история.
Единственное место, где вам может понадобиться «преобразование», это когда вы собираетесь отображать время пользователю . Это касается и отправки сообщений электронной почты. В обоих случаях вам нужно отформатировать дату, чтобы получить ее текстовое представление. Для этого вы должны использовать DateFormat и назначить правильный часовой пояс:

    // that's for desktop application
    // for web application one needs to detect Locale
    Locale locale = Locale.getDefault();
    // again, this one works for desktop application
    // for web application it is more complicated
    TimeZone currentTimeZone = TimeZone.getDefault();
    // in fact I could skip this line and get just DateTime instance,
    // but I wanted to show how to do that correctly for
    // any time zone and locale
    DateFormat formatter = DateFormat.getDateTimeInstance(
            DateFormat.DEFAULT,
            DateFormat.DEFAULT,
            locale);
    formatter.setTimeZone(currentTimeZone);

    // Dates "conversion"
    Date currentDate = new Date();
    long sixMonths = 180L * 24 * 3600 * 1000;
    Date inSixMonths = new Date(currentDate.getTime() + sixMonths);

    System.out.println(formatter.format(currentDate));
    System.out.println(formatter.format(inSixMonths));
    // for me it prints
    // 2011-05-14 16:11:29
    // 2011-11-10 15:11:29

    // now for "UTC"
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    System.out.println(formatter.format(currentDate));
    System.out.println(formatter.format(inSixMonths));
    // 2011-05-14 14:13:50
    // 2011-11-10 14:13:50

Как видите, Java заботится об обработке перехода на летнее время. Конечно, вы можете справиться с этим вручную, просто прочитайте JavaDoc, связанный с TimeZone. .

person Paweł Dyda    schedule 14.05.2011
comment
Через шесть месяцев должно быть примерно через шесть месяцев, но это не имеет большого значения. Часовая часть имеет значение. - person Paweł Dyda; 14.05.2011

Вот лучшее решение, которое я нашел. Я копирую его сюда, но решение пришло с сайта http://biese.wordpress.com/2014/02/28/the-easy-way-to-convert-local-time-to-utc.-time/.

package com.test.timezone;

import java.util.TimeZone;

public final class Utility {
    public static final TimeZone utcTZ = TimeZone.getTimeZone("UTC");

    public static long toLocalTime(long time, TimeZone to) {
        return convertTime(time, utcTZ, to);
    }

    public static long toUTC(long time, TimeZone from) {
        return convertTime(time, from, utcTZ);
    }

    public static long convertTime(long time, TimeZone from, TimeZone to) {
        return time + getTimeZoneOffset(time, from, to);
    }

    private static long getTimeZoneOffset(long time, TimeZone from, TimeZone to) {
        int fromOffset = from.getOffset(time);
        int toOffset = to.getOffset(time);
        int diff = 0;

        if (fromOffset >= 0){
            if (toOffset > 0){
                toOffset = -1*toOffset;
            } else {
                toOffset = Math.abs(toOffset);
            }
            diff = (fromOffset+toOffset)*-1;
        } else {
            if (toOffset <= 0){
                toOffset = -1*Math.abs(toOffset);
            }
            diff = (Math.abs(fromOffset)+toOffset);
        }
        return diff;
    }
}

package com.test.timezone;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TestTimezone {

    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd HH:mm:ss zzzz");
        Calendar date1 = new GregorianCalendar(2014,0,15,10,0,0);
        System.out.println(sdf.format(date1.getTime())+"\n");
        long utcTimeStamp = Utility.toUTC(date1.getTimeInMillis(), date1.getTimeZone());
        Calendar utcCal = Calendar.getInstance();
        utcCal.setTimeInMillis(utcTimeStamp);
        System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n");

        System.out.println("---------------------------------------");
        Calendar date2 = new GregorianCalendar(2014,2,15,10,0,0);
        System.out.println(sdf.format(date2.getTime())+"\n");
        utcTimeStamp = Utility.toUTC(date2.getTimeInMillis(), date2.getTimeZone());
        utcCal.setTimeInMillis(utcTimeStamp);
        System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n");

        System.out.println("---------------------------------------");
        Calendar date3 = new GregorianCalendar(2014,11,25,9,0,0);
        System.out.println(sdf.format(date3.getTime())+"\n");
        long uTime = Utility.toUTC(date3.getTimeInMillis(), date3.getTimeZone());
        System.out.println("utcTimeStamp: "+uTime+"\n");
        long lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST"));
        Calendar locCal = Calendar.getInstance();
        locCal.setTimeInMillis(lTime);
        System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n");

        System.out.println("---------------------------------------");
        Calendar date4 = new GregorianCalendar(2014,6,4,9,0,0);
        System.out.println(sdf.format(date4.getTime())+"\n");
        uTime = Utility.toUTC(date4.getTimeInMillis(), date4.getTimeZone());
        System.out.println("utcTimeStamp: "+uTime+"\n");
        lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST"));
        locCal = Calendar.getInstance();
        locCal.setTimeInMillis(lTime);
        System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n");
    }
}
person TALE    schedule 06.11.2014
comment
Это плохая практика, поскольку вы конвертируете базу времени (эпоху Unix), что приводит к хранению времени в локализованном виде. Дата действительно обрабатывает эти преобразования в представлениях фактов для вас. Если вы используете метод, который вы описываете, и используете время в качестве даты, как в = новая дата (время), объект Date предполагает, что время - GMT, а объект неправильно экземпляр. Единственным допустимым использованием этих функций является преобразование времени из и во внешние системы, которые не работают с метками времени по Гринвичу и, следовательно, не соответствуют соглашению о метках времени UNIX. - person Bas Goossen; 09.11.2016

Код в ответе СКАЗКИ можно упростить:

public final class Utility {
    public static long toLocalTime(long time, TimeZone to) {
        return time + to.getOffset(time);
    }

    public static long toUTC(long time, TimeZone from) {
        return time - from.getOffset(time);
    }
}
person csname1910    schedule 06.05.2016