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?
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");
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.
… 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.
_
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.
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 .
Les classes Java.time peuvent représenter un moment sur la timeline de trois manières:
Instant
)OffsetDateTime
avec ZoneOffset
)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.
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.
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 .
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.
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
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 .
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).
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);
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);
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