I know there are a few dozen similar questions out there, not to mention countless articles on the Interwebs in general, but I'm still having a hard time understanding how Rails works with Time Zones internally.
I currently have config.time_zone = 'Eastern Time (US & Canada)'
configured in my application file because that's where I and the other project administrators are. The company that owns the site is based in CA, so they will be in Pacific time. The application has a global audience and while we haven't done so yet we will eventually be implementing user preferred time zones.
So my current questions:
I know Rails magically transforms datetime column values to and from UTC when stored and retrieved respectively, but what is the proper way to view the local version of a given datetime attribute?
When would one use Time.now
versus Time.zone.now
versus Time.now.in_time_zone
versus DateTime.now
versus DateTime.now.in_time_zone
?
What is the proper way to compare a given datetime attribute with the methods listed above or some other specific time relative to the currently configured time zone? With UTC?
We will have some time-sensitive things like articles that need to be published at a specific time according to the application's time zone, so how do I make the application do that comparison in our specified timezone as opposed to the currently configured one (assuming a user timezones are implemented?)
(New Question) What happens if I change config.time_zone
to UTC
at a later date? Do I have to reset all of my times in the database or does it otherwise affect old times?
First off, its important to understand that rails' timezone stuff is largely about presentation. Behind the scenes, everything happens in UTC.
Q1. At the console Rails will display times in you default timezone, so Something.last.created_at
displays that timestamp in the zone given by Time.zone
Q2. All of these return an object that represents 'now'. The choice of DateTime versus Time is not related to timezones. If you need to be able to represent times outside of the unix epoch for example, use DateTime. The difference between Time.now
and Time.zone.now
is whether you get back an instance of Time (which will be in the server's local timezone as controller by). This controls for example what to_s
returns but not what instant in time is represented:
SomeModel.create(:time_attribute => Time.now)
SomeModel.create(:time_attribute => Time.zone.now)
will insert the same row into the database. If you're just displaying a time to the user (for example if you're site displays the current time in the header) then you should use Time.zone.now
so that it is displayed in the correct timezone. If you're just storing it in the db then it doesn't really matter - activerecord converts it to a TimeWithZone anyway.
Q3. The comparison methods on the TimeWithZone
are implemented by comparing the utc version of the date, so you can safely compare times that are in different zones - you don't need to convert them to some common time zone. You can also compare TimeWithZone instances with plain time objects.
Q4. You normally don't need to do anything. A common way of implementing this would be to have a published_at
attribute on your model. Pages displaying the list articles would add a
where('published_at <= ?', Time.now)
condition to the query. When you create your article, Rails takes the date time from the form and converts it to utc, so what is stored in the database is the utc version of that published_at
time. Comparisons are time zone independant, so the query just works no matter what the time zone is.
This can get complicated with pure time of day stuff (eg '4pm') because a time zone conversion can only be done properly when you know the date too (i.e. you know the precise instant in time), as depending on DST (or political events like countries changing their timezone) the offset from UTC changes. In this sort of situation you normally want to store just the time of day and only convert it into a full time as late as possible, when you know the date too.
Q5. Rails always stores UTC in the database. A direct consequence of this is that changing config.time_zone
doesn't require you to change the data stored in the database. You can even set Time.zone
on a per user basis so that users see times in their timezone - config.time_zone
just controls the default value of Time.zone
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With