My site and server are in the US/Eastern timezone. I created a view with a filter for field_date >= now. The query ends up containing the WHERE clause
(FROM_UNIXTIME(node_data_field_date.field_date_value) + INTERVAL -18000 SECOND>=NOW())
The field_date_value contains the correct timestamp in GMT. The INTERVAL statement converts that value into US/Eastern. However, according to the MySQL documentation, "beginning with MySQL 4.1.3, the CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP(), FROM_UNIXTIME(), LOCALTIME, LOCALTIMESTAMP, NOW, SYSDATE, and UNIX_TIMESTAMP() functions return values in the connection's current time zone." Therefore, the results of FROM_UNIXTIME and NOW are *already* converted to US/Eastern (or whatever timezone I set), and the INTERVAL statement offsets the field_date_value a second time, resulting in an incorrect comparison.
It seems to me that since FROM_UNIXTIME parses a time in GMT into the local timezone and NOW returns a time in the local timezone, either both or neither needs to be converted, and it would be faster to convert neither. Am I missing something?
Commenting out date.inc(1.9.2.22):2097 makes this particular case work correctly. I haven't studied the code closely enough to propose a real fix. Time-handling code is always such a pain in the butt! Kudos on the great job you've done.
Comments
Comment #1
karens commentedI wasn't aware of the change in FROM_UNIXTIME. That's a critical issue since the goal throughout the Date module is to use php and sql functions that will not do any timezone conversion so that the correct timezone conversion can be controlled based on the choices made when setting up the field. The automatic timezone conversions are way too unreliable (i.e. even if your choice is to use the site timezone, a sql conversion will convert to the timezone of the sql server but your site timezone might be something different)
This will take some thought, especially since behavior is not constant across different versions of the same OS. I need to find a method that does no timezone conversion on its own.
Comment #2
karens commentedA fix was just committed to all branches. I am going to try the method used by Views to force the mysql server to use GMT. I don't have an installation with the right mysql version to test this but it looks like it should work. If not, please re-open the issue.
Comment #3
bjaspan commentedI went down this path too but I think it isn't right.
FROM_UNIXTIME() and NOW() both produce output in the "current" timezone. You've now changed the code so the current timezone is GMT instead of (in my case) US/Eastern. In this situation, if field_date_value is a Unix timestamp (always in GMT) and the session timezone is GMT, then FROM_UNIXTIME(field_date_value) is in GMT. Similarly, NOW() is in GMT if the session timezone is in GMT. So the two values are comparable. But if the "current" timezone where still US/Eastern, the values would also be comparable because FROM_UNIXTIME() and NOW() would both return results in US/Eastern (FROM_UNXTIME() would convert its GMT timestamp input into US/Eastern).
However, date_sql is still producing FROM_UNIXTIME(field_date_value) + INTERVAL tz_offset SECONDS >= NOW(). This means that the result of FROM_UNIXTIME is being manually converted into the local timezone but the result of NOW() is not, so the values are not correctly comparable.
The bottom line is that you cannot apply an offset to FROM_UNIXTIME() and not to NOW(), so you might as well not apply an offset to either. Alternatively, replace FROM_UNIXTIME() with a function that does not convert its output into the current timezone; I saw that there are UTC_* functions that work that way though I don't know if there is one that takes a Unix timestamp.
Comment #4
karens commentedYou're right that it wasn't the right fix. My intention is to find a way to remove any timezone adjustment the server might make to any value, then manually adjust by the correct offset value, so here's what I'm now thinking of using (still doing some testing on it). I added a function that will try to determine the amount of adjustment the server is making by default so I can adjust it out when necessary. Also, it looks to me like all versions of MYSQL (and I believe postgres) are automatically adjusting NOW() and TIMESTAMP() values by the server timezone, so I think all of them need to be adjusted back before applying the correct offset.
Comment #5
karens commentedI've done some more checking and fixing and have committed something similar to the code above. It should at least be no worse than the current code and hopefully is now correctly adjusting timezone values.
Comment #6
(not verified) commented