web-dev-qa-db-fra.com

Comment gérer jodatime Instantané illégal en raison de la transition de décalage de fuseau horaire

Je souhaite configurer joda DateTime à aujourd'hui à 2 heures du matin (voir l'exemple de code ci-dessous). Mais je reçois cette exception:

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)

Quelle est la bonne façon de créer l’exception ci-dessus ou de créer un DateTime à une heure donnée?

Exemple de code:

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

Merci.

42
michal.kreuzman

On dirait que vous essayez de passer d'une heure locale spécifique à une instance DateTime et que vous voulez que cela soit robuste face à l'heure d'été. Essayez ceci ... (notez que je suis aux États-Unis/dans l’Est, notre date de transition était donc le 13 mars; je devais trouver la bonne date pour obtenir l’exception que vous avez eue aujourd’hui. J'ai mis à jour le code ci-dessous pour CET, qui passe aujourd'hui. ) L’idée ici est que Joda fournit LocalDateTime pour vous permettre de raisonner sur un réglage d’horloge murale locale et de déterminer s’il est légal ou non dans votre fuseau horaire. Dans ce cas, j'ajoute simplement une heure si l'heure n'existe pas (votre application doit décider si c'est la bonne politique.)

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

}

Ce code produit:

 Bien sûr, instant invalide en raison de la transition de décalage de fuseau horaire! 
 Pas de problème: 2011-03-27T03: 00: 00.000 + 02: 00 
35
andersoj

CET passe à l'heure d'été le dernier dimanche de mars, qui se trouve être aujourd'hui. Le temps est passé de 1:59:59 à 3:00:00 - il n’ya pas 2, d’où l’exception.

Vous devez utiliser le temps UTC au lieu de l'heure locale pour éviter ce type de problème de fuseau horaire.

MutableDateTime now = new MutableDateTime(DateTimeZone.UTC);
12
josh3736

Je pense que très souvent, vous voudrez que Joda répare cela automatiquement pour vous. Vous ne saurez souvent pas comment corriger une date de décalage, car l'ampleur de ce dernier dépend de la zone et de l'année (bien que ce soit généralement une heure).

Un exemple de ceci est si vous analysez un horodatage qui provient d'une source que vous ne contrôlez pas; par exemple, le réseau. Si l'expéditeur de l'horodatage a des fichiers de zone obsolètes, cela peut se produire. (Si vous avez des fichiers de zone obsolètes, vous êtes plutôt mal foutus).

Voici un moyen de le faire, ce qui, certes, est un peu plus compliqué. Je l'ai fait fonctionner dans joda 1.6 ainsi que dans 2.x, car nous sommes bloqués sur 1.6 dans notre environnement.

Si vous construisez une date à partir d'autres entrées comme dans votre question, vous pouvez commencer par une date UTC ou une LocalDate comme suggéré ci-dessus, puis l'adapter pour corriger automatiquement votre décalage. La sauce spéciale est dans DateTimeZone.convertLocalToUTC

Dangereux:

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

Sûr:

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

J'ai testé cela dans les hémisphères est et ouest, ainsi que dans la zone de l'île Lord Howe, où il se trouve qu'il reste une demi-heure.

Ce serait un peu gentil si les formateurs joda supportaient un setStrict (booléen) qui les ferait prendre en charge pour vous ...

7
Jeremy Huiskamp

Si vous devez analyser la date de la chaîne:

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();

Travaillé pour moi parfaitement. Peut-être que quelqu'un en aura besoin.

4
Crushnik

Mettez à jour jodatime 2.1 et utilisez LocalDate.parse():

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