Finding records based on converted timezone? - ruby-on-rails

I have records with a created column whose datetime is stored in UTC.
For instance, this is the datetime stored in one record: 2014-02-01 00:33:25
But if I retrieve that record and confer it to CST, it'd look like this:
Article.find(1).created.in_time_zone('Central Time (US & Canada)') => Fri, 31 Jan 2014 18:33:25 CST -06:00
Which is a different day/month as far as that timezone goes.
The problem I'm having is finding records based on a date. So say I wanted to pull all records for January 31, 2014 (CST). I want to include my example record.
How do I do that in a Rails app? I'm running Rails 4.0.1 and Ruby 2.0.0 with Postgres 9.3.1.0.

Use AT TIME ZONE to change timezone
Article.where("date(created AT TIME ZONE 'UTC' AT TIME ZONE 'CST') = '01/31/2014'")

Got some help outside of SO and got what I was looking for.
Say I wanted to find all records in a date range, this is what it'd be:
Article.where(created: Date.parse("January 1, 2014").in_time_zone('Central Time (US & Canada)').beginning_of_day.utc..Date.parse("January 31, 2014").in_time_zone('Central Time (US & Canada)').end_of_day.utc)

Related

Rails: Converting created_at to PST

I want to convert the created_at to this format January 12, 2:00 PM PST.
The first step I tried was to convert the created_at field to Pacific Standard Time (PST).
However, I'm stuck - I can't even get past this step.
I've tried these, but neither worked:
Time.parse(self.created_at).in_time_zone('Pacific Time (US & Canada)')
time = Time.parse(self.created_at)
time.in_time_zone('Pacific Time (US & Canada)')
I receive no implicit conversion of ActiveSupport::TimeWithZone into String when I do this.
I based it on these questions:
How do you convert the following time from UTC to EST in Ruby (without Rails)?
How to convert time from UTC to PST in rails
Since it is already a datetime, you should be able to just do this to convert it:
self.created_at.in_time_zone('Pacific Time (US & Canada)')
Don't forget to save the new time zone to the record in the database.
Time.parse() is meant to convert strings into datetime(https://apidock.com/ruby/v2_5_5/Time/parse/class).

Daylight Savings Time ignored using in_time_zone Rails 4

I'm having a frustrating issue that I can't seem to narrow down. I have searched many similar articles but they are not close enough to my issue to resolve. I am trying to pull a time from the database and display it in more than one time zone. My Rails app is using UTC as default. Here is what I'm doing:
On the create action I take the string of time which will be saved in the time column in my DB:
params[:schedule][:start] = "09:00"
Time.zone = "Central Time (US & Canada)"
#schedule.start = Time.zone.parse(params[:schedule][:start])
The above formats the time as it is supposed to:
2016-04-12 09:00:00 -0500
This is saved in the DB as:
2000-01-01 14:00:00
This has no time offset which is fine since I know it's in UTC. The problem happens when I go to display the time:
#schedule.start.in_time_zone("Central Time (US & Canada)")
This returns:
Sat, 01 Jan 2000 08:00:00 CST -06:00
Now, since this is a time column, I don't care about the date. I plan on formatting the value to only show the time. However, it is showing CST when it is currently CDT.
I can't figure out why this is happening. As I said I am not setting the Time Zone anywhere in my application.rb or anywhere else and I only set the Time zone on the create action which should be fine when moving to a new action.
Any help on clarifying this would be awesome!
This seems to be because when the time is stored it is stored with the date in the year 2000-01-01 which seems to be why it is using CST. How can I ignore the date when converting it to a particular timezone or will I need to change the column type to DateTime to get this to work properly?
It is showing CST simply because the time is read from the database including the stored date, i.e. it's read as 09:00 of Jan 1st 2000.
I guess you'd have to parse the time upon reading the attribute back. You can use a helper method in your model, for example:
# schedule model
def start_in_zone(zone)
self.start.strftime("%H:%M").in_time_zone(zone)
end
This will take only the hours and minutes part of the stored time and parse it in the given time zone with the date set to today. See this example:
"Sat, 01 Jan 2000 08:00:00".to_time.
strftime("%H:%M").
in_time_zone("Central Time (US & Canada)")
# => Tue, 12 Apr 2016 08:00:00 CDT -05:00
The fact that it matters whether it's CST or CDT means you do, on some level, care about the date. While I'm not familiar with the exact rules of Daylight Savings in that region, I do know that Jan 1 is the middle of winter and will definitely not be on Daylight Savings time.
Add the relevant date into your #schedule before putting it into a time zone, and it should fix the problem.

Rails4: Saving and displaying date in user's timezone

I am working on a rail4 app. Where I want to store dates in all mysql tables in UTC. However I store user's timezone in a specific table, called users. When user logs in, I get user's timezone form user table and save in session.
I am able to save date in all tables in UTC as default value of config.time_zone is UTC for activerecords and activemodels. But while displaying I want to show dates in user's timezone. As well as, when any user inputs a date/time in any html form, then I want to save it in the equivalent UTC format.
What is the best way to achieve this?
Rails, activerecord and MySQL will save all the timestamp fields in UTC. Without you having to do anything.
In your application.rb file where the configuration of the Application is done, you define the default time zone if you want the display of timestamps to take place on time zone different from UTC.
Hence
config.time_zone = 'Central Time (US & Canada)'
will display the timestamp fields (without you having to do anything special in other piece of code) using the Central Time.
When you want each of your users to have timestamps displayed in different time zone you can store the time zone in a column along side the user data. The column can be called time_zone and can contain the string of the user preferred time zone.
But, you have to tell the timestamp object to display itself to the specific timezone. This is done with the help of the method in_time_zone(timezone) that DateTime object responds to.
Example (when the default time zone is UTC):
1.9.3-p194 :004 > d = DateTime.new(2012, 9, 1, 6, 30, 0)
=> Sat, 01 Sep 2012 06:30:00 +0000
1.9.3-p194 :005 > d.in_time_zone("Central Time (US & Canada)")
=> Sat, 01 Sep 2012 01:30:00 CDT -05:00
Or you can change the time zone globally for the request at hand on a before or around filter. There is a documentation on internet if you do a google on that.
Read also this one: http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html
for various alternatives to approach the problem.
You could store the time in UTC, and store the timezone separately. Timezones are commonly stored as a UTC-offset in seconds (seconds are the SI unit of time).
Then you can display it like so:
utime = Time.now.utc.to_i # this value can be any format that Time.at can understand. In this example I'll use a unix timestamp in UTC. Chances are any time format you store in your DB will work.
=> 1375944780
time = Time.at(utime) # parses the time value (by default, the local timezone is set, e.g. UTC+08:00)
=> 2013-08-08 14:53:00 +0800
time_in_brisbane = time.in_time_zone(ActiveSupport::TimeZone[36000]) # sets the timezone, in this case to UTC+10:00 (see http://stackoverflow.com/a/942865/72176)
=> Thu, 08 Aug 2013 16:53:00 EST +10:00
time_brisbane.strftime("%d %b %Y, %l:%M %p %z") # format with strftime however you like!
=> "08 Aug 2013, 4:53 PM +1000"

Rails 3 DateTime and Time beginning_of_day end_of_day format incorrect

I am trying to find events on certain days with this code:
Event.where('starttime BETWEEN ? AND ?', DateTime.now.beginning_of_day, DateTime.now.end_of_day)
In rails console if I run DateTime.now.beginning_of_day I get exactly what I expect:
Mon, 09 Apr 2012 00:00:00 -0700
I can see where the problem is occurring but looking at the SQL in rails console. Somehow when the date makes it into the SQL query it gets automatically formatted to the wrong date and time.
SELECT "events".* FROM "events" WHERE (starttime BETWEEN '2012-04-09 07:00:00' AND '2012-04-10 06:59:59')
This is giving me results that vary from today until tomorrow, as the sql above says. I can see that when the DateTime.now.beginning_of_day also DateTime.now.end_of_day are being formatted incorrectly once they make it into the sql query. Do I need to be formatting this in a certain way? Any idea why it would go to 7:00 of today and 7:00 of tomorrow?
I don't know if it makes a difference but I'm using PostgreSQL.
Thanks!
See: http://railscasts.com/episodes/106-time-zones-in-rails-2-1
I think the times you're quoting above are actually the same time, just one is UTC time (you're on pacific time right?). To fix this you could try setting:
config.time_zone = "Pacific Time (US & Canada)"
in your environment.rb
You could also try:
DateTime.now.utc.beginning_of_day
DateTime.now.utc.end_of_day
so the you're using UTC as per the DB
You are probably using UTC time in your database. This is a good thing but it leads to all sorts of confusion. The -0700 offset is converted to 07:00:00 since that's when your day starts in UTC time.
You could use the PostgreSQL AT TIME ZONE construct with UTC timestamps:
SELECT e.*
FROM events e
WHERE starttime >= '2012-04-09 00:00' AT TIME ZONE 'UTC'
AND starttime < '2012-04-10 00:00' AT TIME ZONE 'UTC'
I recently explained PostgreSQL timestamp and time zone handling in a related answer.

How to parse date such that it is in EST

I am using Rails 3.1. Here is my configuration
config.time_zone = "Eastern Time (US & Canada)"
Now user enters Nov 30, 2011 at 7:00 PM. How do I parse this text so that after parsing I get the result in EST?
You can do so by calling time = ActiveSupport::TimeZone.new('EST').parse('Nov 30, 2011 at 7:00 PM'). Also you can parse the time string as being in user-specific or default timezone by calling Time.zone.parse. You can convert the result time into any timezone thanm i.e. Time.zone.now.in_time_zone('Asia/Yekaterinburg')
Also there is no need in do any manual conversions of timezones before storing the time to database as Rails does is automatically.
You should store all values in UTC and render them in user's local time. "Eastern Time" is a loose concept at best and changes on a fairly regular basis as politicians decide to extend or contract Daylight Saving Time.
Generally you can do this with the ActiveSupport::TimeZone methods local_to_utc and utc_to_local conversion methods.

Resources