Reputation: 94
There is an XMLGregorianCalendar
object that contains the value "2021-01-18T18:43:26.884Z"
(This is its output in toString()
). When I try to serialize this date with Jackson, I get a date 3 hours later in the output:
XMLGregorianCalendar date = ...;
ObjectMapper mapper = new ObjectMapper();
String out = mapper.writeValueAsString(obj); // Output: 1610995406884 (Converted to Date: Mon Jan 18 21:43:26 MSK 2021)
How can I solve this problem?
Upvotes: 2
Views: 1956
Reputation: 10127
There is no problem at all.
The time "2021-01-18T18:43:26.884Z"
in your XMLGregorianCalendar
is 18:43 in the GMT timezone (Greenwich mean time, London) or UTC+0 (because of the trailing Z
).
In the other hand you have a Date
object with the string representation
"Mon Jan 18 21:43:26 MSK 2021"
,
which is 21:43 in the MSK timezone (Moscow Standard Time) or UTC+3.
The Date
class chose this timezone for formatting the output
simply because your computer is located near Moscow.
So both are actually the same point in time, just only stringified for two different timezones.
Upvotes: 3
Reputation: 78965
java.util.Date
represents the number of milliseconds since the epochThe java.util.Date
object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT
(or UTC). When you print an object of java.util.Date
, its toString
method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat
and obtain the formatted string from it.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(1610995406884L);
Date date = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date));
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(sdf.format(date));
}
}
Output:
2021-01-18T18:43:26.884
2021-01-18T21:43:26.884
Note that the date-time API of java.util
and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
Convert the legacy, java.util.Date
to the modern java.time.Instant
using java.util.Date#toInstant
:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(1610995406884L);
Date date = calendar.getTime();
Instant instant = date.toInstant();
System.out.println(instant);
// You can convert Instant to other types e.g.
ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/Moscow"));
// Print default format i.e. the value of zdt#toString
System.out.println(zdt);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss'['z']'");
String formatted = dtf.format(zdt);
System.out.println(formatted);
}
}
Output:
2021-01-18T18:43:26.884Z
2021-01-18T21:43:26.884+03:00[Europe/Moscow]
2021-01-18T21:43:26[MSK]
The Z
stands for Zulu
and represents UTC (or GMT).
Upvotes: 2