Unexpected output with ISO Time (8601) - java

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)

Related

Why is this converted Jackson time different to expected Unix time?

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.

Round date long value

In my Java project I used date in long and for example it is 12136219 and by creating Date object as below:
long time = 12136219;
Date date = new Date(time);
and it represent date as Thu Jan 01 04:22:16 CET 1970. How can I round date (in long representation) to minutes ?
For example I want achieve Thu Jan 01 04:22:00 CET 1970 if the seconds are <30 and Thu Jan 01 04:23:00 CET 1970 if the seconds are >=30 but I want round this long time = 12136219 representation. Any idea?
Don’t reinvent the wheel. Use java.time.Instant for representing an instant in time:
Instant i = Instant.ofEpochMilli(time);
i = i.plusSeconds(30).truncatedTo(ChronoUnit.MINUTES);
Instant doesn’t offer rounding, only truncation. However, adding 30 seconds and then truncating gives you what you want. If you need your milliseconds back, it’s easy:
time = i.toEpochMilli();
System.out.println(time);
With the number from your question this prints
12120000
(This is equal to an instant of 1970-01-01T03:22:00Z, or 1970-01-01T04:22+01:00[Europe/Paris] in CET, or the expected rounding down of your 04:22:16 CET.)
PS I am quite convinced that a library like Time4J will offer rounding so you don’t need the trick of adding and truncating. Unfortunately I don’t have the experience to give you the details.
Since time is
"milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT"
You could calculate the seconds like this:
secondsInMillis = time % (60 * 1000) //get remainder (modulo): seconds * milliseconds
if (secondsInMillis < 30000) {
time -= secondsInMillis; //round down
} else {
time += (60000 - secondsInMillis); // round up
}
When you create a Date from a long, the long represents the number of milliseconds since Jan 1, 1970. There are 60*1000 milliseconds in a minute. That should be enough information to fashion the rounding algorithm you need.
Reset seconds and milliseconds with Calendar.set
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.MINUTES, calendar.get(Calendar.SECOND) >= 30 ? 1 : 0)
currentDate = cal.getTimeInMillis();
Sets the given calendar field to the given value. The value is not interpreted by this method regardless of the leniency mode.
You should do it on the Date object. There is no easy way to calculate it in the time epoch, because of various difficulties including the length of a month (28, 29, 30 or 31).

Conversion from Unix Time to Java Calendar

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);

Date Time Clarification

Currently I have a AIX SERVER and if I issue the command date on the terminal, I get the response as Mon Nov 4 00:28:40 EST 2013.
And I have the seconds value 1383561560 which is the number of seconds since Wednesday, 31 December 1969, 19:00:00 (UTC time).
Now I have a code which computes the date and time since 31 December 1969, 19:00:00 (UTC time) to EST time.
DateFormat df = new SimpleDateFormat("MM/dd/yyyy_HH:mm:ss a");
df.setTimeZone(TimeZone.getTimeZone("EST"));
long ms = (long)(1383560920) *1000;
Date d1 = new Date(ms);
String formattedDate = df.format(d1);
System.out.println("Now the date/time is "+formattedDate );
Now the date/time displayed is 11/04/2013_05:28:40 AM
Here why is there a 5 hour difference?
Java Date base time start from 1 January 1970, 00:00:00 but your time is 31 December 1969, 19:00:00. So the difference of calculated time will be 5 hour.
For details, read this docs.
Allocates a Date object and initializes it to represent the specified
number of milliseconds since the standard base time known as "the
epoch", namely January 1, 1970, 00:00:00 GMT.
Parameters: date - the milliseconds since January 1, 1970, 00:00:00 GMT.

wrong result in date difference in android

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.

Categories

Resources