The following is driving me crazy, why am I getting the wrong calendar date when converting Unix Time 1386230874 using the code below!!
This should be Thu Dec 5 19:07:54 2013
Output:
Comment posted on:Sat Jan 17 11:03:50 EST 1970
Code:
Calendar facebook_created_time_calendar = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney"));
facebook_created_time_calendar.setTimeInMillis(1386230874);
out.print("Comment posted on:");
out.println(facebook_created_time_calendar.getTime());
Java works with millisecond timestamps, while Unix time stamps are typically measured in seconds. Multiply the Unix timestamp by 1000L to get the right time.
Unix measures time as the number of seconds ("1386230" seconds [you went seconds to milliseconds with setTimeInMillis] is "16.04433" days) and since epoch (January 1, 1970 + 16.04 days is Jan 17 it is working) - so try this
facebook_created_time_calendar
.setTimeInMillis(1386230874L * 1000);
Related
Edit: It turns out the problem is not about Jackson, but about time adjustment in Thailand on 1 April 1920.
How does com.fasterxml.jackson.databind.ObjectMapper works? I thought it used Unix timestamp.
I tried converting a java.util.Date with mapper.writeValueAsString().
When I convert the string back to Date with mapper.readerFor(Date.class).readValue(), the result is correct.
However, when I trying removing the last 3 digits and and put the same string into some converter websites, the result is off for some minutes and seconds.
Please see the code below.
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
System.out.println(wayBack); // Wed Jan 31 00:00:00 ICT 1900
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(wayBack)); // -2206420924000
Date deserialised = mapper.readerFor(Date.class).readValue(mapper.writeValueAsString(wayBack));
System.out.println(deserialised); // Wed Jan 31 00:00:00 ICT 1900
Below is a screenshot from http://www.onlineconversion.com/unix_time.htm
Please note that 7-hour off is expected because of my timezone but I don't understand the 17:56 minutes different.
EDIT - Here is my attempt to provide a better answer than my first one.
Background
Before looking at the code in the question, some background notes:
The epoch value (in seconds) at midnight 31st Jan 1900 in Bangkok is -2206420924:
LocalDateTime localDateTime = LocalDateTime.parse("1900-01-31T00:00:00");
ZoneId z = ZoneId.of("Asia/Bangkok");
ZonedDateTime ict_1 = ZonedDateTime.of(localDateTime, z);
System.out.println("Epoch seconds: " + ict_1.toEpochSecond());
System.out.println("ICT datetime : " + ict_1);
The above prints this:
Epoch seconds: -2206420924
ICT datetime : 1900-01-31T00:00+06:42:04[Asia/Bangkok]
The epoch value (in seconds) for UTC midnight on the same date is -1570060800:
ZonedDateTime utcDateTime = ZonedDateTime.parse("1900-01-31T00:00:00Z");
System.out.println("Epoch seconds: " + utcDateTime.toEpochSecond());
System.out.println("UTC datetime : " + utcDateTime);
The above prints this:
Epoch seconds: -2206396800
UTC datetime : 1900-01-31T00:00Z
The time at midnight in Bangkok on 31st January 1900 was 24,124 seconds further into the past than the time at midnight in Greenwich, UK (the prime meridian - or UTC).
That is to say, on that date Bangkok was 6 hours, 42 minutes and 4 seconds ahead of UTC time (or GMT as I believe it was then called - as UTC had not been established at that time).
The Specific Code in the Question
First, I changed my default time zone to match the one used in the question:
System.setProperty("user.timezone", "Asia/Bangkok");
The below line from the question does the following:
(1) The SimpleDateFormat constructor, in which the date format string does not specify a locale, uses the default locale.
(2) Then the parse() method creates the Date object:
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
At this point we can check the date object:
System.out.println(wayBack);
System.out.println(wayBack.getTime());
This prints the following:
Wed Jan 31 00:00:00 ICT 1900
-2206420924000 // epoch milliseconds
This matches what we saw earlier, in the background section.
When you use an online tool such as the one mentioned in the question, you will see the above milliseconds value reported as the following GMT (UTC) datetime:
GMT: Tuesday, January 30, 1900 5:17:56 PM
For the above output I used this tool.
Again, this is what we expect - when it's midnight in Bangkok, it's still the afternoon of the day before in Greenwich, UK.
The remainder of the code (including the Jackson object mapper transformations) are all subject to this initial set-up of your Date object.
For the question: "How does com.fasterxml.jackson.databind.ObjectMapper works? I thought it used Unix timestamp." It shows the same behavior as the core Java date object. I believe your assumption is correct.
Regarding the Unusual Offset
Regarding the ICT offset of +06:42:04 shown above:
On April 1st 1920, an adjustment was made to the local ICT (Indochina Time), to align it with UTC time (with an offset of +7 hours, as you note). The local clocks were set forward by 17 minutes and 56 seconds, to round up the UTC (GMT) offset to 7 hours.
See this link for a specific reference to the 17 minutes & 56 seconds change.
This is why you will not see that unusual offset from April 1920 onwards.
Further Links
See this answer regarding the newer java.time classes which should be used instead of java.util.Date.
See this question and its answers for a related deep-dive into the topic of historic time zone adjustments.
The java.util.Date class is based on the number of seconds since 1 January 1970 00:00 GMT. So why does this code
System.out.println(new Date(0));
print Thu Jan 01 01:00:00 GMT 1970? My local time zone is GMT, so I expected it to print 00:00:00 GMT.
There is an interesting reason for this. Refer (BST Offset bug report)
.
It says, "and the experiment with British Standard Time from 1968 to 1972, by which the time was advanced by one hour from GMT throughout the year." And further: “The local time produced by Date.toString() is historically correct, except for the time zone abbreviation. It should be "BST" (British Standard Time for this case), but it's a known limitation of the current TimeZone implementation.”
This link might help. I'm quite a novice at the Date class, but I figured this could help somehow.
Unix Epoch Time is a system of time describing how much time has elapsed since January 1st, 1970.
Therefore, when you create a new java.util.Date object with 0 milliseconds elapsed, it will return January 1st, 1970.
What you are looking for is here.
I have a very simple Java program as follows:
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.println(new Date(cal.getTimeInMillis()));
System.out.println(cal.get(Calendar.ZONE_OFFSET));
cal.set(Calendar.ZONE_OFFSET, 0);
System.out.println(new Date(cal.getTimeInMillis()));
}
My home timezone is GMT. For the purpose of my experiment I set the computer's timezone to EDT and observed the system clock has moved back 5 hours.
When I run the program, I get this output:
Sat Apr 25 10:09:23 EDT 2015
-18000000
Sat Apr 25 05:09:23 EDT 2015
The Sat Apr 25 10:09:23 EDT 2015 indicates the system time and timezone, as expected.
The -18000000 indicates the zone offset in ms, which is negative 5 hours as expected.
When I set the zone offset to 0, I would expect the time to read my real local time of 15:09 but instead it reads 05:09, in other words, it has taken off another 5 hours instead of adding them.
Why? I'm confused!
I think what you have done is set a calendar with the current time in the current timezone (-5 hours) (10:09) you then got the time in Milliseconds which returns the milliseconds time as if you are in GMT. Ie It adds 5 hours (15:09)
System.out.println(New Date(milliseconds)) interprets that time in the current timezone (-5 hours)(10:09)
You then change the zone offset to zero but keep the day and time numbers unchanged. (10:09) You then take time in Milliseconds again which again is as if it is GMT (it adds nothing) (10:09)
System.out.println(New Date(time in millis)) interprets that time in the current timezone (-5 hours) (05:09)
The key information here is that a Date is always GMT internally and the timezone is only applied when you format it or call toString() which is done by the println (...) method.
calendar.getTimeInMillis () always returns the number of milliseconds since the start of 01/01/1970 UTC (the computer epoch)
Java takes your computer's timezone which is EDT. When you set the Calendar.ZONE_OFFSET to '0' then it will give you the current EDT time. If you need to get your current time you need to set the Calendar.ZONE_OFFSET related to EDT which is 5 hours (+18000000ms).
[UPDATE]
Time zone offset set to '0' means declaring I am at GMT and system time is GMT.
But you need to keep in mind that still you are in your original location which is -18000000.
When you calculate you take the correct location which is -1800000 and then adjust 5 hours early time.
Let me explain what you did using an example.
Think you can go to any location of the world in no time.
You set your time at New York (EST) to 10:00.
Now you go to Greenwich (GMT) and you are saying that my time is 10:00. (setting the time zone offset to '0')
Then you come to New York (EST) and print your time thinking that 10:00 is the time at Greenwich (GMT) which is 05:00.
Date now = new Date();
long timeInterval = now.getTime() - (15705 * 24 * 60 * 60 * 1000L);
long hours = timeInterval / (60 * 60 * 1000L);
LOG.debug(String.format("current date:%s, timeInterval:%d,hours:%d",now.toString(),timeInterval, hours));
The result that system print is(15705 means the number of days since 1970s):
12/12/31 22:06:47 DEBUG stat.TimeTest: current date:Mon Dec 31
22:06:47 CST 2012, timeInterval:50807153, hours:14
You can see the current hour is 21 hours, but the result displays as 14 hours.
Mon Dec 31 22:06:47 CST 2012 is Mon Dec 31 14:06:47 2012 in GMT time, which is the time zone used for the start of the epoch.
In other words, now.getTime() returns the number of milliseconds since January 1, 1970, 00:00:00 GMT and you use a different time zone.
now.getTime() would get you the value in UTC millis - thats GMT+0.
the log print you showed probably uses the system time zone, where it was 22:06:47 and probably wasnt anywhere near england :-)
also, please use the Calendar class for date arithmatic because it, unlike your code, would take into account things like leap years, leap seconds and timezone changes (wehich dont happen in UTC, might mihg thappen in any other zone)
I want to perform a date operation in my android app. What I want is to subtract two dates and get the result. But subtraction leads to the wrong result whenever I change the time zone to central daylight time.
I use the following code to find the difference between the two dates.
Long lDateDiff = dtCycleDay.getTime() - m_dtHistory[0].getTime();
lDateDiff = lDateDiff / (1000 * 60 * 60 * 24);
Here in m_dtHistory[0], the date stored is Thu Mar 01 00:00:00 CST 2012.
And in my dtCycleDay variable the date changes from Thu Mar 01 00:00:00 CST 2012, Thu Mar 02 00:00:00 CST 2012, Thu Mar 03 00:00:00 CST 2012... and so on.
Now up to Thu Mar 11 00:00:00 CST 2012, the subtraction result is fine, but when the date changes to Thu Mar 12 00:00:00 CDT 2012, the CST changes to CDT and it show wrong subtraction result.
Why this happens and these happen only when I change the time zone to Central Daylight Time or pacific Daylight Time.
What do you mean by the "wrong" subtraction result?
My guess is that the result is 23 hours or 25 hours- which is exactly what I'd expect when a daylight transition occurs, as the intervening day is longer or shorter in terms of elapsed time. The "longer" day won't be relevant when dividing by 24, but the shorter one will... you're assuming that every day has 24 hours, and that you can therefore count the number of days by dividing the elapsed milliseconds by "the number of milliseconds in 24 hours". That doesn't work due to varying day lengths.
Don't forget that a Date value is purely an instant in time. It doesn't know about calendars or time zones... if you want to know the difference in "local" dates and times (where midnight to midnight is always 24 hours), I'd suggest using Joda Time instead... Date and Calendar don't really do that for you.
If the real problem you're describing is the time zone changing at the wrong date, that's a different matter entirely, and could be due to various different causes. For one thing, you should show exactly which time zone you're talking about: the abbreviations are ambiguous, whereas the tzdb names (e.g. "Europe/Paris") aren't.