Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do two MySQL dates in 1582 appear to be the same but comparison result is false?

I know that Gregorian calendar started on Oct 15th 1582, and during the transition from Julian calendar, 10 days had been dropped.

When I'm doing this query:

SELECT STR_TO_DATE('1582-10-05', '%Y-%m-%d')

I'm getting this result:

1582-10-15 (the 10 days difference). 

But when I'm trying to match between such dates I'm getting the original date (Oct 5th and not 15th).

For example:

SELECT STR_TO_DATE('1582-10-05', '%Y-%m-%d') = STR_TO_DATE('1582-10-15', '%Y-%m-%d')

I'm getting a false response, although you would have expected to get a true since Oct 5th actually count as Oct 15th, as we saw in the first example.

Anyone can explain what's going on here?

like image 489
Ziv Gabovitch Avatar asked Nov 23 '17 18:11

Ziv Gabovitch


2 Answers

On documentation it is stated that, TO_DAYS and FROM_DAYS functions must be called cautiously because of the transformation you noticed. Additionally, when I inspect the source codes of MySQL, I realized that STR_TO_DATE uses similar methodology with these functions. As I understand, cutover dates are completely unsafe to store or apply operations. Documentation says; "Dates during a cutover are nonexistent.", too.

Also for the inconsistency between different servers I may have an explanation. I have 2 different machines which have MySQL installed in Istanbul, Turkey and Frankfurt, Germany. They have same setup excluding localisation settings. First one shows 1, the other one shows 11 for the date substraction query. It means (in my humble opinion) there is unexplained sections about calendar cutover & localisation on official documentation.

like image 112
Tuğca Eker Avatar answered Oct 19 '22 03:10

Tuğca Eker


Please see the following results:

SELECT STR_TO_DATE('1582-10-05', '%Y-%m-%d');
# Result #1: 1582-10-15

SELECT DATE_FORMAT(STR_TO_DATE('1582-10-05', '%Y-%m-%d'), '%Y-%m-%d');
# Result #2: 1582-10-05

SELECT DATE_FORMAT(STR_TO_DATE('1582-10-15', '%Y-%m-%d'), '%Y-%m-%d');
# Result #3: 1582-10-15

SQL fiddle demo.

These indicate the problem lies in the way the 1582-10-05 date is displayed rather than how it is stored. Result #2 shows that if the DATE_FORMAT function is used instead to explicitly convert the date into the same string format then the input date is displayed. This also explains why the comparison query in the question returns false: Behind the scenes, the two stored dates are different.

As you've discovered, this quirk occurs for all dates between 1582-10-05 and 1582-10-14 inclusive, i.e. the range of dates that don't really exist: The implicit conversion to text for all of these gives a date 10 days after. So if for some reason there is a need to display dates in this range (perhaps questionable), a simple workaround is to always use the DATE_FORMAT function.

like image 2
Steve Chambers Avatar answered Oct 19 '22 04:10

Steve Chambers