Ich habe einen Java.util.Date
von einer String
analysiert, aber es wird die lokale Zeitzone als Zeitzone des date
-Objekts festgelegt.
Die Zeitzone ist nicht in der String
angegeben, aus der Date
analysiert wird. Ich möchte eine bestimmte Zeitzone des date
-Objekts festlegen.
Wie kann ich das machen?
Verwenden Sie DateFormat. Zum Beispiel,
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");
Beachten Sie, dass Java.util.Date
-Objekte selbst keine Zeitzoneninformationen enthalten. Sie können die Zeitzone für ein Date
-Objekt nicht festlegen. Das einzige, was ein Date
-Objekt enthält, ist eine Anzahl von Millisekunden seit der "Epoche" - 1. Januar 1970, 00:00:00 UTC.
Wie ZZ Coder zeigt, legen Sie die Zeitzone für das Objekt DateFormat
fest, um anzugeben, in welcher Zeitzone Sie Datum und Uhrzeit anzeigen möchten.
… Geparst… aus einem String… Zeitzone ist nicht angegeben… Ich möchte eine bestimmte Zeitzone festlegen
_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.
_
Wie in den anderen korrekten Antworten angegeben, hat ein Java.util.Date keine Zeitzone†. Es repräsentiert UTC /GMT (kein Zeitzonenversatz). Sehr verwirrend, da die toString
-Methode beim Generieren einer Zeichenfolgendarstellung die Standardzeitzone der JVM anwendet.
Aus diesem und vielen anderen Gründen sollten Sie die Verwendung des integrierten Java.util.Date & .Calendar & Java.text.SimpleDateFormat vermeiden. Sie sind notorisch lästig.
Verwenden Sie stattdessen das Java.time-Paket , das mit Java 8 gebündelt ist.
Die Java.time-Klassen können einen Moment auf der Zeitachse auf drei Arten darstellen:
Instant
)OffsetDateTime
mit ZoneOffset
)ZonedDateTime
mit ZoneId
)Instant
In Java.time ist der grundlegende Baustein Instant
, ein Moment auf der Zeitachse in UTC. Verwenden Sie Instant
-Objekte für einen Großteil Ihrer Geschäftslogik.
_Instant instant = Instant.now();
_
OffsetDateTime
Wenden Sie Offset-von-UTC an, um die Wanduhrzeit einiger Orte anzupassen.
Wenden Sie ein ZoneOffset
an, um ein OffsetDateTime
zu erhalten.
_ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );
_
ZonedDateTime
Besser ist es, ein Zeitzone , einen Versatz plus die Regeln für die Behandlung von Anomalien wie Sommerzeit (DST) anzuwenden .
Wenden Sie ein ZoneId
auf ein Instant
an, um ein ZonedDateTime
zu erhalten. Geben Sie immer ein richtiger Zeitzonenname an. Verwenden Sie niemals 3-4 Abkürzungen wie EST
oder IST
, die weder eindeutig noch standardisiert sind.
_ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
_
LocalDateTime
Wenn in der Eingabezeichenfolge kein Versatz- oder Zonenindikator vorhanden war, analysieren Sie diese als LocalDateTime
.
Wenn Sie sich der beabsichtigten Zeitzone sicher sind, weisen Sie eine ZoneId
zu, um eine ZonedDateTime
zu erstellen. Siehe obiges Codebeispiel im Abschnitt tl; dr oben.
Rufen Sie die Methode toString
für eine dieser drei Klassen auf, um eine Zeichenfolge zu generieren, die den Datums-/Zeitwert im Standardformat ISO 8601 darstellt. Die Klasse ZonedDateTime
erweitert das Standardformat, indem der Name der Zeitzone in Klammern angehängt wird.
_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]
_
Für andere Formate verwenden Sie die Klasse DateTimeFormatter
. Generell ist es am besten, diese Klasse lokalisierte Formate unter Verwendung der vom Benutzer erwarteten menschlichen Sprache und kulturellen Normen generieren zu lassen. Oder Sie können ein bestimmtes Format angeben.
Das Java.time Framework ist in Java 8 und höher integriert. Diese Klassen ersetzen die lästigen alten Legacy Datum-Zeit-Klassen wie Java.util.Date
, Calendar
, & SimpleDateFormat
=.
Das Joda-Time -Projekt, das sich jetzt im Wartungsmodus befindet, rät zur Migration auf Java.time = Klassen.
Weitere Informationen finden Sie im Oracle Tutorial . Suchen Sie in Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 31 .
Sie können Java.time Objekte direkt mit Ihrer Datenbank austauschen. Verwenden Sie einen JDBC-Treiber , der JDBC 4.2 oder höher entspricht. Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für _Java.sql.*
_ Klassen.
Woher bekomme ich die Java.time-Klassen?
Das Projekt ThreeTen-Extra erweitert Java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von Java.time. Hier finden Sie möglicherweise einige nützliche Klassen wie Interval
, YearWeek
, YearQuarter
und more .
Während Joda-Time noch aktiv gewartet wird, haben uns die Macher angewiesen, so schnell wie möglich auf Java.time zu migrieren. Ich lasse diesen Abschnitt als Referenz intakt, empfehle jedoch, stattdessen den obigen Abschnitt _Java.time
_ zu verwenden.
In Joda-Time kennt ein Datum-Uhrzeit-Objekt ( DateTime
) die zugewiesene Zeitzone wirklich. Dies bedeutet einen Versatz von UTC und der Regeln und des Verlaufs der Sommerzeit (DST) dieser Zeitzone und anderer solcher Anomalien.
_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 );
_
Rufen Sie die Methode toString
auf, um einen String im Format ISO 8601 zu generieren.
_String output = dateTimeIndia.toString();
_
Joda-Time bietet auch umfangreiche Funktionen zum Generieren aller Arten anderer Zeichenfolgenformate.
Bei Bedarf können Sie Joda-Time DateTime in ein Java.util.Date konvertieren.
_Java.util.Date date = dateTimeIndia.toDate();
_
Durchsuchen Sie StackOverflow nach "joda date", um viele weitere, zum Teil recht detaillierte Beispiele zu finden.
†Tatsächlich gibt es eine in Java.util.Date eingebettete Zeitzone , die für einige interne Funktionen verwendet wird (siehe Kommentare zu dieser Antwort). Diese interne Zeitzone ist jedoch nicht als Eigenschaft verfügbar und kann nicht festgelegt werden. Diese interne Zeitzone ist nicht diejenige, die von der Methode toString
zum Generieren einer Zeichenfolgendarstellung des Datum-Zeit-Werts verwendet wird. Stattdessen wird die aktuelle Standardzeitzone der JVM sofort angewendet. Als Abkürzung sagen wir oft "j.u.Date hat keine Zeitzone". Verwirrend? Ja. Ein weiterer Grund, diese müden alten Klassen zu meiden.
Sie können die Zeitzone auch auf der JVM-Ebene einstellen
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);
ausgabe:
Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013
Wenn Sie nur mit Standard-JDK-Klassen arbeiten müssen, können Sie Folgendes verwenden:
/**
* 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;
}
Gutschrift geht an diese post .
Java.util.Calendar
ist der übliche Weg, Zeitzonen nur mit JDK-Klassen zu behandeln. Apache Commons hat einige weitere Alternativen/Hilfsprogramme, die hilfreich sein können. Edit Spongs Notiz erinnerte mich daran, dass ich wirklich gute Dinge über Joda-Time gehört habe (obwohl ich es selbst nicht verwendet habe).
Dieser Code war hilfreich in einer App, an der ich gerade arbeite:
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);
Konvertieren Sie das Datum in einen String und tun Sie es mit 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);
Wenn jemand dies jemals benötigt, wenn Sie eine XMLGregorianCalendar
Zeitzone von UTC in Ihre aktuelle Zeitzone konvertieren müssen, müssen Sie die Zeitzone auf 0
setzen. Dann rufen Sie toGregorianCalendar()
auf - sie bleibt jedoch dieselbe Zeitzone Die Date
weiß, wie sie in Ihre konvertiert wird, damit Sie die Daten von dort aus abrufen können.
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());
Ergebnis:
2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00