Can somebody please tell, what's the difference between the following two statements:
TimeZone.getTimeZone("America/New_York")
and
TimeZone.getTimeZone("EST")
In other words, why is EST different from America/New_York. Also in my application, to get the current time zone in US, should I use America/New_York or EST.
EST is UTC - 5 hours. America/New_York is EST in the winter and E*D*T in the summer, so right now New York is UTC - 4 hours.
EST is half of the New York time zone, effectively. It's always in standard time - it doesn't have the daylight saving part. It's not really a proper time zone in its own right, IMO - it's the "standard" part of a fuller time zone. When writing about a time zone which is just a fixed offset and not related to a particular place, I'd prefer to use "Etc/GMT+5" or something similarly obviously-fixed. (I don't generally like even "Eastern Time" and the like, as different places which observe "Eastern Time" may vary in their DST transitions. It's a bit like calling an encoding "extended ASCII"... it tells you some information, but not quite enough.)
So if you want to know the actual local time for New York at any particular instant, use America/New_York.
In general, stay away from the abbreviations. From the documentation:
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.
(Personally I'd also advise you to stay away from Date and Calendar, preferring to use Joda Time wherever possible. That's a different matter though, really.)
The timezone, America/New_York observes two different timezone offsets:
EST (winter time): has a timezone offset of -05:00 hours
EDT (summer time): has a timezone offset of -04:00 hours
java.time
The java.util Date-Time API 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*.
Also, quoted below is a notice from 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.
What Date-Time object should I use to adjust the offset automatically?
Use ZonedDateTime which has been designed to adjust the timezone offset automatically.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.of("America/New_York");
// Custom times
ZonedDateTime zdtDstOn = ZonedDateTime.of(LocalDate.of(2020, Month.OCTOBER, 22), LocalTime.MIN, zoneId);
ZonedDateTime zdtDstOff = ZonedDateTime.of(LocalDate.of(2020, Month.NOVEMBER, 22), LocalTime.MIN, zoneId);
System.out.println(zdtDstOn);
System.out.println(zdtDstOff);
// Current time
ZonedDateTime zdtNow = ZonedDateTime.now(zoneId);
System.out.println(zdtNow);
}
}
Output:
2020-10-22T00:00-04:00[America/New_York]
2020-11-22T00:00-05:00[America/New_York]
2021-08-17T12:19:41.854781-04:00[America/New_York]
ONLINE DEMO
Avoid using the abbreviated timezone names
The following quote from the documentation states the problem clearly:
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.
Then, what Date-Time object should I use for a fixed timezone offset?
Use OffsetDateTime for a fixed timezone offset.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
ZoneOffset zoneOffset = ZoneOffset.of("-04:00");
// A custom time
OffsetDateTime odt = OffsetDateTime.of(LocalDate.of(2020, Month.OCTOBER, 22), LocalTime.MIN, zoneOffset);
System.out.println(odt);
// Current time
OffsetDateTime odtNow = OffsetDateTime.now(zoneOffset);
System.out.println(odtNow);
}
}
Output:
2020-10-22T00:00-04:00
2021-08-17T12:36:09.123599-04:00
ONLINE DEMO
Note: For any reason, if you need to convert an object of OffsetDateTime or ZonedDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(odtNow.toInstant());
or
Date date = Date.from(zdtNow.toInstant());
Learn more about the modern Date-Time API* from Trail: Date Time.
Check this answer and this answer to learn how to use java.time API with JDBC.
* 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.
Related
I want to get the real offset for a timezone.
My problem :
TimeZone tz = TimeZone.getTimeZone("America/Toronto");
int test = tz.getRawOffset();
test = -18000000
-18000000/1000/3600 = -5
Or if i go https://www.google.fr/search?q=horaire+toronto&oq=horaire+toro&aqs=chrome.1.69i57j0l5.3311j0j7&sourceid=chrome&ie=UTF-8
i see Toronto is on UTC-4.
Its written on documentation , that the method return brut offset.
But how i can get the real offset ?
getRawOffset doesn't take DST into account. It reflects standard time. From the docs:
Returns the amount of time in milliseconds to add to UTC to get standard time in this time zone. Because this value is not affected by daylight saving time, it is called raw offset.
Toronto is currently observing daylight saving time (until November 4th) so its current UTC offset is -4 hours, but that's -5 hours "standard" and +1 hour DST.
Now there's an inaccurate assumption there: that a time zone never changes its standard time. java.util.TimeZone is a relatively old and primitive representation; it would be better to use java.time.ZoneId instead, along with the rest of the java.time package.
If you must use java.util.TimeZone, then call getOffset(long) to get the UTC offset at a particular instant in time.
java.time
The java.util API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.of("America/Toronto");
LocalDateTime ldtDstOn = LocalDateTime.of(LocalDate.of(2018, Month.OCTOBER, 22), LocalTime.MIN);
LocalDateTime ldtDstOff = LocalDateTime.of(LocalDate.of(2018, Month.NOVEMBER, 22), LocalTime.MIN);
// Using ZonedDateTime
ZoneOffset offsetDstOn = ZonedDateTime.of(ldtDstOn, zoneId).getOffset();
// Alternatively, using ZoneId#getRules
ZoneOffset offsetDstOff = zoneId.getRules().getOffset(ldtDstOff);
System.out.println(offsetDstOn);
System.out.println(offsetDstOff);
}
}
Output:
-04:00
-05:00
ONLINE DEMO
Verify with Clock Changes in Toronto, Ontario, Canada 2018
Learn more about 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.
Don't use getRawOffset
use : tz.getOffset(new Date().getTime()) / 1000 / 3600
With the below code, every timezone is printing the value correctly except BST
import java.text.*;
def format = "yyyy-MM-dd HH:mm:ssXXX"
def dt = new Date();
println dt;
SimpleDateFormat utcFormat = new SimpleDateFormat(format)
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"))
println utcFormat.format(dt)
SimpleDateFormat istFormat = new SimpleDateFormat(format)
istFormat .setTimeZone(TimeZone.getTimeZone("IST"))
println istFormat.format(dt)
SimpleDateFormat cetFormat = new SimpleDateFormat(format)
cetFormat.setTimeZone(TimeZone.getTimeZone("CET"))
println cetFormat.format(dt)
SimpleDateFormat bstFormat = new SimpleDateFormat(format)
bstFormat.setTimeZone(TimeZone.getTimeZone("BST"))
println bstFormat.format(dt)
Output:
Mon Mar 26 09:04:14 UTC 2018
2018-03-26 09:04:14Z
2018-03-26 14:34:14+05:30
2018-03-26 11:04:14+02:00
2018-03-26 15:04:14+06:00
Here BST time is wrong. Whats wrong with it?
You should avoid using the abbreviated timezone name. Check the following note from the TimeZone documentation:
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.
In your case, probably the system has mapped BST to Bishkek Standard Time which has a timezone offset of +06:00 hours. The standard naming convention is Region/City e.g. Europe/London, Europe/Paris, Asia/Kolkata etc. where City generally refers to the biggest city of a country in the region. In case of doubt, execute the following statement to get all timezone IDs:
System.out.println(ZoneId.getAvailableZoneIds());
java.time
The java.util Date-Time API 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*.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ssXXX", Locale.ENGLISH);
Instant now = Instant.now();
System.out.println(now.atZone(ZoneOffset.UTC).format(dtf));
System.out.println(now.atZone(ZoneId.of("Asia/Kolkata")).format(dtf));
System.out.println(now.atZone(ZoneId.of("Europe/Paris")).format(dtf));
System.out.println(now.atZone(ZoneId.of("Europe/London")).format(dtf));
}
}
Output from a sample run:
2021-10-12 12:24:03Z
2021-10-12 17:54:03+05:30
2021-10-12 14:24:03+02:00
2021-10-12 13:24:03+01:00
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* 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. Note that Android 8.0 Oreo already provides support for java.time.
It seems you expect BST to be British Summer Time, but in this case it represents Bangladesh Standard Time.
Also see What does Java's BST ZoneId represent?
From Answer:
the below code works
SimpleDateFormat bstFormat = new SimpleDateFormat(format)
bstFormat.setTimeZone(TimeZone.getTimeZone("Europe/London"))
println bstFormat.format(dt)
I ran your code and found that the time for BST was just right. Adding the offset of 6 hours to your UTC time of 09:04:14 gives 15:04:14. I think you're confused with the acronym of the time zone.
If your timezone database in JVM is incorrect, you can get the British Summertime Timezone by TimeZone.getTimeZone("Europe/London");
I have two related questions.
Assume a program running in (British Standard Time)BST generates a date time value for current time in UTC (YYYY-MM-DDTHH:MM:SS.SSSZ) format.
Also assume current time in London is 2016-06-01 12:33:54.
If the current time given by the program is 2016-06-01T11:33:54.000Z , is the program wrong?
How is summertime offset for BST noted in the corresponding time format for YYYY-MM-DDTHH:MM:SS.SSSZ
I assume YYYY-MM-DDTHH:MM:SS+0001. Am I correct ?
Firstly please have a read of the iso8601 information. It's becoming more common place to deal with times in different time zones (e.g. server time zone and client time zone) and the standard is really useful.
In particular please read about UTC or "Zulu" time here.
The program is correct, since the London time is one hour ahead of "UTC" time in summer
The trailing 'Z' is a short notation for UTC (Zulu). You could also write "+00:00" instead of 'Z'. The SS.SSS refer to seconds and milliseconds - not related to the time zone. In devnull's comment he shows you how to apply an offset for summer.
Edit:
There's been some discussion in the comments about whether iso8601 timezone includes timezone or not, and whether timezone will in fact be printed out.
This depends completely on the date/time implementation. If we are using SimpleDateFormat then timezone is supported and will be printed.
Here's a code example to illustrate
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(formatter.format(new Date()));
formatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(formatter.format(new Date()));
Output
2016-06-02T12:53:14.924Z
2016-06-02T13:53:14.925+01:00
Naturally, if you are using a different date/time library such as joda-time, then the implentation details will be different.
Edit: As #DerrylThomas pointed out with SimpleDateFormat wise to use lower case y for years - unless it's intended to use week year - explained in a bit of detail in another answer to a similar question https://stackoverflow.com/a/56911450.
if the current time given by the program is 2016-06-01T11:33:54.000Z ,
is the program wrong?
The format is correct and conforms to ISO 8601 but it does not represent Europe/London time. In London, in 2016, the DST started at Sunday, March 27, 1:00 am and ended at Sunday, October 30, 2:00 am and therefore a date-time representation for Europe/London during this time should have a timezone offset of +01:00 hours. The Z at the end specifies Zulu time which is UTC time and thus has a timezone offset of +00:00 hours. The same instant can be represented for Europe/London as 2016-06-01T12:33:54+01:00.
java.time
The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API* .
Even Joda-Time should not be used anymore. Notice the following note at the Home Page of Joda-Time
Joda-Time is the de facto standard date and time library for Java
prior to Java SE 8. Users are now asked to migrate to java.time
(JSR-310).
java.time API is based on ISO 8601 and the date-time string, 2016-06-01T11:33:54.000Z can be parsed into java.time.ZonedDateTime and java.time.OffsetDateTime without needing a date-time parsing/formatting type.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.parse("2016-06-01T11:33:54.000Z");
System.out.println(zdt);
ZoneId zoneId = ZoneId.of("Europe/London");
ZonedDateTime zdtInLondon = zdt.withZoneSameInstant(zoneId);
System.out.println(zdtInLondon);
}
}
Output:
2016-06-01T11:33:54Z
2016-06-01T12:33:54+01:00[Europe/London]
How to deal with Daylight Saving Time (DST)?
As mentioned earlier, the date-time string, 2016-06-01T11:33:54.000Z can also be parsed into java.time.OffsetDateTime without needing a date-time parsing/formatting type. However, OffsetDateTime has been designed to deal with a fixed timezone offset whereas ZonedDateTime has been designed to deal with a timezone and thus it take care of DST automatically. You can convert a ZonedDateTime to OffsetDateTime using ZonedDateTime#toOffsetDateTime if required.
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS z", Locale.ENGLISH);
String strDateTime = "2016-03-01T11:33:54.000 Europe/London";
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
strDateTime = "2016-06-01T11:33:54.000 Europe/London";
zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2016-03-01T11:33:54Z[Europe/London]
2016-06-01T11:33:54+01:00[Europe/London]
Notice how the timezone offset has automatically changed from Z to 01:00 to reflect DST change. On the other hand,
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
String strDateTime = "2016-03-01T11:33:54.000+01:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt);
strDateTime = "2016-06-01T11:33:54.000+01:00";
odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt);
}
}
Output:
2016-03-01T11:33:54+01:00
2016-06-01T11:33:54+01:00
In this case, you do not talk about a timezone (e.g. Europe/London); rather, you talk about a fixed timezone offset of +01:00 hours.
Learn more about 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.
Given a UTC offset, i.e. -5, can I determine the USA time zone using Joda Time? One of Pacific, Mountain, Central, Easter is sufficient. I can't use Java 8.
If you only have an offset, then no, you can't. -5 could be Central Daylight Time or Eastern Standard Time, for example. Likewise an offset of -7 could be Pacific Daylight Time or Mountain Standard Time.
If you have an offset and a date/time at which it was valid, you could make a pretty good guess - but only if you assume that everywhere in the US switches to daylight saving, and that everywhere does it at the same time - but that's not entirely the case.
You can always obtain a timezone offset from a timezone ID but the reverse of it is not possible because the same timezone offset can be applicable to many timezone IDs. Check List of tz database time zones to find many examples of it.
Note that some timezone IDs can have different timezone offsets (e.g. because of DST or when a country decides to change it). However, you do not need to worry about it as long as the timezone database of your Java installation is up-to-date.
ZonedDateTime has been designed to adjust the timezone offset automatically according to the moment you use it for.
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalTime time = LocalTime.of(10, 20);
ZoneId zoneId = ZoneId.of("Europe/London");
System.out.println(ZonedDateTime.of(LocalDate.of(2021, Month.MARCH, 27), time, zoneId));
System.out.println(ZonedDateTime.of(LocalDate.of(2021, Month.MARCH, 28), time, zoneId));
// ############# Obtaining timezone offset from ZoneId #############
LocalDateTime ldt = LocalDateTime.of(LocalDate.of(2021, Month.MARCH, 28), time);
System.out.println(ZonedDateTime.of(ldt, zoneId).getOffset());
// Alternatively
System.out.println(zoneId.getRules().getOffset(ldt));
}
}
Output:
2021-03-27T10:20Z[Europe/London]
2021-03-28T10:20+01:00[Europe/London]
+01:00
+01:00
ONLINE DEMO
The Z in the output 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).
Learn more about 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.
I was looking for a way to get current time in various timezones based on an user input. I know I could use Joda Time! but is that the only way?
Isn't there an option in Java for doing this? I tried the following code which gives the same output for all 3 sysouts.
Calendar pst = Calendar.getInstance(TimeZone.getTimeZone("PST"));
System.out.println("PST " + pst.getTime());
Calendar ist = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
System.out.println("IST " + ist.getTime());
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("UCT " + utc.getTime());
What am I missing here to get current time in other timezones?
Yes, that would show the same value in every case (or milliseconds apart) because the three calendars all refer to the same instant in time (execution time notwithstanding) and that's all that a java.util.Date represents. That's the result of Calendar.getTime().
However, the Calendar itself does know about time zones, and that will be reflected when you use Calendar.get etc. It will also be used when you use a SimpleDateFormat, where you can specify a particular time zone.
// Specify whatever format you want - bear in mind different locales etc
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(calendar.getTimeZone());
String text = format.format(calendar.getTime());
It's not clear exactly what you're trying to do, but basically you need to be aware of which types are time zone aware, and which aren't. It's really important to understand that a java.util.Date doesn't have a format, a calendar system or a time zone: it's just the number of milliseconds since the Unix epoch.
As Jon pointed out the method getTime() is returning a java.util.Date object which is just a millisecond value and not timezone aware.
If you are just looking at printing the times then you can use the calendar and manually get the fields you want like
System.out.println(utc.get(Calendar.HOUR_OF_DAY) + ":" + utc.get(Calendar.MINUTE))
This would need some formatting for a minute < 10 to display the 0
java.time
The java.util Date-Time API 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*.
Also, quoted below is a notice from 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 Date-Time API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
ZonedDateTime zdtLos = now.atZone(ZoneId.of("America/Los_Angeles"));
ZonedDateTime zdtIndia = now.atZone(ZoneId.of("Asia/Kolkata"));
ZonedDateTime zdtUtc = now.atZone(ZoneOffset.UTC);
System.out.println(zdtLos);
System.out.println(zdtIndia);
System.out.println(zdtUtc);
}
}
Output from a sample run:
2021-07-26T12:39:17.413671-07:00[America/Los_Angeles]
2021-07-27T01:09:17.413671+05:30[Asia/Kolkata]
2021-07-26T19:39:17.413671Z
ONLINE DEMO
An Instant represents an instantaneous point on the timeline, normally represented in UTC time. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
For any reason, if you need to convert this object of Instant to an object of java.util.Date, you can do so as follows:
Date date = Date.from(instant);
Learn more about the modern Date-Time API from Trail: Date Time.
Never use the 3-letter abbreviated timezone ID
Given below is an excerpt from the documentation page of TimeZone:
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.
* 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.