Question

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.

Was it helpful?

Solution 3

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.

OTHER TIPS

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.

java.time

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.

Solution using 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.

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top