I was going through TimeZone page at joda website and I came across this
-05:00 EST
-05:00 EST5EDT
-05:00 Etc/GMT+5
I just wanted to know what does that EST5EDT means, I generally use EST so was just wanted to know about it.
I have searched about it and found nothing before posting the question.
I ran into an issue with US/Eastern, Americas/New_York, and EST5EDT. Here is what I discovered.
For dates after the Uniform Time Act of 1966 went into effect in 1967, these timezones are all identical. Also the US enforced standard DST rules during the World Wars, so they are all identical 1918-1919 and 1942-1945.
For any date before 1918, between 1920 and 1941 inclusive, and between 1946 and 1966 inclusive, EST5EDT will always be identical to EST. No DST is observed. Any date before 1883 Nov 18 12:03:58 will be treated as if the timezone EST existed.
Prior to 1967, Americas/New_York will provide the time as observed in New York City. So Daylight Savings Time will follow the rules in place by the NYC municipal or NY state government. Any date before 1883 Nov 18 12:03:58 will be in local mean time with an offset of -4:56:02 from UTC.
Here is a fragment of Ruby showing the difference:
# you may need to install the tzinfo gem with
# gem install tzinfo
require 'tzinfo'
# Using EST5EDT
# In 1966 DST is not observed.
Time.new(1966, 6, 1, 0, 0, 0, TZInfo::Timezone.get("EST5EDT"))
=> 1966-06-01 00:00:00 -0500
# DST is observed in 1967.
Time.new(1967, 6, 1, 0, 0, 0, TZInfo::Timezone.get("EST5EDT"))
=> 1967-06-01 00:00:00 -0400
# Now with America/New_York
# DST is observed in 1966
Time.new(1966, 6, 1, 0, 0, 0, TZInfo::Timezone.get("America/New_York"))
=> 1966-06-01 00:00:00 -0400
# DST is also observed in 1967
Time.new(1967, 6, 1, 0, 0, 0, TZInfo::Timezone.get("America/New_York"))
=> 1967-06-01 00:00:00 -0400
# America/New_York yields local time for pre-timezone dates.
Time.new(1867, 6, 1, 0, 0, 0, TZInfo::Timezone.get("America/New_York"))
=> 1867-06-01 00:00:00 -0456
# But EST5EDT retroactively applies timezones
Time.new(1867, 6, 1, 0, 0, 0, TZInfo::Timezone.get("EST5EDT"))
=> 1867-06-01 00:00:00 -0500
Odd things can happen if you have multiple systems where one assumes EST5EDT and the other assumes Americas/New_York, especially when a system is storing DATE fields as DATETIME fields with the hours/minutes/seconds set to midnight. Data might look fine for anything recent. But a birthdate for example, from the summer of 1966 might get moved an hour, then truncated so it appears to be on the prior day.
And just for extra fun if you are dealing with old dates in Alaska, you need to remember that Alaska was Purchased from Russia. Dates before 1867 Oct 18 are on the other side of the international date line and use the Julian, not Gregorian Calendar. So Juneau, for example, went from 6 Oct 1867 (Julian) +15:02:19 to 18-Oct-1867 (Gregorian) -8:57:41. (The TZInfo library doesn't handle the Gregorian to Julian change.)
require 'tzinfo'
Time.new(1867, 10, 18, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
=> 1867-10-18 00:00:00 +1502
Time.new(1867, 10, 19, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
#error message
TZInfo::AmbiguousTime (1867-10-19 00:00:00 is an ambiguous local time.)
Time.new(1867, 10, 20, 0, 0, 0, TZInfo::Timezone.get("America/Juneau"))
=> 1867-10-20 00:00:00 -0857
# The Ruby DateTime datatype handles Julian,
# so convert Time to DateTime then to julian
Time.new(1867, 10, 18, 0, 0, 0, TZInfo::Timezone.get("America/Juneau")).to_datetime.julian
=> 1867-10-06 00:00:00 +1502
EST - eastern Standard Time wihtout day light.
EDT - Eastern Standard Time with Day Light Saving Time
This is the short id of TimeZone that is used.
EST5EDT means either in EST or EDT ; value of offset in hours would be the same i.e. -5 hours.
Related
I'm trying to convert ZonedDateTime (EST) to Date (UTC) i see 1 hour off for the month of march for 13 and 14th calendar date
SystemDefault - UTC
ZonedDateTime zonedDateTime1 = ZonedDateTime.of(2021, 3, 13, 19, 0, 0, 0, ZoneId.of("America/New_York"));
Date date1 = Date.from(zonedDateTime1.withZoneSameInstant(ZoneId.systemDefault()).toInstant();
System.out.println("EST -> ", zonedDateTime1);
System.out.println("UTC -> ", date1);
ZonedDateTime zonedDateTime2 = ZonedDateTime.of(2021, 3, 14, 19, 0, 0, 0, ZoneId.of("America/New_York"));
Date date2 = Date.from(zonedDateTime2.withZoneSameInstant(ZoneId.systemDefault()).toInstant();
System.out.println("EST -> ", zonedDateTime2);
System.out.println("UTC -> ", date2);
Actual Result:
EST -> 2021-03-13T19:00-05:00[America/New_York]
UTC -> Sun Mar 14 00:00:00 UTC 2021
EST -> 2021-03-14T19:00-04:00[America/New_York]
UTC -> Sun Mar 14 23:00:00 UTC 2021
Expected Result:
EST -> 2021-03-13T19:00-05:00[America/New_York]
UTC -> Sun Mar 14 00:00:00 UTC 2021
EST -> 2021-03-14T19:00-04:00[America/New_York]
UTC -> Mon Mar 15 00:00:00 UTC 2021
Here is business use case
-> Client specific holidays 2021/1/14, 2021/2/14, 2021/3/14 (These are in UTC)
-> user selects a specific time eg: 2021/2/14 19:00, 2021/3/14 19:00 EST (These two days are actual working days)
Now system has say user selected date is a holiday or working day for
client
For this I converted user selected date (EST) to UTC and checking against client specific calendar (it works for feb but fails for march)
On Sun March 14th daylight saving time started in America/New_York. I suppose this is the reason for the observed difference.
Daylight saving time for America/New_York started on 2021-03-14T02:00:00 EST. That is any date time instance after this (until winter time is effective again) for time zone America/New_York will be EDT and not EST. And EDT has a UTC offset of -4 hours.
Using EST all year
It seems that your client insists on reporting times in EST, Eastern Standard Time, all year, not EDT, Eastern Daylight Time, in summer. There are time zones that do that, so a solution is: instead of using America/New_York time zone, use a time zone that uses Eastern Time and doesn’t use summer time/DST. For example:
ZoneId clientTimeZone = ZoneId.of("America/Atikokan");
ZonedDateTime zonedDateTime1 = ZonedDateTime.of(2021, 3, 13, 19, 0, 0, 0, clientTimeZone);
Date date1 = Date.from(zonedDateTime1.toInstant());
System.out.println("EST -> " + zonedDateTime1);
System.out.println("UTC -> " + date1);
ZonedDateTime zonedDateTime2 = ZonedDateTime.of(2021, 3, 14, 19, 0, 0, 0, clientTimeZone);
Date date2 = Date.from(zonedDateTime2.toInstant());
System.out.println("EST -> " + zonedDateTime2);
System.out.println("UTC -> " + date2);
Output is (when running in UTC time zone):
EST -> 2021-03-13T19:00-05:00[America/Atikokan]
UTC -> Sun Mar 14 00:00:00 UTC 2021
EST -> 2021-03-14T19:00-05:00[America/Atikokan]
UTC -> Mon Mar 15 00:00:00 UTC 2021
Compared to what you expected, the differences are:
The time zone ID is now America/Atikokan.
The UTC offset for 2021-03-14T19:00 is now not -04:00 but -05:00. Which is what causes the time to be converted to the expected UTC time of 00:00.
Compared to your code I have made one other change: I have left the calls to withZoneSameInstant() out. They make no difference here. Since you are doing toInstant() afterward, as the method names say, you get the same instant in both cases.
Edit: North and Central American time zones using Eastern Standard Time all year include:
In Canada: America/Atikokan
In the US: None that I have found
In Central America and the Caribbeans: America/Cancun, America/Jamaica, America/Panama
Can someone explain why is it so? Why there is a 24 minutes offset for that time and how to deal with it?
Scala 2.12 and Java 8.
scala> java.sql.Timestamp.valueOf("1900-01-01 00:59:00")
res22: java.sql.Timestamp = 1900-01-01 00:59:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:00:00")
res23: java.sql.Timestamp = 1900-01-01 01:24:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:14:00")
res24: java.sql.Timestamp = 1900-01-01 01:38:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:20:00")
res25: java.sql.Timestamp = 1900-01-01 01:44:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:23:00")
res26: java.sql.Timestamp = 1900-01-01 01:47:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:24:00")
res27: java.sql.Timestamp = 1900-01-01 01:24:00.0
scala> java.sql.Timestamp.valueOf("1900-01-01 01:30:00")
res28: java.sql.Timestamp = 1900-01-01 01:30:00.0
Look at the time zone definition in the IANA time zone database:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Warsaw 1:24:00 - LMT 1880
1:24:00 - WMT 1915 Aug 5 # Warsaw Mean Time
1:00 C-Eur CE%sT 1918 Sep 16 3:00
2:00 Poland EE%sT 1922 Jun
1:00 Poland CE%sT 1940 Jun 23 2:00
1:00 C-Eur CE%sT 1944 Oct
1:00 Poland CE%sT 1977
1:00 W-Eur CE%sT 1988
1:00 EU CE%sT
In 1900, Poland had a time zone offset of one hour and 24 minutes from UTC, i.e., they were using local mean solar time. That was before standard time zones were introduced on August 5, 1915.
It must be that you feed PostgreSQL a timestamp without time zone, which is interpreted at your local time zone (with an offset of 1:24).
Somebody (scala?) then converts this timestamp back to a timestamp in your local time zone, but erroneously uses an offset of one hour.
I don't know how exactly to fix that, but either use timestamp without time zone throughout or fix the component that thinks the Polish time was offset 1 hour from UTC in 1900.
As far as I can tell there are two bugs involved here. Both are (if I am correct) in the java.util.Date class, the superclass of java.sql.Timestamp.
First, there is no time offset transition in Warsaw in year 1900. The earliest transition that my Java 8 knows of is in 1915. So Warsaw was at offset 1:24 from GMT during all of the time we’re concerned with.
I tried:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw"));
ZoneOffset offset0124 = ZoneOffset.ofHoursMinutes(1, 24);
System.out.println("" + new Date(0, 0, 1, 0, 59)
+ " -> " + new Date(0, 0, 1, 0, 59).toInstant().atOffset(offset0124));
System.out.println("" + new Date(0, 0, 1, 1, 14)
+ " -> " + new Date(0, 0, 1, 1, 14).toInstant().atOffset(offset0124));
System.out.println("" + new Date(0, 0, 1, 1, 24)
+ " -> " + new Date(0, 0, 1, 1, 24).toInstant().atOffset(offset0124));
This prints:
Mon Jan 01 00:59:00 CET 1900 -> 1900-01-01T01:23+01:24
Mon Jan 01 01:38:00 CET 1900 -> 1900-01-01T01:38+01:24
Mon Jan 01 01:24:00 CET 1900 -> 1900-01-01T01:24+01:24
The method Timestamp.valueOf method that you use indirectly uses a deprecated Date constructor, so so am I (not the exact same constructor, I am using the one without seconds, trusting it makes no difference). I will comment on the above three cases backward:
1:24 is handled correctly, we get the expected time both from Date.toString() and from the OffsetDateTime.
1:14 is perceived as 1:38, 24 minutes later. This looks like a bug to me.
0:59 is perceived as 1:23, also 24 minutes later. We can see this from the OffsetDateTime. The same bug. However, Date.toString() produces 00:59 as expected. This seems to me to be a second bug that somehow compensates for the first one. I haven’t checked, but I suspect that the source of this bug also causes Timestamp.toString() to behave incorrectly.
As a check I calculated the difference between your Timestamp objects of 0:59 and 1:24. The desired result is 25 minutes or 1 500 000 milliseconds. The code is:
System.out.println(java.sql.Timestamp.valueOf("1900-01-01 01:24:00").getTime()
- java.sql.Timestamp.valueOf("1900-01-01 00:59:00").getTime());
This prints
60000
60 seconds, the same as 1 minute. So even though both of those timestamps printed the way we had expected, there still is a bug involved.
I have noticed strange behavior of date and time in java. I have the following code:
public class TestDateTime {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Helsinki"));
Calendar calendar = GregorianCalendar.getInstance();
assert(calendar.getTimeZone().equals(TimeZone.getDefault()));
//Set 1899-12-30T23:00:00
calendar.set(1899,11,30,23,0,0);
calendar.set(Calendar.MILLISECOND,0);
long timeInMillis = calendar.getTimeInMillis();
java.util.Date calendarDateTime = new java.util.Date(timeInMillis);
LocalDateTime localDateTime = LocalDateTime.ofInstant(ofEpochMilli(timeInMillis), ZoneId.systemDefault());
System.out.println("Time in millis: " + timeInMillis);
System.out.println("Date: " + calendarDateTime.toString());
System.out.println("Local DateTime: " + localDateTime.toString());
}
}
The output is:
Time in millis: -2209086000000
Date: Sat Dec 30 23:00:00 EET 1899
Local DateTime: 1899-12-30T22:39:49
timeInMillis must contain the number of milliseconds passed from 1970-01-01T00:00:00Z.
The instance of Date class stores number of milliseconds passed from 1970-01-01T00:00:00Z.
Date.toString() method returns local date and time for the default timezone.
So the Date.toString() and LocalDateTime.toString() must return the same date and time, but we see the difference (more than 20 minutes).
Is this a bug of java, or I use date and time incorrectly in Java?
This is a weirdness caused by Finland time change, see Clock Changes in Helsinki, Finland (Helsingfors) in 1921:
May 1, 1921 - Time Zone Change (HMT → EET)
When local standard time was about to reach
Sunday, May 1, 1921, 12:00:00 midnight clocks were turned forward 0:20:11 hours to
Sunday, May 1, 1921, 12:20:11 am local standard time instead
Those 20 minutes 11 seconds seem to be what you're observing.
As Jim Garrison said in his answer, LocalDateTime is correctly handling that, while Calendar is not.
In reality, it seems that the old TimeZone is getting the offset wrong, while the new ZoneId is getting it right, as can be seen in the following test code:
public static void main(String[] args) {
compare(1800, 1, 1, 0, 0, 0);
compare(1899,12,31, 23,59,59);
compare(1900, 1, 1, 0, 0, 0);
compare(1900,12,30, 23, 0, 0);
compare(1921, 4,30, 0, 0, 0);
compare(1921, 5, 1, 0, 0, 0);
compare(1921, 5, 2, 0, 0, 0);
}
private static void compare(int year, int month, int day, int hour, int minute, int second) {
Calendar calendar = new GregorianCalendar();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
calendar.set(year, month-1, day, hour, minute, second);
Date date = calendar.getTime();
ZonedDateTime zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.of("Europe/Helsinki"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z XXX");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z XXX");
System.out.printf("%04d-%02d-%02d %02d:%02d:%02d %s = %d %s = %d %d%n",
year, month, day, hour, minute, second,
sdf.format(date), date.getTime(),
dtf.format(zdt), zdt.toInstant().toEpochMilli(),
date.getTime() - zdt.toInstant().toEpochMilli());
}
Output
1800-01-01 00:00:00 1800-01-01 00:00:00 EET +02:00 = -5364669600000 1800-01-01 00:00:00 EET +01:39 = -5364668389000 -1211000
1899-12-31 23:59:59 1899-12-31 23:59:59 EET +02:00 = -2208996001000 1899-12-31 23:59:59 EET +01:39 = -2208994790000 -1211000
1900-01-01 00:00:00 1900-01-01 00:00:00 EET +02:00 = -2208996000000 1900-01-01 00:00:00 EET +01:39 = -2208994789000 -1211000
1900-12-30 23:00:00 1900-12-30 23:00:00 EET +01:39 = -2177548789000 1900-12-30 23:00:00 EET +01:39 = -2177548789000 0
1921-04-30 00:00:00 1921-04-30 00:00:00 EET +01:39 = -1536025189000 1921-04-30 00:00:00 EET +01:39 = -1536025189000 0
1921-05-01 00:00:00 1921-05-01 00:20:11 EET +02:00 = -1535938789000 1921-05-01 00:20:11 EET +02:00 = -1535938789000 0
1921-05-02 00:00:00 1921-05-02 00:00:00 EET +02:00 = -1535853600000 1921-05-02 00:00:00 EET +02:00 = -1535853600000 0
LocalDateTime is CORRECT. According to the TZ database, the GMT offset at that date was 1:39:49:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31
1:39:49 - HMT 1921 May # Helsinki Mean Time
2:00 Finland EE%sT 1983
2:00 EU EE%sT
Historical timezones are incredibly complex, and prior to standardization offsets were inherited from settings based on things like mean solar noon. When going back that far just about any offset is possible, and the IANA TZ database is the master reference for historical data.
From what I can see in the database, the weird offset did not get standardized to 2:00:00 until 1921 when HMT was replaced with EE(S)T.
As others pointed out, the difference is because the LMT (local mean time) value is not being taken into account by the Date object. This has been discussed before here, with regard to Joda-Time - the precursor to Java 8's time package.
Additionally, the Joda-Time FAQ says the following:
Why is the offset for a time-zone different to the JDK?
There are two main reasons for this.
The first reason is that both the JDK and Joda-Time have time-zone
data files. It is important to keep both up to date and in sync if you
want to compare the offset between the two.
The second reason affects date-times before the modern time-zone
system was introduced. The time-zone data is obtained from the
time-zone database. The database contains information on "Local Mean
Time" (LMT) which is the local time that would have been observed at
the location following the Sun's movements.
Joda-Time uses the LMT information for all times prior to the first
time-zone offset being chosen in a location. By contrast, the JDK
ignores the LMT information. As such, the time-zone offset returned by
the JDK and Joda-Time are different for date-times before the modern
time-zone system.
The last part (which I bolded) is relavent to both Joda-Time and Java 8, even though Java 8 has one set of time zone data files (unlike Joda-Time).
To be more precise about API-inconsistency:
While the new java.time-API always uses the LMT-informations of TZDB, we have also to state that the old JDK-class java.util.TimeZone makes a cut in year 1900 with the consequence that LMT-informations are not taken into account before the year 1900, but after 1900, yes, it is still taken into account! Just make your experiments with an appropriate zone... (Asia/Kamchatka for example)
We cannot really say that either the LMT-strategy of java.time-API is correct or the traditional 1900-strategy. Keep also in mind that there is an open JDK-issue to abolish the LMT-strategy. Citation:
The current TimeZone code does not use LMT. Joda-Time does, as does
JSR-310. This is wrong.
Recent discussion on the tzdb mailing list has indicated that the data
is not properly maintained or reliably linked to the city of the zone
ID. It is also relatively meaningless, being a notional value for a
single city within a large region.
Removing LMT is a good thing.
And Xueming Shen from Oracle says as comment in this issue:
The current j.u.TimeZone implementation DOES use LMT. If the LMT is
defined/used cross the 1900.1.1 j.u.TimeZone cutoff date (by the tzdb
data). For example the offset for Asia/Kamchatka from 1900.1.1 to the
1922.11.10 will be the LMT 10.34.36. Yes, if the LMT end date is before 1900.1.1, the LMT will not be used by the j.u.TZ.
As additional historical note, the JDK-issue was originally suggested by the main author of java.time-API S. Colebourne, see also the ancestor on threeten-issue-tracker.
I have a problem with the difference in getting the time which has arisen this week, possibly due to Daylight Savings Time in the U.S. There is an hour difference in C# and Java (Android). I want the Java to behave the same as the C#.
Windows 10 - C#
value = DateTime.Now;
TimeSpan span = (value - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime());
System.Diagnostics.Trace.WriteLine("span: " + (int)span.TotalSeconds);
Unix epoch seconds:
1489764265
Which converts to:
Fri, 17 Mar 2017 15:24:25 GMT
Java - Android Studio - Run on Samsung T5330-NU
Date date = new Date(); // current date and time
Integer.toString(ConvertToTimestamp(date))
Unit epoch seconds:
1489760686
Which converts to:
Fri, 17 Mar 2017 14:24:46 GMT
The seconds (:25 vs :46) is fine.
The hours are the problem (15 vs 14)
Somehow daylight savings time must be involved.
What can be done?
Using this to convert Unix epoch time:
http://www.onlineconversion.com/unix_time.htm
Edit:
Original Java code gets current date/time like so:
Calendar cal = Calendar.getInstance();
Based on the comment by #AkosNagy, I tried:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("MST"));
and
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("MDT"));
but there is no difference.
Edit:
Changed the title because this is in the end a question about C# and why the C# is not giving the correct time.
Edit:
This is the line I was looking for:
Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime() isn't returning what you think it is. You need to specify the timezone:
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()
1970/1/1 00:00:00.000 in London was actually 1970/1/1 01:00:00.000 UTC (we were in permanent daylight savings at Unix epoch).
Or your computer's clock/timezone may be wrong. After all, you posted your code before Fri, 17 Mar 2017 15:24:25 GMT (it was about Fri, 17 Mar 2017 14:40:00 GMT).
But in any case, it makes the code more robust to specify the UTC timezone, since you won't be dependent upon the local computer's configuration.
(CHECK EDIT BELOW)
In c#, DateTime.Now returns the local time of your computer so time zones don't matter, as you can see in MSDN documentation.
For java, I found these code snippets which use other methods like LocalDateTime.now().
EDIT:
after reading your answer again, I understood that your problem is with the c# code. that is my solution:
instead of that Unix epoch seconds thing:
value = DateTime.Now;
TimeSpan span = (value - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime());
System.Diagnostics.Trace.WriteLine("span: " + (int)span.TotalSeconds);
just use this:
//first, get the corrent time
DateTime date = DateTime.Now;
//print the time
Console.WriteLine(date.ToString());
// For en-US culture, for other culture type refer to MSDN link
//output mm/dd/yyyy hh:mm:ss AM/pm
If you realy need the Unix epoch seconds, refer to this thread
also check your system clock.
Hope I helped!
EDIT: I changed the link to what you needed
I have the following code:
java.util.TimeZone tz = java.util.TimeZone.getDefault();
System.out.println("Server DS Offset: " + tz.getDSTSavings());
Right now the Daylight saving is off, so I was expecting it to return 0, but it still returns 3600000.
Server is Solaris 10
date command returns:
Friday, November 11, 2016 4:27:12 PM EST
env returns:
TZ=Canada/Eastern
How about Determine whether daylight savings time dst is active
What you got in your code is TimeZone attribute about what is offset for DST. In the world some offsets are 30 min. some do not have any. So, if Timezone follows DST then you got this value.