Reputation: 8605
I have some DateTime including TimeZone Europe/Vienna (+0200). It is fetched by this method:
settlementService.getPendingPeriodStart()
and look with toString like this:
2012-06-01T00:00:00.000+02:00
Now I want to save this date 2012-06-01 as java.util.Date, so I tried something like this:
transactionDate = settlementService.getPendingPeriodStart().withTime(0, 0, 0, 0).toDate();
But the result is this:
Thu May 31 22:00:00 UTC 2012
What's the best way to save the DateTime result as Date including the TimeZone offset, so transactionDate should be 2012-06-01. I could tinker with GregorianCalendar, but that's not what I like. This ought to be easier, isn't it?
By the way (if this isn't clear). The local system runs on UTC. That's why the result is Thu May 31 22:00:00 UTC 2012.
Upvotes: 2
Views: 4742
Reputation: 79540
Unfortunately, the accepted answer is misguiding. As a matter of fact,
2012-06-01T00:00:00.000+02:00 = 2012-05-31T22:00:00Z
The Z
on the right-hand side is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC
timezone (which has the timezone offset of +00:00
hours).
Writing 2012-06-01T00:00:00.000+02:00
as 2012-06-01
, although a matter of just a function call, is dangerous for any business logic that depends on the timezone because it may have a different date in a timezone with a different offset value e.g. as shown above. 2012-06-01
is just a LocalDate
which should be used to track events like birth date, wedding date etc.
The legacy date-time API (java.util
date-time types and their formatting type, SimpleDateFormat
etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time
, the modern date-time API*.
Also, quoted below is a notice at the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
java.time
, the modern API:How to parse the given date-time string:
The given date-time string has a timezone offset and therefore it should be parsed to OffsetDateTime
. Since the modern date-time API is based on ISO 8601 and does not require using a DateTimeFormatter
object explicitly as long as the date-time string conforms to the ISO 8601 standards.
OffsetDateTime odt = OffsetDateTime.parse("2012-06-01T00:00:00.000+02:00"); // 2012-06-01T00:00+02:00
How to get the date-time out of it in UTC:
There are multiple ways. The simplest way is to convert it into an Instant
which represents an instantaneous point on the timeline which is in UTC.
Instant instant = odt.toInstant(); // 2012-05-31T22:00:00Z
Alternatively,
OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC); // 2012-05-31T22:00Z
How to get java.util.Date
out of it:
If at all, you need an instance of java.util.Date
from the instance of OffsetDateTime
, you can use Date#from(Instant instant)
.
Date date = Date.from(instant); // Thu May 31 23:00:00 BST 2012 <--In my timezone
Note that a 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 e.g.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date)); // 2012-05-31T22:00:00.000Z
How to get the date part out of it:
As I have already explained, it is dangerous for any business logic that depends on the timezone. However, it's just a matter of a simple function call.
LocalDate localDate = odt.toLocalDate(); // 2012-06-01
Learn more about java.time
, the modern date-time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Upvotes: 1
Reputation: 8605
I think I found a solution. (If you know a better solution, just let me know)
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
DateTime dateTimeWithTimeZone = new DateTime(DateTimeZone.forID("Europe/Vienna")).withDate(2012, 06, 01).withTime(0, 0, 0, 0);
Date dateWithTimeZoneIncluded = dateTimeWithTimeZone.toLocalDate().toDate();
System.out.println(dateFormat.format(dateWithTimeZoneIncluded));
The result is 2012-06-01 as expected.
Upvotes: 0
Reputation: 382404
A date and the time zone of the user are 2 different things. One is a date, the other is a preference, or a presentation parameter.
Don't try to store them in the same field.
Consider that it wouldn't be even possible to store them together efficiently (without losing precision) as a date can be stored in a long only because it's specified that it's an UTC date.
You can save the time zone as an offset (a frequent recommendation is to keep the minutes in this offset ([hh]:[mm]
) because of very small cases).
Upvotes: 0