timezone and yesterday - ruby-on-rails

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.

Related

Timezones in Rails 5 when using beginnig_of_month

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.

how can i menction specific offset to be deducted while saving times or datetime in rails?

I am having a datetime column to store employee check-in ,out times. my logic in the controller action to capture check-in is,
def check_in
#employee = current_user.employee
punch_record = #employee.in_outs.where("date = ?", Date.today).first
punch_record.check_in = DateTime.now
punch_record.save
end
when a person clicks check-in then the above logic gets executed.And in database it saves the check-in by deducting the indian offset ,that is (05:30). and in view page, i am using the in_time_zone method to show the check_in time, back in indian timezone,so that its adding the offset(05:30). and the time is showing properly. this is working fine.
record.check_in.in_time_zone(record.time_zone).strftime(" %I:%M %P")
here the record time_zone = Mumbai
now i am facing the time_zone issue in import attendance, where a person fills the employee check-in,out times in spreadsheet and uploads it. the format that is used in excel sheet is 09:30 am.
so here i am using the following logic to convert it into datetime.
irb(main):004:0> "09:30 am".to_datetime
=> Mon, 07 Nov 2016 09:30:00 +0000
here in this case the offset(05:30) is not getting deducted. how to make the offset deducted in this case?
You aren't comparing like with like.
In the first case you are doing:
record.check_in.in_time_zone(record.time_zone)
Which is taking the recorded datetime object (9:30 am) and converting it to the relevant time zone.
In the second case:
"09:30 am".to_datetime
Which is just setting date time to 9:30 am - you are doing nothing to convert it.
Replicate your logic in rails console by doing:
"09:30 am".to_datetime.in_time_zone('Kolkata')
and you will find you get the right result.
If "9:30 am" is input that isn't UTC but represents the time in India itself, then to convert it to UTC simply do:
"9:30".in_time_zone('Kolkata').utc
=> 2016-11-07 04:00:00 UTC

Rails 3 timezone confusions

I'm confused on how rails 3 timezones are supposed to work.
So I config rails to use Pacific time, and tell active record to store in Pacific time.
# application.rb
config.time_zone = 'Pacific Time (US & Canada)'
config.active_record.default_timezone = 'Pacific Time (US & Canada)'
Now I submit update a model and this comes through in the params:
"start_at"=>"2013-07-24 00:00:00"
From the console now:
>> Sale.last
=> #<Sale id: 24, start_at: "2013-07-24 00:00:00", ...snipped... >
>> Sale.last.start_at
=> Tue, 23 Jul 2013 17:00:00 PDT -07:00
>> Sale.last.start_at.in_time_zone
=> Tue, 23 Jul 2013 17:00:00 PDT -07:00
So after trying to force everything to Pacific time, its creating time objects form the database by factoring in the -7 hours of Pacific time.
If I set a time to 2013-07-24 00:00:00 I would expect Tue, 24 Jul 2013 00:00:00 PDT -07:00 to come back out. And yet it does not. I was having similar confusing issues when active record was using UTC to store dates. I had a few tests that would fail only after 5pm when time to date conversions yielded a different date.
How do I tame this? Storing UTC dates in the database seems like a good idea, and I can use in_time_zone on time objects for display, but does that means that times in forms must be UTC?
Our application functionality is very tied to server time, and certain thing happen every day as specific times. So forcing everything to Pacific time seems like it should be fine. But so far I can't seem to make this behave consistently.
How do I make all this not suck?
This is going to be a 1/2 answer, re-iterating from comment thread above with some additional information
I hope to update with more later. There are many gotchas with this stuff
UPDATE: finally did a blog post on rails timezones
http://jessehouse.com/blog/2013/11/15/working-with-timezones-and-ruby-on-rails/
See also: http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails
i would use UTC for the application timezone and the activerecord default. Use I18n.localize method (setup formats in config/locales/en.yml) for display of dates and datetimes; set the current threads timezone based on user settings or a default (whatever makes sense for your app)
if the current thread is set to the users timezone activerecord should do the right magic and save the offset UTC value in the db, then when you display that value to the user with I18n it will display it as the user entered it (converting from UTC to the users timezone) - it gets a bit tricky when you are entering a time for say an event that is taking place in another timezone - in that case the thread needs to be set to the timezone of that location and using I18n displays need to be for the location instead of the user
setting current users timezone
see http://railscasts.com/episodes/106-time-zones-revised which uses around filter
example below uses before_filter
both assume a time_zone column on the user account
some code
class ApplicationController < ActionController::Base
protect_from_forgery
# auth the user
before_filter :authenticate_user!
# Set user's time zone
before_filter :set_user_time_zone
# ....
def set_user_time_zone
if current_user and current_user.time_zone.present?
Time.zone = current_user.time_zone
# else some default?
end
end
end
Alternatively - set based on browser settings, etc...
see http://guides.rubyonrails.org/i18n.html
specifically: http://guides.rubyonrails.org/i18n.html#setup-the-rails-application-for-internationalization
display date times
Use I18n.localize aka I18n.l or just l - see http://guides.rubyonrails.org/i18n.html#adding-date-time-formats
changing the timezone display for part of a view
User is set to Pacific but showing an event time for an event taking place in Eastern
Time.use_zone(event.location.time_zone) do
puts event.start_time
end
WARNING: I have found the above does not work correctly if event was pulled using find_by_sql method, regular active record queries work well

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