Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SimpleDateFormat setTimeZone not working

I am using the below code to cast time as UTC which is working

import java.text.SimpleDateFormat;
import static java.util.Calendar.* 

def dt = "2018-03-19T06:00:00+01:00"
def format = "yyyy-MM-dd'T'HH:mm:ssX"

TimeZone tz  = TimeZone.getDefault(); //getting up local time zone
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 
SimpleDateFormat sdf = new SimpleDateFormat(format);      
Date d = sdf.parse(dt);
TimeZone.setDefault(tz);

println d //output: 2018-03-19T05:00:00Z

println d.toTimestamp(); //Output: 2018-03-19 06:00:00.0

But when I use TimeZone.setTimeZone(TimeZone.getTimeZone("UTC")); then it not working.

It is working only with TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Why so?

Update after comments: Outputs needs to be in CET but in UTC

def dt = "2018-03-19T06:00:00+01:00"
def format = "yyyy-MM-dd'T'HH:mm:ssX"
SimpleDateFormat sdf = new SimpleDateFormat(format);      
sdf.setTimeZone(TimeZone.getTimeZone("CET"))
Date d = sdf.parse(dt);

println d
println d.toTimestamp();

​ Output:

Mon Mar 19 05:00:00 UTC 2018
2018-03-19 05:00:00.0
like image 515
Hary Avatar asked Mar 23 '18 14:03

Hary


1 Answers

java.time

    String dt = "2018-03-19T06:00:00+01:00";
    OffsetDateTime dateTime = OffsetDateTime.parse(dt);
    System.out.println(dateTime);

This prints

2018-03-19T06:00+01:00

Contrary to the outdated Date class, an OffsetDateTime from java.time, the modern Java date and time API, does contain a UTC offset, as the name also says. I don’t have experience with Groovy, so sorry to have to trust you to translate from my Java code.

If you want to make sure you get a specific time zone regardless of which offset is in the string:

    ZoneId zone = ZoneId.of("Europe/Brussels");
    ZonedDateTime dateTime = OffsetDateTime.parse(dt).atZoneSameInstant(zone);

This time the result is:

2018-03-19T06:00+01:00[Europe/Brussels]

Don’t rely on three letter time zone abbreviations like CET. CET is a common name for the standard time half (the part without summer time/DST) of very many European time zones that generally share time, but have not always done so and tend to disagree on the time when it comes to historic dates. Other three letter abbreviations are ambiguous and thus lead to even more confusion. Always give time zone as region/city, as I did with Europe/Brussels. Of course, pick the city that matches your desired time zone.

If you think you need a java.sql.Timestamp — you may not need that. If using JDBC 4.2 or higher or a similarly modern JPA implementation, it is better to store either an Instant or a LocalDateTime to your database. The choice depends on your exact requirements and the exact datatype of your database column.

    Instant inst = dateTime.toInstant();
    System.out.println(inst);

Output

2018-03-19T05:00:00Z

Instants always print in UTC. If a sufficiently new JDBC driver is unavailable, you may convert to Timestamp in either of two ways:

    System.out.println(Timestamp.from(inst));
    System.out.println(Timestamp.valueOf(dateTime.toLocalDateTime()));

2018-03-19 06:00:00.0
2018-03-19 06:00:00.0

Because my time zone agrees with the time zone in the date-time object, I get the same result from both conversions. In other time zones the result may not be the same, and you will need to take care to pick the correct one.

What went wrong in your code?

When you use SimpleDateFormat for parsing a string with a UTC offset in it, it uses that offset for determining the point in time. In this case it does not use the time zone you have set through setTimeZone for anything. And it doesn’t put any time zone or offset into the Date it returns because a Date cannot contain a time zone. It is just a point in time.

What confuses many is that the result of Date.toString() seems to contain a time zone abbreviation, as UTC in your output Mon Mar 19 05:00:00 UTC 2018. What happens is that toString() uses the JVM’s time zone setting for generating the string. This is why TimeZone.setDefault() affects the output you get: it sets the JVM setting, affecting all programs running in the same JVM. It doesn’t affect the Date object itself, however, only the result of its toString().

The TimeZone, Date and Timestamp classes are long outdated. SimpleDateFormat is too and at the same time notoriously troublesome. I recommend you don’t use those classes at all. java.time is so much nicer to work with.

Link

Oracle tutorial: Date Time explaining how to use java.time.

like image 106
Ole V.V. Avatar answered Oct 22 '22 01:10

Ole V.V.