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

Я использую библиотеки Joda time (1,6), и он продолжает возвращать объекты DateTime с неправильным часовым поясом, вместо этого используется British Summer Time от 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", как ожидалось.

Ответы

Ответ 1

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

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

В 1968 году часы были увеличены на один час до 18 февраля и 18 февраля так и осталось до Британского стандарта Время, в течение которого часы были сохранены в продвижение GMT ​​в течение всего года, вошло в силы между 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()

который делает это для меня.

Ответ 2

Вам может быть интересно увидеть статический инициализатор для класса 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, были бы подобраны к настоящему времени.