web-dev-qa-db-fra.com

Comment définir le fuseau horaire d'un fichier Java.util.Date?

J'ai analysé un Java.util.Date à partir d'une String, mais le fuseau horaire local est défini comme fuseau horaire de l'objet date.

Le fuseau horaire n'est pas spécifié dans la String à partir de laquelle Date est analysé. Je souhaite définir un fuseau horaire spécifique de l'objet date.

Comment puis je faire ça?

173
Yatendra Goel

Utilisez DateFormat. Par exemple,

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
267
ZZ Coder

Sachez que les objets Java.util.Date ne contiennent aucune information de fuseau horaire. Vous ne pouvez pas définir le fuseau horaire d'un objet Date. La seule chose qu'un objet Date contient est un nombre de millisecondes depuis le "Epoch" - 1er janvier 1970, 00:00:00 UTC.

Comme l'indique ZZ Coder, vous définissez le fuseau horaire sur l'objet DateFormat pour lui indiquer le fuseau horaire dans lequel vous souhaitez afficher la date et l'heure.

150
Jesper

tl; dr

… Analysé… à partir d'un String… le fuseau horaire n'est pas spécifié… Je souhaite définir un fuseau horaire spécifique

_LocalDateTime.parse( "2018-01-23T01:23:45.123456789" )  // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
    .atZone( ZoneId.of( "Africa/Tunis" ) )              // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.
_

Pas de fuseau horaire dans j.u.Date

Comme indiqué dans les autres réponses correctes, un fichier Java.util.Date n’a pas de fuseau horaire.. Il représente UTC / GMT (pas de décalage de fuseau horaire). Très déroutant car sa méthode toString applique le fuseau horaire par défaut de la JVM lors de la génération d'une représentation String.

Évitez j.u.Date

Pour cette raison et bien d’autres encore, évitez d’utiliser les fonctions intégrées Java.util.Date & .Calendar & Java.text.SimpleDateFormat. Ils sont notoirement gênants.

Utilisez plutôt le package Java.time fourni avec Java 8 .

Java.time

Les classes Java.time peuvent représenter un moment sur la timeline de trois manières:

  • UTC (Instant)
  • Avec un décalage (OffsetDateTime avec ZoneOffset)
  • Avec un fuseau horaire (ZonedDateTime avec ZoneId)

Instant

Dans Java.time , le bloc de construction de base est Instant , un moment sur la ligne de temps au format UTC. Utilisez des objets Instant pour une grande partie de votre logique métier.

_Instant instant = Instant.now();
_

OffsetDateTime

Appliquez un offset-de-UTC pour l’ajuster à l’heure horloge murale de certaines localités .

Appliquez un ZoneOffset pour obtenir un OffsetDateTime .

_ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );
_

ZonedDateTime

Mieux vaut appliquer un fuseau horaire , un décalage plus les règles de traitement des anomalies telles que heure avancée/(/) .

Appliquez un ZoneId à un Instant pour obtenir un ZonedDateTime . Indiquez toujours un nom de fuseau horaire approprié . N'utilisez jamais 3-4 abréviations telles que EST ou IST qui ne sont ni uniques ni normalisées.

_ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
_

LocalDateTime

Si la chaîne d'entrée ne contient aucun indicateur de décalage ou de zone, analysez-la en tant que LocalDateTime .

Si vous êtes certain du fuseau horaire prévu, affectez un ZoneId pour produire un ZonedDateTime. Voir l'exemple de code ci-dessus dans tl; dr section en haut.

Chaînes formatées

Appelez la méthode toString sur l’une de ces trois classes pour générer une chaîne représentant la valeur date-heure au format standard ISO 8601 . La classe ZonedDateTime étend le format standard en ajoutant le nom du fuseau horaire entre parenthèses.

_String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]
_

Pour les autres formats, utilisez DateTimeFormatter class. Il est généralement préférable de laisser cette classe générer des formats localisés en utilisant le langage humain et les normes culturelles attendus de l'utilisateur. Ou vous pouvez spécifier un format particulier.


À propos de Java.time

Le cadre Java.time est intégré à partir de Java 8. Ces classes supplantent les anciennes legacy / classes/date/heure problématiques telles que Java.util.Date , Calendar , & SimpleDateFormat .

Le Joda-Time projet, maintenant en mode maintenance , conseille la migration vers le Java.time Des classes.

Pour en savoir plus, voir le Oracle Tutorial . 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 conforme à JDBC 4.2 ou ultérieur. Pas besoin de chaînes, pas besoin de _Java.sql.*_ classes.

Où obtenir les classes Java.time?

Le ThreeTen-Extra project é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 more .


Joda-Time

Tandis que Joda-Time est toujours activement maintenu, ses concepteurs nous ont conseillé de migrer vers Java.time dès que possible. Je laisse cette section intacte à titre de référence, mais je suggère d'utiliser plutôt la section _Java.time_ ci-dessus.

Dans Joda-Time , un objet date-heure ( DateTime ) connaît réellement son fuseau horaire. Cela signifie un décalage par rapport à UTC et par les règles et l’historique de l’heure d’été de ce fuseau horaire, ainsi que par d’autres anomalies de ce type.

_String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );
_

Appelez la méthode toString pour générer une chaîne au format ISO 8601 .

_String output = dateTimeIndia.toString();
_

Joda-Time offre également de nombreuses fonctionnalités pour générer toutes sortes d'autres formats String.

Si nécessaire, vous pouvez convertir de Joda-Time DateTime en Java.util.Date.

_Java.util.Date date = dateTimeIndia.toDate();
_

Recherchez dans StackOverflow "date de joda" pour trouver de nombreux autres exemples, dont certains très détaillés.


En fait, il y a est un fuseau horaire intégré à un fichier Java.util.Date, utilisé pour certaines fonctions internes (voir les commentaires sur cette réponse). Mais ce fuseau horaire interne n'est pas exposé en tant que propriété et ne peut pas être défini. Ce fuseau horaire interne est not celui utilisé par la méthode toString pour générer une représentation sous forme de chaîne de la valeur date-heure; le fuseau horaire actuel par défaut de la machine virtuelle Java est appliqué à la volée. Donc, en abrégé, nous disons souvent “j.u.Date n'a pas de fuseau horaire”. Déroutant? Oui. Encore une autre raison d'éviter ces vieilles classes fatiguées.

73
Basil Bourque

Vous pouvez également définir le fuseau horaire au niveau de la machine virtuelle Java

Date date1 = new Date();
System.out.println(date1);

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"

Date date2 = new Date();
System.out.println(date2);

sortie:

Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013
62
starmer

Si vous devez travailler uniquement avec les classes JDK standard, vous pouvez utiliser ceci:

/**
 * Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
 * <code>toTimeZone</code>.  Since Java.util.Date has does not really store time zome
 * information, this actually converts the date to the date that it would be in the
 * other time zone.
 * @param date
 * @param fromTimeZone
 * @param toTimeZone
 * @return
 */
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
    long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
    long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);

    return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}

/**
 * Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <code>date</code>.
 * @param date
 * @param timeZone
 * @return
 */
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
    long timeZoneDSTOffset = 0;
    if(timeZone.inDaylightTime(date))
    {
        timeZoneDSTOffset = timeZone.getDSTSavings();
    }

    return timeZone.getRawOffset() + timeZoneDSTOffset;
}

Le crédit va à ce post .

6
diadyne

Java.util.Calendar est le moyen habituel de gérer les fuseaux horaires en utilisant uniquement les classes JDK. Apache Commons a d’autres alternatives/utilitaires qui pourraient être utiles. Edit La note de Spong m'a rappelé que j'avais entendu de très bonnes choses à propos de Joda-Time (même si je ne l'ai pas utilisé moi-même).

6
T.J. Crowder

Ce code a été utile dans une application sur laquelle je travaille:

    Instant date = null;
    Date sdf = null;
    String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
    try {
        SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
        isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
        sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
        date = sdf.toInstant();

    } catch (Exception e) {
        System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
    }

    LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
    LOGGER.info("sdf: " + sdf);
    LOGGER.info("parsed to: " + date);
0
VikR

Convertissez la date en chaîne et faites-le avec SimpleDateFormat.

    SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
    String dateStr = readFormat.format(date);
    SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Date date = writeFormat.parse(dateStr);
0
avisper

Si quelqu'un a besoin de cela, si vous devez convertir un fuseau horaire XMLGregorianCalendar en votre fuseau horaire actuel de l'heure UTC, il vous suffit de définir le fuseau horaire sur 0, puis d'appeler toGregorianCalendar(). le Date sait comment le convertir en vôtre, de sorte que vous puissiez obtenir les données à partir de là. 

XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(
        ((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());

Résultat:

2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00
0
EpicPandaForce