Timezones in Rails 5 when using beginnig_of_month - ruby-on-rails

My Rails 5 app is set to BRT (Brazilian timezone) and my Postgres database to UTC. I never had to worry about that because Rails always calculated the correct time when reading from or writing to the database. So for example when I had an input field with time = 15:00 it would write 18:00 to the database and when reading from the database it would return 15:00 again. Perfect!
But now I want to write the beginning of the month to the database:
Time.now.beginning_of_month which is 2017-04-01 00:00:00
Payment.create(
:time => Time.now.beginning_of_month
)
Now it writes exactly this (in BRT) to the database without converting to UTC. When I read this from the database later it converts it to BRT 2017-03-31 21:00:00 which is wrong.
Of course I could convert the time to UTC before saving it to the database. But I find it strange that Rails always took care of converting and in this case it does not.
I hope the problem became clear.
Any ideas?

I found a very good article about this subject:
https://www.varvet.com/blog/working-with-time-zones-in-ruby-on-rails/
Basically what I had to to is change Time.now to Time.current as Time.now ignores the timezone settings.

Related

Using default application timezone with DateTime.strptime in Rails 5

I read similar questions but did not find a solution.
My Rails 5 App is in
'America/Sao_Paulo'
time zone but saves all times in UTC to the database.
When saving a datetime
'2017-01-01 19:00:00'
to my database it will convert it to UTC and save the UTS time to the database.
Now I need to convert a string to datetime using:
DateTime.strptime(date + ' ' + time, '%d/%m/%Y %H:%M:%S')
And this will take the date and time values as they are and save them to the database without converting to UTC. How can I let my app know that my the datetime is not in UTC yet?
ActiveRecord (by default) will save any datetime to UTC. So, in my opinion you don't need to worry if the time in the database isn't yet in UTC, because ActiveRecord will convert it to UTC.
So, when saving to database, ActiveRecord will always convert it to UTC (whether it is in UTC or not).
And when fetching from database, it follows your configuration in config/application.rb
You can find in the file config.time_zone = 'YOUR_TIMEZONE'.
Reference:
http://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html
Hope it helps, cheers!

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.

timezone and yesterday

I have a problem with rails timezones.
application.rb
config.time_zone = 'Athens'
controller
#from = (Time.zone.now-1.day).to_date
#to = (Time.zone.now).to_date
Entry.where(:created_at => #from..#to)
This query supposed to list entries which were created yesterday. When i list entries, i see that some entries were created today.
For example:
It is 5:53 am now and i see that the last entry which was created yesterday was created 3 hours ago, it mustn't be smaller than 6 hours. Any help will be appreciated.
Your database is probably using UTC timestamps (at least it should be) but Time.zone.now is in your local timezone. Then you call to_date and lose the timezone information. Try this:
#from = (Time.zone.now - 1.day).beginning_of_day.utc
#to = (Time.zone.now).beginning_of_day.utc
Entry.where(:created_at => #from..#to)
So you call beginning_of_day to get back to 00:00:00 and then convert to UTC with utc to get your timestamps into UTC to match the database. You want to keep the time-of-day around all through this so that you don't lose track of what's going during the timezone transitions.

Problems with saving and querying dates in Rails

I have an Appointment model, and for one particular appointment, I saved it having a start_time of 12:15am on 3/5/2011. Look at this:
irb(main):002:0> a = Appointment.find(15)
=> #<Appointment id: 15, start_time: "2011-03-05 05:15:00", created_at: "2011-03-05 03:42:03", updated_at: "2011-03-05 03:42:03", stylist_id: 13, client_id: 8>
irb(main):003:0> a.start_time
=> Sat, 05 Mar 2011 00:15:00 EST -05:00
As you can see, the date got saved wrong. Interestingly, though, Rails compensates for it when the data comes back out.
I assume my app has always behaved this way and I just didn't notice. Recently, though, I wrote a query that pulls the dates out with raw SQL, so I'm getting the wrong time and it's causing problems.
Can anyone shed some light on why this is happening and what I can do to get around the problem?
Rails does this on purpose. Check your time zone settings:
config.active_record.default_timezone
config.time_zone
http://guides.rubyonrails.org/configuring.html#configuring-active-record
Time zone features were introduced in 2.1 and haven't changed much. This article gives a good explanation:
http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/
Rails save datetime in database in UTC time(zero offset) and converts the time to the time zone which we intend when it displays it. So, when we parse directly from the database, you will be getting UTC time. If you try to convert it into time like this:
time_string = #raw string obtained from database(like "2011-03-05 05:15:00")
time_object = Time.parse(time_string)
You will get the time with offset according to the timezone of your machine or server. Ruby parses time like that. It will take the time and give the timezone of your machine(which is incorrect here as the timezone is actually UTC as it is from database). I ran into this problem and solved it by adding UTC when I parse time from raw sql strings from database.
time_string << " UTC"
time_object = Time.parse(time_string) # gives time zone as UTC
then if you use it, the result will be correct.

Rails timestamps don't use the right timezone

I'm a bit confused about timezones in rails. I want my rails app to use British Summer Time (like daylight savings in the US) for the timestamps set in updated_at and created_at in my models. I changed my environment.rb to say
config.time_zone = 'London'
The ubuntu server my app is on seems to use BST for it's time: in the command line, for example, if i type 'date' i get the current time (not offset by an hour). In the rails console, i see the following:
>> time = Time.now
=> Wed Oct 27 16:29:17 +0100 2010
>> time.zone
=> "BST"
All fine. However, if i make a new AR model object and save it, the timestamps are from an hour ago. So, it looks like this is using UTC. Now, i can see the logic in this: since the timestamps might be used in the model logic, you want them to be based on an unvarying yardstick time, ie UTC. But, this is a weird bit of behaviour that i don't understand:
#change a record and save it
>> someobj.save
=> true
#object's updated_at is one hour ago
>> someobj.updated_at
=> Wed, 27 Oct 2010 15:34:22 UTC +00:00
>> Time.now
=> Wed Oct 27 16:34:31 +0100 2010
#however, Time.now - object's updated at is just a few seconds.
>> Time.now - someobj.updated_at
=> 15.305549
So, before doing the subtraction, updated_at is converted into the current time zone.
The reason i want to show the date in the current time zone is just for status reports etc in the views: if someone updates something i want them to see that it was updated '1 minute ago' not 'one hour ago'.
Can anyone unconfuse me? cheers, max
EDIT: My immediate problem, of showing the right time in the status, is solved by using the 'time_ago_in_words' helper, which adjusts for time zone. I'd still like someone to explain what's going on with the timestamps though :)
Timestamps are stored in UTC by default, and this is probably the best way to do it. If you move from one server environment to another, you don't want all of your times shifting around just because you switched time zones.
If you want to know what the timestamp is in your local time zone, you just have to ask for it that way:
someobj.updated_at.localtime
Note the offset listed at the end of the times -- the first offset is 0, the second is 1. When the time calculation occurs, the offset is included automatically, so that the subtraction gives you the correct result. someobj.updated_at and Time.now each displays its value in a different time zone, so they are really only 9 seconds apart, not 1 hour and 9 seconds.

Resources