I am working on a Rails application that needs to handle dates and times in users' time zones. We have recently migrated it to Rails 2.1 and added time zone support, but there are numerous situations in which we use Time#utc and then compare against that time. Wouldn't that be the same as comparing against the original Time object?
When is it appropriate to use Time#utc in Rails 2.1? When is it inappropriate?
If you've set:
config.time_zone = 'UTC'
In your environment.rb (it's there by default), then times will automagically get converted into UTC when ActiveRecord stores them.
Then if you set Time.zone (in a before_filter on application.rb is the usual place) to the user's Time Zone, all the times will be automagically converted into the user's timezone from the utc storage.
Just be careful with Time.now.
Also see:
http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/
http://errtheblog.com/posts/49-a-zoned-defense - you can use the JS here to detect zones
Hope that helps.
If your application has users in multiple time zones, you should always store your times in UTC (any timezone would work, but you should stick with the most common convention).
Let the user input in local time, but convert to UTC to store (and compare, and manipulate). Then, convert back from UTC to display in each users' local time zone.
Related
I have weird situation with my PostgreSQL db date value.
On my web site I have calendar for selecting a date and when I select some future date like "2018-09-23" in PostgreSQL table column it is saved as "2018-09-22 22:00:00"?
Obviously I am missing something. On web site all the time it shows okay time "2018-09-23" but at the table it is minus one day as you see above. Why?
Rails stores DateTime fields in UTC, but without marking their time zone as UTC. This corresponds to the timestamp without time zone type in postgres. So if your time zone is +2, it'll store the time as UTC (+0).
In Rails, Time.zone will return the current local timezone (you can add logic to change this by user, for example). When persisting a datetime, Rails will automatically convert the current Time.zone to UTC. However, it doesn't use the Postgres type that actually includes the time zone data, so it relies on convention to convert back and forth to the user's time zone.
If you really only care about the date, use the date type in your migration instead of Timestamp or DateTime.
Times and dates have a lot of subtle quirks and the "right" behavior depends on your use case. In some applications, you need to deal with "local" time when considering date transitions, and sometimes you need to finesse your application or database logic to think in terms of local time and sometimes you care about UTC time.
I have table which have a datetime field named date. When doing a POST in order to insert a new row, the date sent from the client (browser) looks like 2015-11-20T14:30:00+10:00 which is actually a correct date and timezone.
However, inside Postgres this date has been inserted as 2015-11-20 04:30:00.000000, which as you can see, is not at all the same as above. I know the problem is related to the timezone. But I cannot seems to figure out a fix.
For information, I have configured my app timezone :
class Application < Rails::Application
config.time_zone = 'Brisbane'
end
Ideas?
2015-11-20T14:30:00+10:00 means that the local time of 14:30 is 10 hours ahead of UTC. Your database field reflects the correct UTC value of 04:30. This is often the desired behavior, especially if the value represent a timestamp - the date and time something occured (past tense).
In PostgreSQL, there are two different types of timestamp fields (reference)
The TIMESTAMP WITH TIME ZONE field accepts an input that contains a time zone offset. It then converts the value to UTC for storage. On retrieval, it uses the session's timezone setting.
The TIMESTAMP, or TIMESTAMP WITHOUT TIME ZONE simply stores the date and time given, ignoring any offset, and not converting to UTC.
Most of the time, you should indeed use TIMESTAMP WITH TIME ZONE. You should only use TIMESTAMP WITHOUT TIME ZONE if you need to retain the local date and time value, such as in scheduling of future events and calculation of business hours. And for those scenarios, it often makes more sense to split date and time into separate DATE and TIME fields.
One last thing - if you can avoid it, avoid using Rails time zones and use standard tzdb zones. "Australia/Brisbane" is the full tzdb identifier equivalent to the Rails "Brisbane" time zone. Refer to the section on Rails time zones at the bottom of the timezone tag wiki.
I found this gem to be incredibly useful and easy for correctly setting the time https://github.com/kbaum/browser-timezone-rails
I created a new object and saved the same through the console. I noticed that created_at and updated_at columns were in GMT format but when I do a Time.now in my console I get the time in my time zone. How can save my records from the console with my local time?
Rahul, Rails correctly goes out of its way to store dates in UTC (like GMT) format. I strongly advise against undoing this.
Rails (and ruby) provides Time.zone, Time.local and other methods that help you display the values in the correct local time. Your local time is determined by the settings of your system, but your local time isn't necessarily the same as that of other people using the system. Once you put this on a web server in the wild, people may be in different time zones. You can tell Rails which time zone to use by default in application.rb in this section
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = 'Eastern Time (US & Canada)'
This might work OK for cases where most of your users are in the same timezone, but if you want users to be able to see date/times in their timezone, you'll probably want to store their zone in the User record. There's a time_zone_select helper to make it easy to capture that info.
I'm using Rails 3.2.8. When I generate a scaffold with a time field or datetime field. The HTML form field gets pre-populated with the current date/time in UTC. Great that it's pre-populated with the current date/time, but because it's in UTC, we have to change the time back 7 hours every time (which will sometimes require setting the day back 1 also, possibly month and year too). And then it seems the UTC time gets stored in the database, so I'll have issues displaying/editing it as well if I recorded it in our local time.
I looked at the Ruby documentation for the form helpers to deal with local time better, but I don't see anything relevant.
What's the best way to deal with editing and displaying dates and times in Rails?
UPDATE: To clarify, I like the idea that UTC time is stored in the database. I just want the time_select and datetime_select form helpers to edit the times in the user's local timezone. And, of course, I want to easily display the time in the user's local timezone.
You have to set the time zone to display on a per-user basis somewhere in a before/around_filter. This has to be done like:
Time.zone = "Kyiv"
An example can be found in its API: http://api.rubyonrails.org/classes/Time.html#method-c-zone-3D.
Run the rake time:zones:all to see all of them.
All the conversions has to be handled for you behind the scene.
This has helped me in the past. You can do things like:
Time.now.in_time_zone("Central Time (US & Canada)")
See Rails: convert UTC DateTime to another time zone
I have a Rails app that stores time values, and I have set a time zone in config/application.rb.
This works correctly on datetime columns, but time columns show the time in UTC, not the specified time zone.
The time on these two examples are both stored as 20:50 (UTC) in the database, but when I show it in a view the time column shows as UTC and the datetime column is correctly shown in the chosen time zone.
time2: 2000-01-01 20:50:00 UTC
datetime2: 2012-02-09 21:50:00 +0100
Is this expected behavior? Shouldn't time types also use the configured time zone?
ActiveRecord uses TimeWithZone, where methods like localtime, utc, utc? may help you.
Yes, this is expected behavior. Rails (ActiveRecord) stores times in UTC, then coverts them to whatever time zone Time.zone is set to upon rendering in the view.
I give up this, Rails seems to totally ignore config.time_zone with time attributes and just uses it for datetime attributes for reasons I don't understand. And as it seems, not many others understand it as well.
I will change the time attributes to type string and parse it to a time object when I need to work with it as a time object. If this is fixed in a later Rails release I can always change back to using time attributes, but now I need to go on, this has been holding me back for days.
But thanks for trying to help :)