Преобразование местного времени в UTC или наоборот с учетом летнего времени - PullRequest
9 голосов
/ 14 мая 2011

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

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

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

Ответы [ 3 ]

15 голосов
/ 14 мая 2011

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

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

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

    // 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 заботится об обработке DST.Конечно, вы можете справиться с этим вручную, просто прочитав JavaDoc .

, связанный с TimeZone.
8 голосов
/ 06 ноября 2014

Вот лучшее решение, которое я нашел.Я копирую это здесь, но решение пришло от 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");
    }
}
4 голосов
/ 06 мая 2016

Код в ответе TALE можно упростить:

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);
    }
}
...