web-dev-qa-db-fra.com

Joda Time analyse une date avec un fuseau horaire et conserve ce dernier

Je souhaite analyser une date créée avec un fuseau horaire spécifique, la convertir en un format et la renvoyer. La conversion fonctionne mais le décalage de fuseau horaire est toujours défini sur +0000, la différence de temps étant ajoutée/soustraite selon les besoins. Comment puis-je le mettre en forme et garder le décalage correct?

J'attends ceci: 2012-11-30T12: 08: 56.23 + 07: 00

Mais obtenez ceci: 2012-11-30T05: 08: 56.23 + 00: 00

La mise en oeuvre:

public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSZZ";

public static String formatDateToISO8601Standard(Date date) {
    DateTime dateTime = new DateTime(date);
    DateTimeFormatter df = DateTimeFormat.forPattern(ISO_8601_DATE_FORMAT);
    return dateTime.toString(df);
}

Classe de test:

private static final String DATE_WITH_TIMEZONE = "30 11 2012 12:08:56.235 +0700";
private static final String EXPECTED_DATE_WITH_TIMEZONE = "2012-11-30T12:08:56.23+07:00";

@Test public void testFormattingDateWithSpecificTimezone() throws Exception {
    String result = JodaDateUtil.formatDateToISO8601Standard(createDate(DATE_WITH_TIMEZONE));
    assertEquals("The date was not converted correctly", EXPECTED_DATE_WITH_TIMEZONE, result); }

private Date createDate(String dateToParse) throws ParseException {
    DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
    DateTime temp = df.parseDateTime(dateToParse);
    Date date = temp.toDate();
    return date; }
27
edwardmlyte

Fondamentalement, une fois que vous avez analysé la chaîne de date [dans votre méthode createDate ()], vous avez perdu la zone d'origine. Joda-Time vous permettra de formater la date en utilisant n'importe quelle zone, mais vous devrez conserver la zone d'origine. 

Dans votre méthode createDate (), DateTimeFormatter "df" peut renvoyer la zone qui figurait dans la chaîne. Vous devrez utiliser la méthode withOffsetParsed () . Ensuite, lorsque vous avez votre DateTime , appelez getZone () . Si vous enregistrez cette zone quelque part ou si vous la passez d'une manière ou d'une autre à votre routine de formatage, vous pouvez l'utiliser ici en créant un DateTimeFormatter "withZone" et en spécifiant cette zone comme celle de votre choix pour le format.

En guise de démonstration, voici un exemple de code dans une seule méthode. J'espère que cela vous aidera à modifier votre code comme vous le souhaitez.

  public static void testDate() 
  {
    DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
    DateTime temp = df.withOffsetParsed().parseDateTime("30 11 2012 12:08:56.235 +0700");
    DateTimeZone theZone = temp.getZone();

    Date date = temp.toDate();

    DateTime dateTime = new DateTime(date);
    DateTimeFormatter df2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSZZ");
    DateTimeFormatter df3 = df2.withZone(theZone);

    System.out.println(dateTime.toString(df2));
    System.out.println(dateTime.toString(df3));

  }
37
Darius X.

tl; dr

OffsetDateTime.parse ( 
    "30 11 2012 12:08:56.235 +0700" , 
    DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US )
).toString() 

2012-11-30T12: 08: 56.235 + 07: 00

Détails

La réponse acceptée est correcte. Dès que vous convertissez en un objet Java.util.Date, vous perdez les informations de fuseau horaire. Ceci est compliqué par le fait que Java.util.Date::toString applique de manière confuse un fuseau horaire par défaut actuel lors de la génération de la chaîne. 

Évitez d’utiliser ces anciennes classes date-heure comme Java.util.Date. Ils sont mal conçus, déroutants et gênants. Maintenant hérité, supplanté par le projet Java.time. Le projet Joda-Time est également remplacé par les classes Java.time.

Java.time

Analyser cette chaîne d'entrée en tant qu'objet OffsetDateTime car elle inclut un décalage par rapport à UTC mais ne dispose pas d'un fuseau horaire. Appelez DateTimeFormatter.ofPattern pour spécifier un format personnalisé correspondant à votre chaîne d'entrée. Transmettez cet objet de formatage à OffsetDateTime.parse .

String input = "30 11 2012 12:08:56.235 +0700" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US );
OffsetDateTime odt = OffsetDateTime.parse ( input , f );

odt: toString (): 2012-11-30T12: 08: 56.235 + 07: 00

Pour voir le même moment en UTC, extrayez une Instant. La classe Instant représente un moment sur la ligne temporelle en UTC avec une résolution de nanosecondes (jusqu'à neuf (9) chiffres d'une fraction décimale). 

Instant instant = odt.toInstant();

instant.toString (): 2012-11-30T05: 08: 56.235Z

Vous pouvez appliquer n’importe quel fuseau horaire pour lequel vous souhaitez afficher le même moment, le même point sur la timeline.

ZonedDateTime zdtKolkata = odt.toInstant ().atZone ( ZoneId.of ( "Asia/Kolkata" ) );

zdtKolkata.toString (): 2012-11-30T10: 38: 56.235 + 05: 30 [Asie/Kolkata]

Pas besoin de mélanger les anciennes classes date-heure. S'en tenir à Java.time. Si vous devez utiliser un ancien code non encore mis à jour en types Java.time, recherchez les nouvelles méthodes ajoutées aux anciennes classes à convertir en/à partir de Java.time.

L'équivalent de Java.util.Date est Instant, les deux étant un décompte depuis l'époque de 1970-01-01T00:00:00Z au format UTC. Mais méfiez-vous de la perte de données car les classes Java.time prennent en charge la résolution en nanosecondes, mais les anciennes classes sont limitées à des millisecondes.

Java.util.Date utilDate = Java.util.Date.from( instant );

Code live

Voir code de travail en direct sur IdeOne.com .


À propos de Java.time

Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciennes classes gênantes anciennes date-heure telles que Java.util.Date , .Calendar _, & Java.text.SimpleDateFormat .

Le projet Joda-Time , désormais en mode mode de maintenance , conseille la migration vers Java.time.

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .

Où obtenir les classes Java.time? 

  • Java SE 8 et SE 9 et versions ultérieures
    • Intégré. 
    • Une partie de l'API Java standard avec une implémentation fournie.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 et SE 7
    • Une grande partie de la fonctionnalité Java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport .
  • Android

Le projet ThreeTen-Extra étend Java.time avec des classes supplémentaires. Ce projet est un terrain d’essai pour d’éventuels ajouts à Java.time. Vous pouvez y trouver des classes utiles telles que Interval _, YearWeek , YearQuarter _ et plus _.

2
Basil Bourque

Essaye ça.

ISODateTimeFormat.dateTimeParser().parseDateTime(dateString), 

puis convertissez-le au format souhaité.

0
EricW

Utilisez le format val formateur = DateTimeFormat.forPattern ("aaaa-MM-jj HH: mm: ss.SSSZZ")

0
frostcs