web-dev-qa-db-fra.com

Analyser la chaîne de date ISO8601 avec le fuseau horaire UTC

J'essaie de sérialiser/désérialiser une date de/vers une application javascript.

Côté serveur, j'utilise Java, JodaTime y est installé. J'ai découvert comment sérialiser au format ISO avec le fuseau horaire UTC, mais je ne sais pas comment effectuer l'opération inverse.

Voici mon code

public static String getIsoDate( Date date )
{
    SimpleDateFormat  dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT );
    TimeZone tz = TimeZone.getTimeZone("UTC");
    dateToIsoDateString.setTimeZone( tz );
    return dateToIsoDateString.format( date );
}

// this will return a date with GMT timezone
public static Date getDateFromIsoDateString( String iso8601date )
{
    DateTimeFormatter jodaParser = ISODateTimeFormat.dateTimeNoMillis();
    return jodaParser.parseDateTime( iso8601date ).toDate();
}

Cela ne me dérange pas d'utiliser ou non Joda, j'ai juste besoin d'une solution rapide et efficace,

Merci

9
Dimitri Kopriwa

Si vous utilisez Java 7 ou une version antérieure, vous pouvez vous référer à ceci post .

Si vous utilisez Java 8, vous pouvez faire:

    DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
    TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");

    Date date = Date.from(Instant.from(accessor));
    System.out.println(date);

Mettre à jour

Comme l'a souligné @BasilBourque dans le commentaire, TemporalAccessor est une interface de niveau cadre Java, il est déconseillé de l'utiliser dans le code de l'application et il est conseillé d'utiliser des classes concrètes plutôt que les interfaces.

Cette interface est une interface de niveau cadre qui ne devrait pas être largement utilisée dans le code d'application. Au lieu de cela, les applications doivent créer et transmettre des instances de types concrets, telles que LocalDate. Il y a plusieurs raisons à cela, notamment parce que les implémentations de cette interface peuvent être dans des systèmes de calendrier autres que ISO. Voir ChronoLocalDate pour une discussion plus complète des problèmes.

Il existe quelques classes concrètes utilisables, telles que LocalDate , LocalDateTime , OffsetDateTime , ZonedDateTime et etc ..

DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;

OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);

Date date = Date.from(Instant.from(offsetDateTime));
System.out.println(date);

tl; dr

OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )
.toInstant()
.toString()

2015-10-27T23: 22: 27.605Z

Détails

Votre question n'est pas claire et spécifique. Peut-être que ces petits exemples aideront. Mélanger les anciennes classes Java.util.Date et .Calendar avec Joda-Time peut vous dérouter. Joda-Time complètement remplace ces classes plutôt que des augmentations. 

Java.time

Les classes modernes Java.time supplantent à la fois les anciennes classes date-heure en Java ainsi que la bibliothèque Joda-Time qui les a inspirées.

OffsetDateTime

La classe OffsetDateTime représente un moment sur la ligne de temps avec un décalage particulier par rapport à UTC déterminant son heure de l'horloge murale. 

Les classes Java.time utilisent par défaut les formats standard ISO 8601 lors de l'analyse/de la génération de chaînes. Donc, pas besoin de spécifier un modèle de formatage.

OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;

Instant

Pour ajuster le décalage de sept heures entre l'heure UTC et l'heure UTC proprement dite, nous devons ajouter sept heures à l'heure du jour et reporter la date si nécessaire. La classe OffsetDateTime peut faire ce travail pour nous. Spécifiez le temps universel coordonné à l'aide de la constante ZoneOffset.UTC.

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;

odtUtc.toString (): 2015-10-27T23: 22: 27.605Z

Si vous utilisez beaucoup cette valeur UTC dans votre code et que vous devriez le faire en général, vous constaterez peut-être qu'il est plus simple d'utiliser des objets Instant. Une Instant est toujours en UTC par définition. Nous pouvons extraire une Instant de la OffsetDateTime.

Instant instant = odt.toInstant() ;

instant.toString (): 2015-10-27T23: 22: 27.605Z

Notez que les trois objets ci-dessus (odt, odtUtc, instant) représentent tous le même moment simultané, le même point sur la timeline. La seule différence est leur heure de l'horloge murale.

ZonedDateTime

En passant, si vous souhaitez que le même moment soit ajusté à l'heure utilisée par les habitants d'une région donnée, spécifiez un fuseau horaire via ZoneId pour obtenir un objet ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

zdt.toString (): 2015-10-27T19: 22: 27.605-04: 00 [Amérique/Montréal]

Utiliser des classes concrètes dans Java.time

La réponse de always_a_rookie_to_learn est similaire à l'approche ci-dessus mais utilise l'interface TemporalAccessor . En règle générale, l’utilisation d’interfaces et de super-classes supérieures est une bonne idée en Java. Mais pas ici. La documentation de Java.time explique que leur conception nous oblige à utiliser les classes inférieures les plus concrètes dans nos applications. Les abstractions sont à usage interne uniquement dans le cadre, en général.

Dans le cas spécifique de cette Question, la classe OffsetDateTime est appropriée plutôt que TemporalAccessor


À propos de Java.time

Le framework {JAVA.TIME} est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciennes classes legacy date-heure, telles que Java.util.Date , Calendar , & SimpleDateFormat .

Le projet Joda-Time _ , désormais en mode de maintenance , conseille la migration vers les classes 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 .

Vous pouvez échanger des objets Java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou ultérieur. Pas besoin de chaînes, pas besoin de Java.sql.* classes.

Où obtenir les classes Java.time? 

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 trouver ici quelques classes utiles telles que Interval , YearWeek , YearQuarter , et more .


Joda-Time

UPDATE: Le projet Joda-Time est en mode maintenance et conseille la migration vers les classes Java.time. Cette section est laissée intacte pour l'histoire.

La valeur par défaut de Joda-Time est ISO 8601 pour les chaînes, que ce soit pour l'analyse ou la génération. Joda-Time a des analyseurs syntaxiques par défaut intégrés pour ISO 8601, il vous suffit donc de transmettre votre chaîne conforme au constructeur ou à la méthode statique parse.

Java.util.Date date = new DateTime( "2010-01-01T12:00:00+01:00Z" ).toDate();

Dans la mesure du possible, évitez Java.util.Date et .Calendar et restez lié à Joda-Time et à ses classes telles que DateTime. Utilisez .Date uniquement si requis par d’autres classes.

DateTime dateTimeUtc = new DateTime( someJavaDotUtilDotDate, DateTimeZone.UTC ); // Joda-Time can convert from Java.util.Date type which has no time zone.
String output = dateTime.toString(); // Defaults to ISO 8601 format.
DateTime dateTimeUtc2 = new DateTime( output, DateTimeZone.UTC ); // Joda-Time can parse ISO 8601 strings.

Pour la présentation, ajustez au fuseau horaire attendu par l'utilisateur.

DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
5
Basil Bourque

Solution native en Java8

Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())

Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())
0
stonelazy