Discrepancy in Converting Date to TimeStamp in java - java

I have a Date Object in following:
Date date=new Date("Mon, 05 May 2014 12:31:12 +0000")
I want to get Timestamp of date Object then :
date.getTime()
1399293072000
but this value not correct , correct value in following :
1399276872000
//*** for get timestamp use of http://www.epochconverter.com ***\\
why ?

First things first, from the JavaDoc for Date
Date(String s)
Deprecated.
As of JDK version 1.1, replaced by DateFormat.parse(String s).
So the constructor you are using has been deprecated since 1997!
Next, onto the JavaDoc for Date.parse which the construtor uses:
It accepts many syntaxes; in particular, it recognizes the IETF
standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
understands the continental U.S. time-zone abbreviations, but for
general use, a time-zone offset should be used: "Sat, 12 Aug 1995
13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
meridian). If no time zone is specified, the local time zone is
assumed. GMT and UTC are considered equivalent.
Empathsis mine.
So, what timezone are you in? Presumably not UTC.

You should specify local time zone while constructing Date object
Example:
Date date=new Date("Mon, 05 May 2014 12:31:12 GMT+0530");

Using Mon, 05 May 2014 12:31:12 +0000 at http://www.epochconverter.com I get 1399285872000 which is different from your timestamp.
Or you're passing different values, or there's a bug somewhere or
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
where the javadoc for java.util.Date.getTime() doesn't mention leap seconds.

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.

Java Date start epoch

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.

LocalDate inconsistency

I am trying to produce a Date object (java.util.Date) from a LocalDate object (java.time.LocalDate) in which I have the following criteria:
Allow a parameter that can subtract a certain number of days from the Date object
Have the Date & Time be the date and time currently in UTC
Have the time at the beginning of the day i.e. 00:00:00
The Timezone stamp (i.e. CDT or UTC) is irrelevant as I remove that from the String
To meet this criteria, I have created a test program, however I am getting interesting results when I modify a certain property of the LocalDate. See code below:
public static void main (String args[]) {
Long processingDaysInPast = 0L;
LocalDate createdDate1 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
LocalDate createdDate2 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
System.out.println(createdDate1);
System.out.println(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC));
System.out.println(Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)));
System.out.println((createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
System.out.println(Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}
Output:
2017-08-14
2017-08-14T00:00:00Z
Sun Aug 13 19:00:00 CDT 2017
2017-08-14
2017-08-14T05:00:00Z
Mon Aug 14 00:00:00 CDT 2017
When I add the value Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)) I get the expected output of the date, with a 00:00:00 time field. However, if I do not add this parameter, such as: Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()) I get the resulting day before , at 19:00:00 why is this?
My main goal from this is to be able to capture a Date object, with the current UTC Date, and the Time zeroed out (StartOfDay).
When you do:
createdDate2.atStartOfDay().atZone(ZoneId.systemDefault())
First, createdDate2.atStartOfDay() returns a LocalDateTime, which will be equivalent to 2017-08-14 at midnight. A LocalDateTime is not timezone-aware.
When you call atZone(ZoneId.systemDefault()), it creates a ZonedDateTime with the respective date (2017-08-14) and time (midnight) in the system's default timezone (ZoneId.systemDefault()). And in your case, the default timezone is not UTC (it's "CDT", so it's getting midnight at CDT - just do System.out.println(ZoneId.systemDefault()) to check what your default timezone is).
To get the date at midnight in UTC, you can replace the default zone (ZoneId.systemDefault()) with UTC (ZoneOffset.UTC):
Date.from(createdDate2.atStartOfDay().atZone(ZoneOffset.UTC).toInstant())
Or (a shorter version):
Date.from(createdDate2.atStartOfDay(ZoneOffset.UTC).toInstant())
Of course you can also do the same way you did with createdDate1:
Date.from(createdDate2.atStartOfDay().toInstant(ZoneOffset.UTC))
They're all equivalent and will result in midnight at UTC.
Just a quick note: short timezone names like CDT or PST are not real timezones.
The API uses IANA timezones names (always in the format Region/City, like America/Chicago or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CDT or PST) because they are ambiguous and not standard.
There are lots of different timezones that can use CDT as abbreviation. This happens because a timezone is the set of all different offsets that a region had, has and will have during history. Just because many places uses CDT today, it doesn't mean they all used in the past at the same periods, nor that it'll be used by all in the future. As the history differs, a timezone is created for each region.

Java Date object parsing precision is off on SimpleDateFormat

I have a date as a string 2016-10-07T12:46:23Z and after parsing to Date object using SimpleDateFormat is converted to Fri Oct 07 08:46:22 EDT 2016 which is 1 sec precision off. Debugging that code it came that it was parsed to Fri Oct 07 08:46:22.998 EDT 2016
SimpleDateFormat to parse as looks like
DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
and the code to parse looks like
String dateStr = valuesArray.getString(0);
values[0] = RESTUtils.DATE_FORMAT_ISO8601.parse(dateStr);
Any tips how to get proper seconds value after parsing?
The expression new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")) defines an offset not of zero, but 2 milliseconds, see Javadoc, thus explaining the observed result of "Fri Oct 07 08:46:22.998 EDT 2016".
The constant SimpleTimeZone.UTC is not intended to indicate an offset (as mandated as first argument to SimpleTimeZone-constructor). Its numerical value of "2" is rather a mode to denote how to interprete start or end time parameters for other constructors.
Therefore the correct solution to interprete the trailing "Z" in your input (ISO-8601-notation for zero offset) is:
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));
Alternatively, if you really want to use the class SimpleTimeZone:
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(0, "UTC"));
And if you are on Java-8, you could also do this:
Instant instant = Instant.parse("2016-10-07T12:46:23Z");
System.out.println(instant); // 2016-10-07T12:46:23Z
System.out.println(Date.from(instant)); // Fri Oct 07 14:46:23 CEST 2016
You are seeing the second difference when you add the time zone as UTC using SimpleTimeZone, if you comment that part out you will get the exact seconds.
String str = "2016-10-07T12:46:24Z";
SimpleDateFormat DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
// DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
System.out.println(DATE_FORMAT_ISO8601.parse(str));
SimpleTimeZone is not meant to be used to define the time zone. Per the documentation
SimpleTimeZone is a concrete subclass of TimeZone that represents a
time zone for use with a Gregorian calendar. The class holds an offset
from GMT, called raw offset, and start and end rules for a daylight
saving time schedule. Since it only holds single values for each, it
cannot handle historical changes in the offset from GMT and the
daylight saving schedule, except that the setStartYear method can
specify the year when the daylight saving time schedule starts in
effect.
The correct way to set the timezone is by doing the following
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("UTC"));

joda time to Date inconsistent time zones

I have a load of dates that I'd like to store in a database running on a server using BST:
2015-09-23
2024-05-07
2024-03-13
However they are stored in the DB as:
2015-09-23 01:00:00
2024-05-07 01:00:00
2024-03-13 00:00:00 <-- I need this to be 01:00:00
The values are converted to Date prior to being stored in the DB. I noticed the following when debugging:
TimeZone timeZone = Calendar.getInstance().getTimeZone();
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));
System.out.println(new SimpleDateFormat("zzz").format(new Date()));
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
System.out.println(formatter.parseDateTime("2015-09-23").toDate());
System.out.println(formatter.parseDateTime("2024-05-07").toDate());
System.out.println(formatter.parseDateTime("2024-03-13").toDate());
The first two dates are using BST and the last one is GMT. Is is possible to make them all use the same time zone?
GMT
BST
Wed Sep 23 01:00:00 BST 2015
Tue May 07 01:00:00 BST 2024
Wed Mar 13 00:00:00 GMT 2024
First of all, keep in mind that java.util.Date doesn't have a timezone (more details about it can be read here).
What happens is that Date.toString() method uses the system's default timezone to print its value (check the value of TimeZone.getDefault() in your JVM, it'll probably be Europe/London).
And in Europe/London timezone, the offset is equals to UTC in the winter (which is printed as GMT) and is +01:00 in the summer (which is printed as BST, aka British Summer Time). These different 3-letter names denotes the offset change, but it doesn't mean the dates "changed" their timezone.
Also consider that timezone is not only the offset or the name, but the set of all offset changes that occur in a region during history (when the changes occur, and the offsets before and after each change).
So, the dates doesn't have different timezones, because:
In the same timezone there can be more than 1 offset. And some changes in the offset cause the change in the 3-letter name - although the use of these 3-letter names is widely used, they're ambiguous and not standard.
java.util.Date doesn't have a timezone, so it can't change it.
If you want to save these objects in a DB, what you should care about is the timestamp (the number of milliseconds from 1970-01-01T00:00:00Z), which is preserved when converting to Date.
If you check the timestamp millis in the objects created, you'll see that it wasn't changed:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
DateTime d1 = formatter.parseDateTime("2015-09-23");
DateTime d2 = formatter.parseDateTime("2024-05-07");
DateTime d3 = formatter.parseDateTime("2024-03-13");
// comparing timestamp millis between DateTime and java.util.Date
System.out.println(d1.getMillis() == d1.toDate().getTime());
System.out.println(d2.getMillis() == d2.toDate().getTime());
System.out.println(d3.getMillis() == d3.toDate().getTime());
All 3 cases above prints true, meaning that they represent the same instant in time (so the dates hasn't changed).
Actually, you can see that all DateTime objects were in UTC:
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
This prints:
2015-09-23T00:00:00.000Z
2024-05-07T00:00:00.000Z
2024-03-13T00:00:00.000Z
Conclusion:
you can save the Date objects without any problem, as their values are correct
if you want to display the dates to the user, you can use the DateTime objects (and use a DateTimeFormatter if you want a different format), because they don't use the default TimeZone in the toString() method.
Try this:
SimpleTimeZone UTCTimeZone = new SimpleTimeZone(0, "UTC");
TimeZone.setDefault(UTCTimeZone);
All the date object will use UTC as default timezone for you backend code

Categories

Resources