SimpleDateFormat appears to give an incorrect result - java

I'm using Java 7 and Clojure 1.4 for this.
I'm writing up some database tests in Clojure for a table that contains Date objects, using OracleDB over JDBC.
I need to compare the date I receive (a Date object) with a String - so presumably I need to convert that string to a Date object. After some googling, I found Java's SimpleDateFormat.
This is what I use (with extra stuff for debugging)
(defn parseDate [date]
(do (debug (str "Parsing date: " date ))
(let [ dateobj (java.text.SimpleDateFormat. "dd-MMM-YY")
parsed (do (. dateobj setLenient false) (. dateobj parse date))]
(debug (str "Result: " parsed)) parsed)))
I throw in some dates, and I get the following output..
Parsing date: 01-jan-12
Result: Mon Jan 02 00:00:00 GMT 2012
Parsing date: 01-jan-13
Result: Mon Dec 31 00:00:00 GMT 2012
Parsing date: 00-jan-12
Result: Mon Jan 02 00:00:00 GMT 2012
Parsing date: 02-jan-13
Result: Mon Dec 31 00:00:00 GMT 2012
That doesn't seem right, at all.
The Date object returned is something like this: #<Date Mon Jan 02 00:00:00 GMT 2012>, which is clearly not equal to what I get back from the database, for example, #<Date 2012-01-01>.
Does anyone have any ideas about this?
NOTE: I get the same result whether I use setLenient or not (and with either true or false).
Answer (Courtesy of Jon Skeet Link to answer)
I was using YY in my format string, where I should have actually used yy (Since Y is the week-year and y is the simple year).

I believe the problem is that you're using YY instead of yy. From the docs of SimpleDateFormat, YY refers to the week-year rather than the year.
Week-years are somewhat odd, and unless you know you want to use it, you probably don't. In particular, mixing week-year with "day of month" and "month" is almost never appropriate. You'd normally use "week-year, week-of-year, day-of-week" together.
To put it another way: the two systems are a bit like RGB and HSV for colours; it's as if you've defined a format of "red, green, hue" which doesn't make a lot of sense :)

Related

Strange result with negative parameter with Date

Consider the following program
Date date1 = new Date(-124304227239000L);
Date date2 = new Date(0);
System.out.println(date1 + " vs. " + date2);
The result (at least with Java 8 on my computer, and with Java 11 on a different computer):
Sun Jan 01 16:59:21 CET 1970 vs. Thu Jan 01 01:00:00 CET 1970
This seems strange because following the documentation (https://docs.oracle.com/javase/8/docs/api/java/util/Date.html#Date-long-) , negative values as parameter for Date indicate dates before 1970. Instead, I get a Sunday instead of Thursday, but still 1970.
Can anybody explain this to me?
The value you've provided is around 1969/1970 BC, depending on whether you do a Gregorian/Julian cutover or not. Date.toString(), aside from all its other problems, doesn't bother to mention the era.
If you use Instant with the same value, it's clearer:
Instant instant = Instant.ofEpochMilli(-124304227239000L);
System.out.println(instant);
Output:
-1970-12-15T15:59:21Z
I'd draw the following conclusions from this:
When using values in the far past, there are lots of considerations to bear in mind, including textual representation and calendar system
Avoid java.util.Date as far as you can

how to convert string date to java.util.Date in java and oracle [duplicate]

I've been searching all over and just can't find a explanation or reason why this is happening but the parse(String) method of DateFormat just isn't parsing my String correctly.
I'm trying to parse a String into the date format that is used for HTTP headers and got as far as getting the String on its own such as:
Thu, 11 Nov 2010 18:34:22 GMT
Which is in the format:
E, d MMM yyyy HH:mm:ss z
But when I use df.parse(dateStr); this is what I get out of it:
Thu Nov 11 18:34:22 GMT 2010
Which is nothing like what I wanted, why is the year now after the GMT? Why is there no comma anymore? And why is the date after the month?
I'm completely confused about this now and can't find a solution but I really need the date to be in that format. Is the comma messing things up? or the colons?
Thanks for your time,
Infinitifizz
P.S.
Forgot to mention this but I've tried dateformat.setLenient(false) and it makes no difference.
P.P.S
I'm trying to do this to compare the dates with date1.before(date2) and after() etc to see if one is newer than the other but I can't do this because the parsing isn't working.
Even though they look the same but just the format is different, they are not the same because after calling getTime() on both of them (When I have provided 2 identical dates) the longs are not the same. As in the date is:
Thu, 11 Nov 2010 19:38:52 GMT for a lastModified() on a File
If I input the String "Thu, 11 Nov 2010 19:38:52 GMT" and then compare their longs once converting the string to a date using parse() and then calling getTime() on that date I get:
lastModified = 1289504332671
fromString = 1289504332000
It is only the last 3 digits that are different, does this have any significance?
Thanks again for your time and sorry I didn't put this bit in first,
Infinitifizz
The result format is the default format of Date#toString() (click link to see the javadoc). You're apparently doing a System.out.println(date). You would like to use SimpleDateFormat#format() instead with another pattern to format it in the desired format. E.g.
String newDateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
Update: You shouldn't care about the format when using Date. You should only care about the format at that point when Date is to be converted (displayed) as String. As to the difference in timestamps, the Date uses millisecond precision for the timestamp while HTTP header uses second precision. You'd like to divide the timestamps by 1000 before comparing.

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()?
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
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.

How to format the output of the date-object (not as string)?

I'm trying to pass a Date-Object to a SOAP-API and need the output of the date-object itself to be yyyy-MM-dd
I'm already converting my string into a date-object like this:
// String __startDatum = "2013-02-05";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date convertedDate = dateFormat.parse(__startDatum);
For now the output of convertedDate will be Tue Feb 05 00:00:00 MEZ 2013.
How could I change the output of convertedDate to be 2013-02-05?
Please keep in mind I still need it to be a date-object not a string!
For now the output of convertedDate will be Tue Feb 05 00:00:00 MEZ 2013.
There's no "output of convertedDate" - it's just a Date variable. The only way to get "Tue Feb 05 00:00:00 MEZ 2013" would be to call toString() on it, either implicitly or explicitly - and you can't change the format used by Date.toString().
It's important to understand that a Date is just a number of milliseconds since the Unix epoch. It doesn't have a time zone; it doesn't have a calendar system; it doesn't have a particular format.
If you want a better API which allows you to create an object which just represents a date (rather than a date/time) you should look at Joda Time which is a far nicer date and time API than the built-in one. It's reasonably large - primarily due to the time zone data, I believe - so you may want to look for a cut down version tailored to Android. It's mostly a pleasure to work with though - at least compared with Date and Calendar.

Parsing a String into Date with DateFormat not parsing correctly

I've been searching all over and just can't find a explanation or reason why this is happening but the parse(String) method of DateFormat just isn't parsing my String correctly.
I'm trying to parse a String into the date format that is used for HTTP headers and got as far as getting the String on its own such as:
Thu, 11 Nov 2010 18:34:22 GMT
Which is in the format:
E, d MMM yyyy HH:mm:ss z
But when I use df.parse(dateStr); this is what I get out of it:
Thu Nov 11 18:34:22 GMT 2010
Which is nothing like what I wanted, why is the year now after the GMT? Why is there no comma anymore? And why is the date after the month?
I'm completely confused about this now and can't find a solution but I really need the date to be in that format. Is the comma messing things up? or the colons?
Thanks for your time,
Infinitifizz
P.S.
Forgot to mention this but I've tried dateformat.setLenient(false) and it makes no difference.
P.P.S
I'm trying to do this to compare the dates with date1.before(date2) and after() etc to see if one is newer than the other but I can't do this because the parsing isn't working.
Even though they look the same but just the format is different, they are not the same because after calling getTime() on both of them (When I have provided 2 identical dates) the longs are not the same. As in the date is:
Thu, 11 Nov 2010 19:38:52 GMT for a lastModified() on a File
If I input the String "Thu, 11 Nov 2010 19:38:52 GMT" and then compare their longs once converting the string to a date using parse() and then calling getTime() on that date I get:
lastModified = 1289504332671
fromString = 1289504332000
It is only the last 3 digits that are different, does this have any significance?
Thanks again for your time and sorry I didn't put this bit in first,
Infinitifizz
The result format is the default format of Date#toString() (click link to see the javadoc). You're apparently doing a System.out.println(date). You would like to use SimpleDateFormat#format() instead with another pattern to format it in the desired format. E.g.
String newDateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
Update: You shouldn't care about the format when using Date. You should only care about the format at that point when Date is to be converted (displayed) as String. As to the difference in timestamps, the Date uses millisecond precision for the timestamp while HTTP header uses second precision. You'd like to divide the timestamps by 1000 before comparing.

Categories