wow! Thanks for taking the time to explain! Rails' behavior is pretty close to what you describe, but poorly documented.

To make the system behave this way, you basically need to perform no
time zone skew if there's no time component to a date/time value.
Instead, you simply append the application or client time zone
information, and any implicit time range (e.g. 00:00:00--24:00:00). I've
no idea if that's what Rails does, but it's what it should do. :-)
Rails doesn't quite do this. It simply has no timezone support whatsoever for Date objects and Date fields in the database. If you enter "2008-09-09" into a field on the site, it will get parsed into a Date representing September 9th, 2008. When saved to the database, it will be 2008-09-09 regardless of any timezones set for Rails or the user. When it is pulled out of the database, it will still be "2008-09-09" regardless of timezones.


My last remaining question is rails related. How does rails handle the
following query

find(:all, :conditions => ['show_from <= ?', Time.now.utc ]).collect { |t|
t.activate! }

I know that Todo.show_from is mapped to the correct timezone, but I could
not find / google if the show_from in the :conditions is mapped to the
correct timezone.

It does, in fact, just drop that value into the SQL query. But let's say I'm in UTC-8 and I want to show todo X on 2008-09-09. If I hit the Tickler at, say, 10PM Eastern on the 9th, Time.now.utc will be 2008-09-10, so any events with a show_from of 2008-09-10 will leave the Tickler, even though it isn't tomorrow yet in my local timezone. Thus we need to compare against the current date in the user's local timezone.

On Sep 8, 2008, at 12:14 PM, mathew wrote:

Reinier Balt wrote:

I agree that Todo.show_from is a Date converted to the user’s timezone
(*). But does the time_zone in the :condition clause refer to the
database field (in UTC (**) ) or does it refer to Todo.show_from (in
the users time_zone)?

I always thought activerecord just appends the :condition clause to
the SQL query and thus refers to the database field and not the
getter/setter of the object. Or am I wrong?

Furthermore, you say “Basically, Times/Datetimes in the database are
in UTC, but Dates are not”. I assume you mean UTC only when
config.active_record.default_timezone is UTC?


In general, there's only one way to do this correctly.

[Let me start out by explaining my background: I've been building
date/time and calendar code for most of my career, starting in 1990. I
currently maintain multi-country enterprise calendar systems at a very
big corporation, and have recently been doing a lot of systems
integration of calendars using web services and Java.]

Every time&date stored in the database must be stored in UTC, because
not all SQL databases support time zones. While PostgreSQL will store a
timestamp with time zone, MySQL and DB2 will not. So the code needs to
work for the lowest common denominator.

You might ask why not simply store database date/time values in local
time zone. There are at least three good reasons why not...

Firstly, the local time zone's definition may change, as is often the
case with DST transitions.

Secondly, the system may have users from multiple time zones, and when
two or more time zones change you can get massive confusion.

Thirdly, it means your time/date values are not unique. BSD syslog has
this problem. For example, the timestamp instant 2007-10-30 01:55:47
actually occurred twice, because of DST changeover. I've got a long post
talking about this issue at
<URL:http://meta.ath0.com/2005/05/25/syslog-is-broken-will-someone-please-fix-it/ >

So, in general the only safe thing to do is store date/time values in a
single non-varying time zone which has a 1:1 mapping from date/time
value to an instant in physical time. UTC is the obvious choice to meet
those criteria. That means that the web application needs to translate
all date/time values from UTC when loading them from the database, and
back to UTC when storing them.

Since there's no standard way to query a web client for the user's time zone, generally there will be an application default time zone which the application converts dates and times to for display and modification. I
assume that's what the new Rails feature is. I'm guessing Rails
automagically converts to UTC when persisting, and converts back when
loading data.

[To add an extra layer of complexity, for a multi-user application (like
Tracks can be), you'll of course want to have a preference for each
user's time zone, and convert date/time values to and from that instead
of the server's/app's default time zone.]

Now, there are a couple of problems with this approach, which become
apparent when someone changes time zone--either because of a DST
changeover, or because they've traveled to a place with a different time zone, or perhaps because the time zone has been redefined by legislature.

The first problem is what a date with no time zone means. The answer is
that in general, people expect "2008-09-08" to behave as
"2008-09-08T00:00:00--2008-09-08T24:00:00" *in whatever time zone they
happen to be in at the time*.

That is, if I set a date of 2008-09-08 for something when I'm in Texas, and then I fly to Germany, I expect the thing to happen on 2008-09-08 in Germany, even though I had no idea I would be in Germany when I set the date. And when I looked at the calendar in January, I wanted to see the thing appear on a single day, as if it was scheduled in the time zone I
was in in January.

To make the system behave this way, you basically need to perform no
time zone skew if there's no time component to a date/time value.
Instead, you simply append the application or client time zone
information, and any implicit time range (e.g. 00:00:00--24:00:00). I've
no idea if that's what Rails does, but it's what it should do. :-)

The second problem is probably not going to affect tracks, but it's the problem of how you deal with events that are scheduled for a particular time range specified in local time, if the user switches time zone after
scheduling the event. The answer in this case is that *there is no
correct answer*.

Example 1: I have a weekly telephone conference call at 10:00 on
Tuesday. I happen to be working in Germany for a week. Clearly my
calendar appointment needs to appear at 17:00 local time while I'm in
Germany.

Example 2: While I'm in Germany, I'm going to be meeting with colleagues
at 10:00 on Wednesday. Clearly my calendar appointment needs to appear
at 10:00 local time while I'm in Germany.

So the only way to deal with this latter problem in general, is for each
calendar event to have either a controlling time zone associated with
it, or "Local" to indicate that it should float to whatever the user's
local time zone is at any given moment (like with an untimed date, as
per previous discussion). Unfortunately, there are a lot of calendar
systems that don't provide this feature; e.g. Palm organizers and
smartphones. And unfortunately, there's no standard way to store such
information in a relational database; I had to do a lot of code
refactoring recently when switching from PostgreSQL to IBM DB2.

I hit this problem because one system I maintain is used to schedule
events at corporate locations. When an event at a physical location is
scheduled for 10:00 on August 9th, what is actually meant is "10:00 in
the local time for that location on August 9th, whatever that time zone happens to be, even if the government redefines DST earlier in the year
to be something you didn't expect". :-)

Anyway, rather a long e-mail, but hopefully it'll help clarify the issues.


mathew
_______________________________________________
Tracks-discuss mailing list
[email protected]
http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss

_______________________________________________
Tracks-discuss mailing list
[email protected]
http://lists.rousette.org.uk/mailman/listinfo/tracks-discuss

Reply via email to