Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does java.sql.Date work with negative dates?

I had a situation where the Java runtime returned sort of "inverted" millisecond values when reading dates from the database (in java.sql.Date). The millisecond value was approximately the same amount of days, but counted backwards from year 0.

The problem was solved by just restarting the Java runtime.

But: I found out that Java handles these "inverted" values almost correctly except of the week day.

When you run the following code:

System.out.println(new java.util.Date(253402214400000l));
System.out.println(new java.util.Date(-377648784000000l));

You will get the following output:

Fri Dec 31 01:00:00 CET 9999
Tue Dec 31 01:00:00 CET 9999

Another example:

System.out.println(new java.util.Date(-294192000000l));
System.out.println(new java.util.Date(-123967324800000l));

Result:

Mon Sep 05 01:00:00 CET 1960
Mon Sep 05 01:00:00 CET 1960

When using online converters, the result will be different for the particular second line. It will result in a negative date (the year is negative) close to the real, positive date:

Example1:
253402214400000 = Fri Dec 31 9999 01:00:00
-377648784000000 = Tue Oct 15 -9998 02:00:00

Example 2:
-294192000000 = Mon Sep 05 1960 02:00:00
-123967324800000 = Mon Aug 19 -1959 02:00:00

I have not found any information about this "topic".

So, what's the myth behind "inverted" dates? Why does Java handle them almost correctly? And what is the sense of a JDBC ResultSet returning "inverted" millisecond values when calling resultSet.getDate(1).getTime()?

like image 902
praisezh Avatar asked Feb 03 '16 13:02

praisezh


2 Answers

When you are passing a negative number in the Date constructor then it is considered as number of milleseconds before 1/1/1970. The Javadoc says:

date - milliseconds since January 1, 1970, 00:00:00 GMT not to exceed the milliseconds representation for the year 8099. A negative number indicates the number of milliseconds before January 1, 1970,

You can see the result which you get when you try to provide the Long.MIN_VALUE and Long.MAX_VALUE in the Date constructor.

DateFormat df = new SimpleDateFormat("d MMM yyyy G, HH:mm:ss.S Z");
System.out.println(df.format(new Date(Long.MIN_VALUE)));
System.out.println(df.format(new Date(Long.MAX_VALUE)));

Ideone Demo

like image 159
Rahul Tripathi Avatar answered Oct 25 '22 14:10

Rahul Tripathi


I found out that Java handles these "inverted" values almost correctly except of the week day.

In your first example, the two dates are not the same - one is BC and the other one AD (which explains why the day of the week is different):

Date d1 = new Date(253402214400000l);
Date d2 = new Date(-377648784000000l);
DateFormat fmt = new SimpleDateFormat("yyyy G");
System.out.println(fmt.format(d1)); //9999 AD
System.out.println(fmt.format(d2)); //9999 BC

So your observation is just a coincidence (however there may be a date formatter somewhere that has gone wild and negates the years or the years may actually be negative in your database).

The difference with online converters is probably due to how the year 0 is taken into account and/or variations in the calendar used for the calculations.

like image 42
assylias Avatar answered Oct 25 '22 15:10

assylias