0

Usually I have datetime fields in my webapp that are stored in the postgresql database as UTC time by Rails. When I go to display those dates and times on a webpage, they display in the local time because I have something similar to the following code:

before_filter :set_time_zone

def set_time_zone
  Time.zone = "Pacific Time (US & Canada)"
end

Works great, except now I need to convert some of those datetime fields to date fields in the database (it's important). For example, I might have a log of dates students started:

Log.create(at: began_at, student_id: student_id)

began_at is a datetime field. It doesn't matter that I've set the Time.zone correctly, the at field is a date and it will be stored in postgresql as potentially the 1 day ahead or behind local time. When I go to display that date, it doesn't get converted to local time, which makes sense... if I haven't stored the time, how does Ruby/Rails know which day it was locally?

What I need is for the local date to be stored. So I need to convert began_at to local time before assigning it to at. What's the proper way to do this in a controller in Rails?

I'm using latest stable Rails (3.2.9 right now)

at.
  • 50,922
  • 104
  • 292
  • 461
  • I don't recommend storing the local date. Store everything in UTC and display it depending on where your users are: e.g. using this gem: https://github.com/basecamp/local_time -- secondly, if you want to query based on date time fields, then you'll probably need to pass in the time zone as extracted from the client side, and convert that to UTC somehow. – BenKoshy Nov 17 '21 at 23:40

2 Answers2

0

Try using use_zone with the zone.

Time.use_zone(zone) do
   log.at = DateTime.parse(params[:at])
 end
Joe Pym
  • 1,826
  • 12
  • 23
0

Given a timestamp in UTC for :began_at, say around 1AM

[1] pry(main)> Time.zone.now.utc.midnight + 1.hour
=> 2012-12-20 01:00:00 UTC

This can be converted to local time

[2] pry(main)> Time.zone.name
=> "Eastern Time (US & Canada)"

using Time.parse(str)

[3] pry(main)> x = Time.zone.now.utc.midnight + 1.hour
=> 2012-12-20 01:00:00 UTC
[4] pry(main)> Time.zone.parse(x.to_s)
=> Wed, 19 Dec 2012 20:00:00 EST -05:00

You can then convert that local timestamp to a date object with .to_date

[5] pry(main)> Time.zone.parse(x.to_s).to_date
=> Wed, 19 Dec 201

which you can then set Log's :at with. Altogether now

Log.create(at: Time.zone.parse(began_at.to_s).to_date, student_id: student_id)
deefour
  • 34,974
  • 7
  • 97
  • 90