Как обрабатывать jodatime Незаконный момент из-за перехода со смещением часового пояса - программирование
Подтвердить что ты не робот

Как обрабатывать jodatime Незаконный момент из-за перехода со смещением часового пояса

Я хочу настроить joda DateTime на сегодня в 2 часа ночи (см. пример кода ниже). Но я получаю это исключение:

Exception in thread "main" org.joda.time.IllegalFieldValueException: Value 2 for hourOfDay is not supported: Illegal instant due to time zone offset transition: 2011-03-27T02:52:05.239 (Europe/Prague)
at org.joda.time.chrono.ZonedChronology$ZonedDateTimeField.set(ZonedChronology.java:469)
at org.joda.time.MutableDateTime.setHourOfDay(MutableDateTime.java:702)

Каков правильный путь к исключению дескриптора выше или для создания DateTime в определенный час дня?

Пример кода:

MutableDateTime now = new MutableDateTime();
now.setHourOfDay(2);
now.setMinuteOfHour(0);
now.setSecondOfMinute(0);
now.setMillisOfSecond(0);
DateTime myDate = now.toDateTime();

Спасибо.

4b9b3361

Ответ 1

Похоже, вы пытаетесь перейти с определенного локального времени к экземпляру DateTime, и вы хотите, чтобы это было устойчиво против летнего сбережения. Попробуйте это... (обратите внимание, что я нахожусь в США/Восточной, поэтому наша дата перехода была 13 марта 11, мне нужно было найти подходящую дату, чтобы получить исключение, которое вы получили сегодня. Обновленный мой код ниже для CET, который перешел сегодня. ) Проницательность здесь заключается в том, что Joda предоставляет LocalDateTime, чтобы вы могли рассуждать о настройке локальных настенных часов и о том, является ли это законным в вашем часовом поясе или нет, В этом случае я просто добавляю час, если время не существует (ваше приложение должно решить, является ли это правильной политикой.)

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;

class TestTz {

  public static void main(String[] args)
  {
     final DateTimeZone dtz = DateTimeZone.forID("CET");
     LocalDateTime ldt = new LocalDateTime(dtz)
       .withYear(2011)
       .withMonthOfYear(3)
       .withDayOfMonth(27)
       .withHourOfDay(2);

    // this is just here to illustrate I'm solving the problem; 
    // don't need in operational code
    try {
      DateTime myDateBorken = ldt.toDateTime(dtz);
    } catch (IllegalArgumentException iae) {
      System.out.println("Sure enough, invalid instant due to time zone offset transition!");
    }

    if (dtz.isLocalDateTimeGap(ldt)) {
      ldt = ldt.withHourOfDay(3);
    }

    DateTime myDate = ldt.toDateTime(dtz);
    System.out.println("No problem: "+myDate);
  }

}

Этот код создает:

Sure enough, invalid instant due to time zone offset transition!
No problem: 2011-03-27T03:00:00.000+02:00

Ответ 2

CET переключается на летнее время (DST) в последнее воскресенье марта, которое сегодня и сегодня. Время шло от 1:59:59 до 3:00:00 – там нет 2, поэтому исключение.

Вы должны использовать UTC вместо локального времени, чтобы избежать такой проблемы с часовым поясом.

MutableDateTime now = new MutableDateTime(DateTimeZone.UTC);

Ответ 3

Я думаю, что много времени, вы захотите, чтобы Джода исправила это автоматически для вас. Вы часто не знаете правильного способа исправить промежуток, потому что размер пробела зависит от зоны и года (хотя, конечно, обычно час).

Одним из примеров этого является анализ синтаксиса, который исходит от источника, которого вы не контролируете; например, сети. Если отправитель метки времени имеет устаревшие файлы зон, это может произойти. (Если у вас устаревшие файлы зон, вы сильно завинчены).

Здесь способ сделать это, который, предоставленный, немного сложнее. Я сделал это в joda 1.6, а также 2.x, так как мы оказались в 1.6 в нашей среде.

Если вы строите дату с некоторых других входов, как в своем вопросе, вы можете начать с даты UTC или LocalDate, как было предложено выше, а затем адаптировать ее для автоматического исправления смещения. Специальный соус находится в DateTimeZone.convertLocalToUTC

Dangerous:

public DateTime parse(String str) {
    formatter.parseDateTime(gapdate)
}

Safe:

public DateTime parse(String str) {
    // separate date from zone; you may need to adjust the pattern,
    // depending on what input formats you support
    String[] parts = str.split("(?=[-+])");
    String datepart = parts[0];
    DateTimeZone zone = (parts.length == 2) ?
        DateTimeZone.forID(parts[1]) : formatter.getZone();

    // parsing in utc is safe, there are no gaps
    // parsing a LocalDate would also be appropriate, 
    // but joda 1.6 doesn't support that
    DateTime utc = formatter.withZone(DateTimeZone.UTC).parseDateTime(datepart);

    // false means don't be strict, joda will nudge the result forward by the
    // size of the gap.  The method is somewhat confusingly named, we're
    // actually going from UTC to local
    long millis = zone.convertLocalToUTC(utc.getMillis(), false);

    return new DateTime(millis, zone);
}

Я тестировал это в восточном и западном полушариях, а также в зоне Лорд-Хау-Айленд, которая, как оказалось, полчаса.

Было бы неплохо, если бы joda formatters поддерживал setStrict (boolean), который заставил бы их позаботиться об этом для вас...

Ответ 4

Если вам нужно проанализировать дату из строки:

final DateTimeZone dtz = DateTimeZone.getDefault(); //DateTimeZone.forID("Europe/Warsaw")
LocalDateTime ldt = new LocalDateTime("1946-04-14", dtz);
if (dtz.isLocalDateTimeGap(ldt)){
    ldt = ldt.plusHours(1);
}
DateTime date = ldt.toDateTime();
Date date = date.toDate();

Работал для меня отлично. Может быть, кому-то это понадобится.

Ответ 5

Обновить до jodatime 2.1 и использовать LocalDate.parse():

DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy");
LocalDate.parse(date, formatter);