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

je veux mettre en place joda DateTime aujourd'hui à 2 H (voir code échantillon ci-dessous). Mais j'obtiens 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 un DateTime à une heure donnée de la journé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.

41
demandé sur Kirby 2011-03-27 22:01:00

5 réponses

il semble que vous essayez de passer d'une heure locale spécifique à un DateTime exemple et vous voulez que ce soit robuste contre l'heure d'été. Essayez ceci... (notez que je suis aux États-Unis / de L'est, donc notre date de transition était le 13 mars 11; je devais trouver la bonne date pour obtenir l'exception que vous avez obtenu aujourd'hui. Mis à jour mon code ci-dessous pour CET, qui transitions 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 si c'est légal dans votre fuseau horaire ou pas. Dans ce cas, je viens de rajouter une heure si le temps n'existe pas (votre demande de 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:

Sure enough, invalid instant due to time zone offset transition!
No problem: 2011-03-27T03:00:00.000+02:00
33
répondu andersoj 2011-03-27 18:42:52

CET passe à DST (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'y a pas 2, donc l'exception.

Vous devriez utiliser UTC au lieu de l'heure locale pour éviter ce genre de problème de fuseau horaire.

MutableDateTime now = new MutableDateTime(DateTimeZone.UTC);
12
répondu josh3736 2011-03-27 18:11:26

je pense que beaucoup de temps, vous voulez joda réparer automatiquement pour vous. Vous ne saurez souvent pas la bonne façon de fixer une date d'intervalle parce que la taille de l'intervalle dépend de la zone et de l'année (bien sûr, il est généralement d'une heure).

un exemple de ceci est si vous analysez un timestamp qui vient 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 périmés, cela pourrait se produire. (Si vous avez des fichiers de zone périmés, vous êtes assez bien foutue).

Voici une façon de faire, qui, est, est un peu plus compliqué. J'ai fait en sorte que ça marche dans joda 1.6 aussi bien que 2.x, puisque nous arrive d'être coincé sur 1.6 dans notre environnement.

si vous construisez une date à partir d'autres entrées comme dans votre question, vous pouvez commencer avec une date UTC ou un LocalDate comme suggéré ci-dessus, puis adaptez ceci pour corriger automatiquement votre offset. La sauce spéciale est en DateTimeZone.convertLocalToUTC

Dangereux:

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

Sécurité:

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é ceci dans les hémisphères Est et ouest ainsi que dans la zone de L'Île de Lord Howe, qui se trouve avoir une heure et demie de dst.

ce serait plutôt sympa si joda formatters soutenait un setStrict(booléen) qui leur ferait prendre soin de cela pour vous...

7
répondu Jeremy Huiskamp 2013-07-12 04:13:54

Si vous avez besoin d'analyser la date de chaîne de caractères:

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

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

4
répondu Crushnik 2017-05-23 04:04:30

mise à Jour de jodatime 2.1 et utiliser LocalDate.parse():

DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy");
LocalDate.parse(date, formatter);
0
répondu Jorge Washington 2017-10-13 23:42:21