Issue Formatting DateTime in Rails - ruby-on-rails

So my rails application supports different time zones and sets the time zone at each request like so:
def set_current_time_zone
Time.zone = current_user.time_zone
end
All of my formatting and reports site wide work except for a jQuery date time selector.
The form submits a start time in the format of 04/20/2018 5:23 AM. When I parse the time with the code below I get the following output.
# this is the value of params[:job][:start] 04/20/2018 5:23 AM
job.start = DateTime.strptime(params[:job][:start],"%m/%d/%Y %H:%M %p")
#printing job.start outputs this: 2018-04-20 00:23:00 -0500
As you'll notice the time zone has been applied to the time and is now the wrong time. How do I correct this?
Thanks in advance.

Keep in mind DateTime.strptime('04/20/2018 5:23 AM',"%m/%d/%Y %H:%M %p") will return the value in UTC =>Fri, 20 Apr 2018 05:23:00 +0000
However if you store this value say to a database field, in an active record object, it will output the timezone value to whatever value you've set to Time.zone
This may not be a complete answer but could lead you in the right direction.

Add some more details to my last comment above.
I did this in rails console, my model is Shift and has start_time: datetime.
2.1.3 :022 > time = "04/02/2018 5:23 AM"
=> "04/02/2018 5:23 AM"
2.1.3 :023 > Time.zone = "Singapore"
=> "Singapore"
2.1.3 :024 > shift.start_at = time
=> "04/02/2018 5:23 AM"
2.1.3 :025 > shift.save
(0.1ms) begin transaction
SQL (0.5ms) UPDATE "shifts" SET "start_at" = ?, "updated_at" = ? WHERE "shifts"."id" = 2 [["st
art_at", "2018-02-03 21:23:00.000000"], ["updated_at", "2018-05-02 05:43:38.527338"]]
(1.4ms) commit transaction
=> true
2.1.3 :026 > Time.zone = "Dublin"
=> "Dublin"
2.1.3 :027 > shift.start_at = time
=> "04/02/2018 5:23 AM"
2.1.3 :028 > shift.save
(0.2ms) begin transaction
SQL (0.4ms) UPDATE "shifts" SET "start_at" = ?, "updated_at" = ? WHERE "shifts"."id" = 2 [["st
art_at", "2018-02-04 05:23:00.000000"], ["updated_at", "2018-05-02 05:45:44.638291"]]
(1.4ms) commit transaction
=> true
See the data inside the SQL.

Related

Time column is not showing the time in the time_zone in which it is saved, in Rails?

i am having Time column in my table. and in/config/application.rb am having the following statement. config.time_zone = 'Mumbai'.
and iam saving the time in the database, with the following query
punch_rec.check_out = Time.now
punch_rec.save
When i type the Time.now in the terminal it is showing the following time.
2.2.2 :032 > Time.now
=> 2015-09-28 15:59:06 +0530
and when i retrieve the data from the database, then the time it is displaying in UTC time_zone. because of this in my view the time is displaying wrongly.
these are the steps iam executing.
2.2.2 :038 > p = PunchInOut.find_by_id("28")
PunchInOut Load (0.3ms) SELECT `punch_in_outs`.* FROM `punch_in_outs` WHERE `punch_in_outs`.`id` = 28 LIMIT 1
=> #<PunchInOut id: 28, employee_id: 3, check_in: nil, check_out: nil, date: "2015-09-28", created_at: "2015-09-28 18:37:24", updated_at: "2015-09-28 10:25:22", shift_id: nil, shift_name: nil>
2.2.2 :039 > p.check_in
=> nil
2.2.2 :040 > Time.now
=> 2015-09-29 00:19:17 +0530
2.2.2 :041 > p.check_in= Time.now
=> 2015-09-29 00:19:33 +0530
2.2.2 :042 > p.save
(0.3ms) BEGIN
SQL (0.7ms) UPDATE `punch_in_outs` SET `check_in` = '2015-09-28 18:49:33', `updated_at` = '2015-09-28 18:49:38' WHERE `punch_in_outs`.`id` = 28
(37.7ms) COMMIT
=> true
2.2.2 :043 > p = PunchInOut.find_by_id("28")
PunchInOut Load (0.6ms) SELECT `punch_in_outs`.* FROM `punch_in_outs` WHERE `punch_in_outs`.`id` = 28 LIMIT 1
=> #<PunchInOut id: 28, employee_id: 3, check_in: "2000-01-01 18:49:33", check_out: nil, date: "2015-09-28", created_at: "2015-09-28 18:37:24", updated_at: "2015-09-28 18:49:38", shift_id: nil, shift_name: nil>
2.2.2 :044 > p.check_in
=> 2000-01-01 18:49:33 UTC
2.2.2 :045 >
how can i fix this issue.
If your database is set up to store time in UTC than that time will always be stored in UTC no matter what you do in your app. If you need to display that time to a user who is in some timezone different than UTC than you need to know what timezone he is in. If all your users are in a specific timezone than you can hard code that and display it in your app, for example something like this:
<%= p.check_in.in_time_zone('Mumbai').strftime("%H:%M") %>
If your users are in different timezones then you need to find that timezone first and then you need to display the time correctly. You can do that using some gems or with JavaScript which is the easiest solution. Check this article.
Maybe you had a different timezone in your server. Try to store the value like this: p.check_in = Time.zone.now.
The main difference between Time.now and Time.zone.now is that the first one use server's timezone, and the second one use application.rb's timezone.
Let me know if that works :)

How to fix time retrieved in a different time zone from sqlite in rails?

I have set the default time zone in config/application.rb by adding the following:
config.time_zone = 'Pacific Time (US & Canada)'
config.active_record.default_timezone = :local
Even though Time.now shows the right time zone and the query generated is showing the right time zone when retrieving the record with ActiveRecord, I am getting the wrong time zone. How to fix that?
irb(main):010:0> Time.now
=> 2015-01-15 00:17:18 -0800
irb(main):011:0> Article.first.update_attributes(:updated_at => Time.now)
Article Load (0.2ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" ASC LIMIT 1
(0.1ms) begin transaction
SQL (0.3ms) UPDATE "articles" SET "updated_at" = ? WHERE "articles"."id" = ? [["updated_at", "2015-01-15 00:17:23.369993"], ["id", 1]]
(4.7ms) commit transaction
=> true
irb(main):012:0> Article.first
Article Load (0.2ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" ASC LIMIT 1
=> #<Article id: 1, title: "First article updated", body: "This is my first article", published_at: "2015-01-14 06:53:00", created_at: "2015-01-14 06:53:38", updated_at: "2015-01-15 08:17:23", excerpt: nil, location: nil>
I think you messed things up. Everything is OK in your example. Look:
▶ d1 = DateTime.parse "2015-01-15 00:17:18 -0800"
#=> #<DateTime: 2015-01-15T00:17:18-08:00 ((2457038j,29838s,0n),-28800s,2299161j)>
▶ d2 = DateTime.parse "2015-01-15 08:17:18"
#=> #<DateTime: 2015-01-15T08:17:18+00:00 ((2457038j,29838s,0n),+0s,2299161j)>
▶ d1 == d2
#=> true
Now what you want is to get the time in your timezone? Nothing’s easier:
▶ d2.to_time
#=> 2015-01-15 09:17:18 +0100
The latter shows +0100 just because I’m in CET. Your to_time will show the same TZ as your Time.new.

Time.new subtracting 6 hours AND tacking on CST -6 on Heroku?

I'm sure there's some conversion thing I'm looking over here.
On Heroku's console,
irb(main):052:0> Time.new(2014, 1, 21)
=> 2014-01-21 00:00:00 +0000
However, setting a column to that:
irb(main):042:0> PressRelease.first.update_attribute :published_on, Time.new(2014, 1, 21)
PressRelease Load (1.9ms) SELECT "press_releases".* FROM "press_releases" ORDER BY created_at DESC LIMIT 1
(1.0ms) BEGIN
FriendlyId::Slug Load (0.8ms) SELECT "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = 1 AND "friendly_id_slugs"."sluggable_type" = 'PressRelease' ORDER BY "friendly_id_slugs".id DESC LIMIT 1
(0.6ms) COMMIT
=> true
Gives this date:
=> Mon, 20 Jan 2014 18:00:00 CST -06:00
To clarify, application.rb does indeed have the time zone set:
config.time_zone = 'Central Time (US & Canada)'
And when I check on their console:
irb(main):054:0> Time.zone
=> (GMT-06:00) Central Time (US & Canada)
However, doing this locally works fine:
1.9.3-p448 :011 > Time.new(2014, 1, 21)
=> 2014-01-21 00:00:00 -0600
So, it looks like Heroku is subtracting -6 (since our Time Zone is set to CST -6), then tacking on the timezone of CST -6 as well. Why? This is, as you can see, messing up date-specific items.
If you want Rails to use the time_zone setting, you need to use the wrappers provided by ActiveSupport::TimeZone. See docs: http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html
Here's an example:
Time.zone.parse("2014-1-21")
# Outputs Tue, 21 Jan 2014 00:00:00 MST -07:00

Rails config.time_zone and datetime attribute update

In my application I have: config.time_zone = 'Warsaw'
A strange issue I have, is that it seems like Rails are having problems with comparision of datetime fields.
If I change the datetime 1 hour back (and Warsaw is currently in timezone +0100), Rails won't update the database, even if the field has changed. However, if I change the field once again, then the update will go to the database.
Example:
(Rails 3.1.0, ruby-1.9.2-p290, fresh rails app):
$ rails g model User starts_at:datetime
$ rake db:migrate
$ rails c
Loading development environment (Rails 3.1.0)
ruby-1.9.2-p290 :001 > u = User.create({:starts_at => "2011-01-01 10:00"})
SQL (21.3ms) INSERT INTO "users" ("created_at", "starts_at", "updated_at") VALUES (?, ?, ?) [["created_at", Tue, 13 Dec 2011 11:32:50 CET +01:00], ["starts_at", Sat, 01 Jan 2011 10:00:00 CET +01:00], ["updated_at", Tue, 13 Dec 2011 11:32:50 CET +01:00]]
=> #<User id: 1, starts_at: "2011-01-01 09:00:00", created_at: "2011-12-13 10:32:50", updated_at: "2011-12-13 10:32:50">
ruby-1.9.2-p290 :002 > u.starts_at
=> Sat, 01 Jan 2011 10:00:00 CET +01:00 # datetime created
ruby-1.9.2-p290 :003 > u.starts_at = "2011-01-01 09:00:00" # new datetime with one hour back
=> "2011-01-01 09:00:00"
ruby-1.9.2-p290 :004 > u.starts_at
=> Sat, 01 Jan 2011 09:00:00 CET +01:00 # changed datetime
ruby-1.9.2-p290 :005 > u.save
=> true
ruby-1.9.2-p290 :006 > u.starts_at = "2011-01-01 09:00:00"
=> "2011-01-01 09:00:00"
ruby-1.9.2-p290 :007 > u.save
(0.3ms) UPDATE "users" SET "starts_at" = '2011-01-01 08:00:00.000000', "updated_at" = '2011-12-13 10:33:17.919092' WHERE "users"."id" = 1
=> true
I've tested it in this fresh app, because I have a problem with this in larger application. What is going on? I've tried to browse the Rails code, tried to re-copy the relevant code 'by-hand' in console (like update, assign_attributes, even checked time_zone_conversion) and it worked, but not in 'real world'..
looks like you stumbled on a similar issue.
The problem appears to be here:
https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L62
When rails it testing if the value was changed it compares old & new:
old = From cache (which is Time in your current timezone)
new = Time in UTC (+00:00) as saved in the database
If the difference in time is the UTC offset, the above erroneously succeeds (luckly the new cached value holds the intended change).
The next save/update compares with the new (and correct) cached value and marks the field as changed.
EDIT:
Done some tests, this works well for me:
https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb#L50
Change
write_attribute(:#{attr_name}, original_time)
to
write_attribute(:#{attr_name}, time.in_time_zone('UTC').to_s)
Boris

Save Datetime in UTC, view/query in User's timezone in Rails?

What is the standard for saving times in one zone and viewing them in another? I have this in my environment.rb:
config.time_zone = 'UTC'
But I want to render it, and do queries like "all posts created today" in their timezone, where beginning_of_day returns the beginning of the day in their timezone rather than UTC. Is rails already handling the conversion in the background?
Here's the issue:
#now = Time.now
=> Wed Jan 26 09:50:04 -0600 2011
User.count(:conditions => ["created_at > ?", #now])
SQL (1.3ms) SELECT count(*) AS count_all FROM `users` WHERE (created_at > '2011-01-26 09:50:04')
=> 1
#now = Time.now.utc
=> Wed Jan 26 15:50:10 UTC 2011
User.count(:conditions => ["created_at > ?", #now])
SQL (1.2ms) SELECT count(*) AS count_all FROM `users` WHERE (created_at > '2011-01-26 15:50:10')
=> 0
ActiveSupport has built-in methods to display time values in any time zone. Typically you'd add a time_zone column to your User model and set it to the user's preferred zone.
#user.update_attribute(:time_zone,'Eastern Time (US & Canada)')
Then when displaying a time value, set the zone to the user's zone.
Time.zone = #user.time_zone
Time.zone.now # shows current time according to #user.time_zone
One approach is to set this in ApplicationController so it is done for each request:
class ApplicationController < ActionController::Base
before_filter :set_time_zone
def set_time_zone
Time.zone = current_user.time_zone if current_user
end
end
Note: see the API under ActiveSupport::TimeWithZone

Resources