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 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.
I have a timestamp I want to convert to a date. I tried this timestamp: 1336425840. This should be Mon, 07 May 2012 21:24:00 GMT, where GMT is the timezone the emulator should be set to. I tried this:
final Calendar c = Calendar.getInstance();
c.setTimeInMillis(1336425840*1000);
Date d = c.getTime();
Log.i("MyTag", "Hours: " + d.getHours());
The result is: Hours: 23.
So it seems like the returned date is computed according to GMT+2, which is the timezone set for my system. I expected g.hetHours() to return 21, since the emulator's timezone seems to be set to GMT.
Also, that timestamp results from reading the actual date in C using mktime, which seems to return the correct timestamp. But Java seems to refer to a different timezone. Am I doing anything wrong? Why isn't Mon, 07 May 2012 21:24:00 GMT returned?
I'm pretty sure 1336425840*1000 will give you a value outside the regular range of int. In fact, if you would print the full date of the Calendar object, you'll see it displays Thu Jan 08 23:56:50 GMT 1970, which explains the 23 hours you see.
Change the multiplication to: (note the L at the end)
c.setTimeInMillis(1336425840 * 1000L);
// Edit: easy to confirm:
System.out.println((1336425840 * 1000L > Integer.MAX_VALUE));
:)
You should use a DateFormat object, and then set the time zone with setTimeZone().
I have problem with getting server date (linux server). When I use linux 'date' command I get properly date value (real date). If I modify some file
on server, modify date is also properly (real date). But if i use java code System.out.println(new Date()) on server I get date with 1 hour difference
i.e. linux 'date' command result = Wed Sep 16 08:48:25 CEST, System.out.println(new Date()) result = Wed Sep 16 07:48:25 GMT+1
Is this linux configuration problem or wrong getting date using java.
Thanks
date --rfc-2822; date +%s
Wed, 16 Sep 2009 09:59:36 +0200
1253087976
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
16 wrz 2009 09:00:33 +0100
1253088033
You must make sure you use the correct time zone before using Date (or Calendar, for that matter - wasn't Date deprecated?).
For instance:
/* Skipping the boring class def part. */
public static void main(String[] args) {
Date date = new Date();
DateFormat myDateFormat = new SimpleDateFormat();
TimeZone firstTime = TimeZone.getTimeZone(args[0]);
myDateFormat.setTimeZone(firstTime);
System.out.println("-->"+args[0]+": " + myDateFormat.format(date));
}
the argument then can be your desired time zone, for example "IST", "GMT", or whatever.
This is probably a timezone/daylight savings issue. Use:
java.util.Timezone.getDefault()
to see which timezone is Java configured to use and whether daylight savings apply or not.
I suggest you upgrade your Java installation. Your JRE likely doesn't have the latest daylight savings rules in place. Java gets the time since the epoch, and uses your current TZ setting to compute what the local time is. DST rules change from time to time, and both the operating system and the JDK need to be updated when this occurs.
Can you add the output of the following to your question:
# unix
date --rfc-2822; date +%s
# Java
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
The should both output something like:
Wed, 16 Sep 2009 17:26:08 +1000
1253085968