Joda Time указывает неправильный часовой пояс

Я использую библиотеки Joda time (1.6), и он продолжает возвращать объекты DateTime с неправильный часовой пояс, британское летнее время вместо GMT.

Моя рабочая станция Windows (под управлением JDK 1.6.0_16) думает, что находится в GMT, и если я получаю часовой пояс по умолчанию из классов даты / времени JDK, он правильный (GMT). Такое же поведение наблюдается и на наших серверах Linux. Я подумал, что это может быть ошибка в файлах базы данных часовых поясов в Joda, поэтому я перестроил банку с последней базой данных, но без изменений.

import java.util.TimeZone;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

public class TimeZoneTest {

    public static void main(String[] args) {                
        DateTimeFormatter timeParser = ISODateTimeFormat.timeParser();
        TimeZone timeZone = TimeZone.getDefault();
        System.out.println(timeZone.getID()); // "Europe/London"
        System.out.println(timeZone.getDisplayName()); // "Greenwich Mean Time"

        DateTimeZone defaultTimeZone = DateTimeZone.getDefault();
        System.out.println(defaultTimeZone.getID()); //"Europe/London"
        System.out.println(defaultTimeZone.getName(0L)); //"British Summer Time"

        DateTime currentTime = new DateTime();
        DateTimeZone currentZone = currentTime.getZone();
        System.out.println(currentZone.getID()); //"Europe/London"
        System.out.println(currentZone.getName(0L)); //"British Summer Time"            
    }
}

Выполняя отладку с помощью статического инициализатора в org.joda.time.DateTimeZone, я вижу, что вызов System.getProperty("user.timezone") дает "Europe/London", как и ожидалось.


person matthewKizoom    schedule 11.11.2009    source источник
comment
расширенный ответ для объяснения реальной проблемы   -  person jitter    schedule 11.11.2009


Ответы (2)


Хорошо, чтобы добраться до сути этого, вы должны ознакомиться с тем, что на самом деле означает британское летнее время, и когда оно было на месте. Чтобы сделать его короче, вы передаете 0L в getName(), который равен 1970-01-01T00:00:00Z, поэтому DefaultTimeZone ищет имя часового пояса в данный момент. Это было британское летнее время.

От: http://www.nmm.ac.uk/explore/astronomy-and-time/time-facts/british-summer-time.

В 1968 году часы были переведены на один час вперед по Гринвичу 18 февраля и оставались таковыми до тех пор, пока британское стандартное время, в течение которого часы переводились вперед по Гринвичу весь год, не вступило в силу с 27 октября 1968 года по 31 октября 1971 года.

Если бы вместо этого вы пропустили нужное количество миллисекунд с 1970-01-01T00:00:00Z. например при выполнении

defaultTimeZone.getName(new GregorianCalendar().getTimeInMillis())

Вы также получите правильную строку. По сути, вы просто передали методу getName() неправильный параметр, что привело к неожиданному результату.

Если вы хотите проверить подробно, проверьте файлы в org/joda/time/tz/src исходного кода joda, чтобы узнать, как joda определяет часовые пояса.


Вместо

defaultTimeZone.getName(0L)

вы могли бы использовать

defaultTimeZone.toTimeZone().getDisplayName()

что делает это для меня.

person jitter    schedule 11.11.2009
comment
Потрясающий. Кто бы мог подумать. Я буквально сказал, что 1 января 1970 года никак не могло быть в британское летнее время. Больше обманывай меня. Это также объясняет основную проблему, которая приводит к вопросу, который анализировал 10: 00: 00.0000000 + 00: 00 с помощью ISODateTimeFormat.timeParser (), приводя к DateTime в GMT + 1. Это связано с тем, что у Joda нет независимого понятия времени и даты, поэтому это время сравнивается с 1 января 1970 года, которое, как вы указали, было GMT + 1! Сумасшедший. Спасибо. - person matthewKizoom; 11.11.2009

Возможно, вас заинтересует статический инициализатор для класса DateTimeZone в версии 1.6:

static {
    setProvider0(null);
    setNameProvider0(null);

    try {
        try {
            cDefault = forID(System.getProperty("user.timezone"));
        } catch (RuntimeException ex) {
            // ignored
        }
        if (cDefault == null) {
            cDefault = forTimeZone(TimeZone.getDefault());
        }
    } catch (IllegalArgumentException ex) {
        // ignored
    }

    if (cDefault == null) {
        cDefault = UTC;
    }
}

Я предполагаю, что у вас определено свойство user.timezone (и установлено значение BST). В противном случае похоже, что Joda должен создать свой собственный экземпляр часового пояса на основе часового пояса JDK; и я ожидаю, что любые ошибки в этой области, особенно преобразование зоны GMT, уже были бы обнаружены.

person Andrzej Doyle    schedule 11.11.2009
comment
user.timezone дает Europe / London (я добавил это к вопросу). - person matthewKizoom; 11.11.2009