I am confused with Timezone conversions in Java. I have a few cases which I will list out below.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// sdf.setTimeZone(TimeZone.getTimeZone("Asia/kolkata"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); //. O/P - Sun Jan 31 00:00:00 IST 2021
Now lets uncomment the Timezone part and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/kolkata"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 05:30:00 IST 2021
Now lets set the TimeZone to IST and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("IST"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 00:00:00 IST 2021
Now lets set the TimeZone to UTC and see the time difference
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1); // O/P - Sun Jan 31 05:30:00 IST 2021
Can anybody please explain me why this shift in time is happening (+- 5:30) when I change the Timezone?
For IST and Asia/Kolkata, time should have remain same because they are same Timezone, but why the shift?
Why When using the UTC Timezone, time gets increased by 5:30 hours? What I understand is IST is 5:30 hrs ahead of UTC, so cnverting to UTC should have decreased the time by 5:30 hrs
Why even after converting to UTC, my time displays IST 2021?
I still have confusion here.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1.getTime()); // 1612051200000
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf1.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date2 = sdf1.parse("2021-01-31");
System.out.println(date2.getTime()); // 1612031400000
Why instant of time in UTC is greater than instant of time in Asia/Kolkata ?
Here are some things for you to note:
When a Date is printed, it will be formatted in your computer's local timezone (that's what Date.toString does). Presumably, your computer is in the Asia/Kolkata timezone, so the output is always displayed as a date & time in that timezone.
A Date represents a point in time (i.e. an instant). It is not a tuple of year, month, day, hour, minute, seconds and timezone
Since there are no time in your input string, the time 00:00:00 is used for the time when parsing.
Just a date and a time is not enough to produce a point in time. You also need a timezone to specify a point in time. Since there is no timezone in your input string, the local timezone of your computer is used, or if you have set it, sdf.getTimeZone().
Although a timezone is used in parsing the date, the timezone is not part of the Date object.
Can anybody please explain me why this shift in time is happening (+- 5:30) when I change the Timezone?
When you use the "IST" timezone (first and third code snippet), sdf gets the following pieces of information:
Date: 2021-01-31
Time: 00:00:00
TimeZone: Asia/Kolkata
With these pieces of information, it can produce a point in time, represented by a number of milliseconds since the Java Epoch - 1970-01-01 00:00:00 UTC. This is the Date object. Then you print the Date object, which gets formatted to your local timezone. Your local timezone just so happens to be the same as the one that sdf is provided with, so you see Sun Jan 31 00:00:00 IST 2021.
When you use UTC (second and fourth code snippets), these information are provided to sdf:
Date: 2021-01-31
Time: 00:00:00
TimeZone: UTC
That represents a different point in time than 2021-01-31T00:00:00 in Kolkata. How different? 2021-01-31T00:00:00 in UTC is exactly 5 and a half hours later than 2021-01-31T00:00:00 in Kolkata. Recall that to convert a UTC time to Kolkata, you add 5 and a half hours.
For IST and Asia/Kolkata, time should have remain same because they are same Timezone, but why the shift?
Because you have misspelled Asia/Kolkata. The first "K" in "Kolkata" should be capitalised. Unknown zone IDs are treated as UTC by the TimeZone class. This is why you should move to the new java.time classes. ZoneId throws an exception if you supply it with an unknown zone ID.
Why When using the UTC Timezone, time gets increased by 5:30 hours? What I understand is IST is 5:30 hrs ahead of UTC, so converting to UTC should have decreased the time by 5:30 hrs
You are thinking about formatting dates, not parsing, because remember that the timezone is not part of Date, but part of SimpleDateFormat. Your code does not format Date, only parses them. Without formatting, Dates are always printed in your local timezone.
To see your desired behaviour using SimpleDateFormat, you'd first parse the date string once, and then format it using SimpleDateFormats with different timezones.
Really though, you should change to java.time. Using that API, your zone changing code could be written like so:
ZonedDateTime zdt = LocalDate.parse("2021-01-31")
.atStartOfDay()
.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdt);
ZonedDateTime utcDateTime = zdt.withZoneSameInstant(ZoneId.of("UTC"));
System.out.println(utcDateTime);
// output:
// 2021-01-31T00:00+05:30[Asia/Kolkata]
// 2021-01-30T18:30Z[UTC]
java time
I recommend you use java.time, the modern Java date and time API, for your date work
LocalDate date = LocalDate.parse("2021-01-31");
System.out.println(date);
Output is:
2021-01-31
A LocalDate is a date without time of day and without time zone or UTC offset, so using it frees you completely from all time zone trouble. Furthermore we don’t need any explicit formatter. Your string is in ISO 8601 format, and LocalDate parses the most common ISO 8601 variant as its default. As you can see, it also prints the same ISO 8601 format back when we print it, implicitly calling its toString method.
What went wrong in your code?
The SimpleDateFormat, TimeZone and Date classes that you are using are poorly designed and long outdated. No wonder that their behaviour confuses you.
I am assuming that Asia/Kolkata (or Asia/Colombo or Asia/Calcutta) is the default time zone of your JVM. In your first example the SimpleDateFormat is using your default time zone and is parsing the string into the first moment of the day in that time zone.
In your second example, as Elavya has spotted so well, you have got a lower case k in Asia/kolkata which causes TimeZone not to recognize the intended time zone. And this is where TimeZone excels in bad design: it just tacitly gives you GMT instead. Next the Date class is poorly designed too and still prints the time in the default time zone of the JVM, giving the illusion that the Date object contains a time zone. This has confused very many. The start of the day in GMT is the same point in time as 05:30:00 IST, so this is what you get.
In your third and fourth example, even though the three letter time zone abbreviations are deprecated, IST (contrary to what Eklavya said) is interpreted as Asia/Kolkata and UTC as Etc/UTC. Even though as Eklavya also said, IST is ambiguous.
So in short:
The change happens because the start of the day is a different point in time in different time zones.
Because of your typo in Asia/kolkata. Time zone IDs are case sensitive.
You are not converting to UTC. You are parsing in UTC thereby converting from UTC, and Date.toString() further converts to Asia/Kolkata (IST) as the output also says.
Because the Date object hasn’t got a time zone and because Date.toString() grabs the default time zone of your JVM and uses it for rendering the string to be returned.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
All about java.util.Date
Java doc for getTimeZone
ID - the ID for a TimeZone, either an abbreviation such as "PST", a
full name such as "America/Los_Angeles", or a custom ID such as
"GMT-8:00". Note that the support of abbreviations is for JDK 1.1.x
compatibility only and full names should be used.
TimeZone abbreviation is not supported. So you can't use IST
And in TimeZone Doc for Three-letter time zone IDs
For compatibility with JDK 1.1.x, some other three-letter time zone
IDs (such as "PST", "CTT", "AST") are also supported. However, their
use is deprecated because the same abbreviation is often used for
multiple time zones (for example, "CST" could be U.S. "Central
Standard Time" and "China Standard Time"), and the Java platform can
then only recognize one of them.
Problem is IST abbreviation is used for multiple time zones like Irish Standard Time, Isreal Standrad Time, Indian Standard Time. And you mistyped Asia/Kolkata as Asia/kolkata.
So, the GMT zone will return if the given ID cannot be understood from TimeZone.getTimeZone()
As an addition to the accepted answer, for the last part of your question;
Why instant of time in UTC is greater than instant of time in Asia/Kolkata in below code?
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date1 = sdf.parse("2021-01-31");
System.out.println(date1.getTime()); // 1612051200000
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf1.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date2 = sdf1.parse("2021-01-31");
System.out.println(date2.getTime()); // 1612031400000
First, you have a point T in time regardless of timezone. In our example T=2021-01-31 00:00:00.
When we set timezone as UTC and print the time using java.util.Date.getTime() method, it will print milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. So it will print 1612051200000. As you see the epoch and our date has the same timezone which is UTC. So the time is printed directly, no adjustment necessary for timezone.
Now, when we set timezone as Asia/Kolkata, during SimpleDateFormat.parse, timezone information will be added to date. That means +5:30h(19800000ms) will be added to time T. Therefore our time T is increased by 19800000ms. However T must be pointing to the same point in time. How do we fix that? It is fixed on SimpleDateFormat.parse method by subtracting 19800000ms from the time 1612051200000ms so that getTime() method will now show 1612031400000ms so that our actual time T will still show the same point in time(which is 1612051200000ms) because in this date object we have an extra 19800000ms which comes from timezone.
Our server is running in netherlands but users uses the application in UK .
For UK 2017-03-26 02:30:00 is valid date-time but not in Netherlands.
I am using the code to convert the time by setting the timezone . But its not giving me right output.
String toDate ="2017-03-26 02:30:00";//Valid Time in UK
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Use London's time zone to format the date in
df.setTimeZone(TimeZone.getTimeZone("London"));
System.out.println("Date and time in London: " + df.parse(toDate));
Output from Program : Date and time in London: Sun Mar 26 04:30:00 CEST 2017
Output Required : Date and time in London: Sun Mar 26 02:30:00 CEST 2017
Java version used : 1.7 . Can not use joda time for some dependency.
First a detail, TimeZone.getTimeZone() is dangerous, if it doesn’t recognize the ID string, it will tacitly give you GMT. Exactly in London this is so close to the correct you may get fooled for a while. TimeZone.getTimeZone("London") gives you UTC (or GMT). As Stefan Freitag pointed out, it has to be TimeZone.getTimeZone("Europe/London") for the correct British time zone.
Next a very common misunderstanding: A Date object does not have a time zone in it. It’s a point in time only. So how come it is printed as Sun Mar 26 04:30:00 CEST 2017, where CEST obviously refers to a time zone (Central European Summer Time, used in the Netherlands)? When printing the date, you are implicitly invoking Date.toString(). This methods unconditionally prints the time according the default time zone for the JVM. Therefore, setting the time zone for the DateFormat you used for parsing has no effect here. And therefore changing the JVM’s time zone setting, as Hugo did in a comment, works. The other way of getting correct output for British users is to format the Date back into a string using a DateFormat with British time zone.
If you use Hugo’s trick in the beginning, before creating the DateFormat, it too will have the British time zone, and you need not call df.setTimeZone() (but you may if you think it makes the code clearer, of course).
Look forward to using Java 8 or later some day. The new date and time classes in java.time generally don’t come with the surprises experienced with the old ones.
I wanted to raise issue directly on joda github, but there was a hint, that i should at first ask it on stackoverflow.
If you try to use joda DateTime object in Greenwich Mean Time Zone (UK), you are getting bad DateTime value
Step to reproduce
Write method like this
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z");
DateTime dt = formatter.parseDateTime("2014-02-16T07:00:00.000Z");
System.out.println(dt);
Expected value
2014-05-16T07:00:00.000+00:00
Actual value
2014-05-16T07:00:00.000+Z
In UK, time is changed every 29 March. This is the last day in year, when time is +00:00. From 30 march till next time change there is +01:00.
If think that joda has problem with processing +00:00 gmt.
UK Time is not GMT... If you want UK time, use a full timezone name: Europe/London.
UK could be in GMT or BST based on the time of the year. The timezone can be mentioned like below:-
DateTime dt = formatter.parseDateTime("2014-02-16T07:00:00.000Z").withZone(DateTimeZone.forID("Europe/London"));
I would like to know if the following is DST aware ie., the SimpleDateFormat parse method is DST aware if we set the Timezone of that respective country.
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(TimeZone.getTimeZone("CET")); //Germany
String currentDate = sdf.format((new Date()).getTime());
currentDate = sdf.parse(currentDate);
I undserstand that "CET", "MST", "EST" etc are three letter codes and is not encouraged to use this, but irrespective of this is the dateformat parse DST aware ?
Thanks in advance.
In some specific cases, the three-letter codes will work - but not all of them include daylight saving time rules.
From the TZ database sources:
Europe:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone WET 0:00 EU WE%sT
Zone CET 1:00 C-Eur CE%sT
Zone MET 1:00 C-Eur ME%sT
Zone EET 2:00 EU EE%sT
North America:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone EST -5:00 - EST
Zone MST -7:00 - MST
Zone HST -10:00 - HST
As you can see, the European file defines 4 three-letter zones for backwards compatibility purposes, all of which follow European daylight saving time rules.
However, the North American file only defines 3 of these. Notably, PST and CST are missing. Also, the EST and MST zones that are defined do not have any daylight saving time rules.
In general, you should avoid using the three-letter abbreviations. They are not all supported, the ones that are do not all support DST, and in general they can be ambiguous.
Sorry if this is a re-post. I did not find a suitable answer.
Please ignore best practices and use of deprecated apis.
I want to format the following date "Mon May 19 02:16:52 EDT 2003" into "MM/dd/yyyy HH:mm:ss". Again, I only want to change the output format and this is being executed from my laptop which is in EST.
My Windows Regional Settings are:
Current time zone: Eastern Daylight Time
Timezone: (GMT-05:00) Eastern Time (US & Canada)
Automatically adjust clock for daylight saving changes: Checked
This java code does it:
Date aDate = new Date("Mon May 19 02:16:52 EDT 2003");
SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy HH:mm:ss");
System.out.println("Formatted Date: " + sdf.format(aDate));
Output is
Formatted Date: 05/19/2003 02:16:52
Now I change the windows setting to the following (only uncheck the DST setting)
Current time zone: Eastern Daylight Time
Timezone: (GMT-05:00) Eastern Time (US & Canada)
Automatically adjust clock for daylight saving changes: Checked
Output is:
Formatted Date: 05/19/2003 01:16:52
Questions:
Why is the output off by an hour?
Does java use Windows DST settings even when formatting? I though java maintains its own data for DST settings times for various timezones.
Internally, dates are stored by a long value that represents the number of milliseconds past some epoch. When you clicked off the daylight savings time on you machine, you changed your timezone. So Java is using the same time number with a different timezone and that's why you have what you have
Because the summer time is one hour ahead of the normal one. Set your calendar to January and you'll see no difference.
When you create the Date Java will internally store the value as GMT. When you format the date to a String Java will use your computers time zone to convert the date to your local time zone, which is the reason that you get different results. As an example, if I run the following code on my computer (with time zone CEST):
System.out.println(new Date("Mon May 19 02:16:52 UTC 2003"));
System.out.println(new Date("Mon May 19 02:16:52 EDT 2003"));
System.out.println(new Date("Mon May 19 02:16:52 PST 2003"));
I get the following results:
Mon May 19 04:16:52 CEST 2003
Mon May 19 08:16:52 CEST 2003
Mon May 19 12:16:52 CEST 2003
If you want more predictable results you could either not supply a time zone in your input (e.g. as long as input and output is performed in the same time zone it stays the same) or use a more reliable method where you specify which time zone to use:
SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("EDT"));
It's because by default SimpleDateFormat prints date in your system time zone. To check it, add time zone output to format: "MM/dd/yyyy HH:mm:ss z" So you'll see in what time zone it actually prints the value.
If you want to control, in what timezone you want to format value, use DateFormat.setTimeZone(TimeZone z) method.