Weird created_at behavior - ruby-on-rails

I've set config.time_zone = 'UTC' in environment.rb, and yet still I get some weird behavior with Rails' built-in datetime fields:
>> Time.now
=> Sun Jun 21 17:05:59 -0700 2009
>> Feedback.create(:body => "testing")
=> #<Feedback id: 23, body: "testing", email_address: nil, name: nil, created_at: "2009-06-22 00:06:09", updated_at: "2009-06-22 00:06:09">
>> Time.parse(Feedback.last.created_at.to_s)
=> Mon Jun 22 00:06:09 UTC 2009
Any thoughts?

It looks like it's properly setting the timezone in the ActiveRecord object, so I don't think you need to worry too much. If you want to force your timestamp from Rails to use UTC, you can use Time.utc.
Time.now.utc
=> Mon Jun 22 00:54:21 UTC 2009

Related

Rails app not following the timezone configured in config/application.rb

I'm new to configuring timezones and confused about a few points. Any advice on the correct configuration would be appreciated.
My understanding is that it's best practice to store all timestamps as UTC in the DB (I'm using PostgreSQL). On the other hand, in the actual app, I'd like to see the timestamps in my local timezone (JST +9:00).
I've configured config/application.rb like this:
module MyApp
class Application < Rails::Application
config.load_defaults 5.2
config.time_zone = 'Tokyo'
end
end
However, I'm not sure it's configured correctly, because I'm getting mixed results in the rails console. Time.zone and Time.now tell me the timezone is set to JST, but the created_at and updated_at timestamps are rendered as UTC when I do User.first.
User.first
#=> #<User id: 1, first_name: "Bob", last_name: "Smith", created_at: "2019-04-09 08:54:30", updated_at: "2019-04-09 08:54:30">
But then, the time is rendered as JST if I specifically ask for the created_at time:
User.first.created_at
#=> Tue, 09 Apr 2019 17:54:30 JST +09:00
Why are the timestamps being rendered as UTC unless I specifically ask for the time itself? Is this normal? The same phenomenon is happening for DateTime columns in my other tables as well.
All your dates seems to be the same, it's just how they are represented on different contexts.
This:
User.first
#=> #<User id: 1, first_name: "Bob", last_name: "Smith", created_at: "2019-04-09 08:54:30", updated_at: "2019-04-09 08:54:30">
renders the result of .inspect
This:
User.first.created_at
#=> Tue, 09 Apr 2019 17:54:30 JST +09:00
is the console guessing you want the date formated with the current time zone.
You could force some representation being explicit
User.first.created_at.to_formatted_s(:db) #should print the same as you see on the inspect
I18n.localize(User.first.created_at) #should localize the date with the default date format
I18n.localize(USer.first.created_at, format: :something) #should localize the date as the format you defined as ":something" on your locale file

Adding year for all records with update_all

I need to update all records in my model by adding another year before the date saved , seek information and an option is with update_all , I really would help an example with dates update_all database: PostgreSQL
An example:
the saved date is this 15/01/16 after executing the action 01/15/17 and so on all records.
or some other option would be very helpful!
If you use the PostgreSQL database you can use the interval from datetime functions:
$ rails console
=> User.last
=#<User:0x00563c0ed6e0c0
id: 7,
name: "foo",
email: "foo#test.ru",
created_at: Tue, 15 Mar 2016 19:54:52 MSK +03:00,
^^^^
.......
=> User.update_all("created_at = created_at + '1 year'::interval")
=> #<User:0x00563c0c9e4f78
id: 7,
name: "foo",
email: "foo#test.ru",
created_at: Wed, 15 Mar 2017 19:54:52 MSK +03:00,
^^^^
........
If MySQL database you can use the DATE_ADD function.
All of this should work if the column have a right type.

Rails model attribute (a DateTime) has different value depending on how its called

I am using Rails 4.2 and Ruby 2.2.0. I have a model called Ride that has a DateTime attribute called start_time. When I call Ride.find(1803), The start_time is shown as January 9th. But when I call Ride.find(1803).start_time, It returns a start_time on January 9th. How is this possible and how do I fix it? Here's the full code I ran in the console:
irb(main):028:0> Ride.find(1803)
=> #<Ride id: 1803, start_time: "2016-01-09 00:00:00", end_time: nil, created_at: "2016-01-05 16:55:44", updated_at: "2016-01-05 20:35:38", user_id: 29, ride_type: nil, horse_id: nil, notes: "", available_to_ride_additional_horses: nil, admin_approved: false, weekday: nil, unavailable_to_ride: false, time_range_dropdown: "Morning", rider_name: "Matti Fisher", rider_last_name: "Fisher", rider_first_name: "Matti", edited_at: nil, requested_time: "2016-01-09 19:30:00">
irb(main):029:0> Ride.find(1803).start_time
=> Fri, 08 Jan 2016 19:00:00 EST -05:00
This is because a date/time value is stored in the database as UTC and the default implementation of inspect for an ActiveRecord model doesn't apply any timezone conversion.
However, when you access the date/time value, Rails will apply the current timezone settings.
You can do the math. Since your timezone is UTC-5, both datetime represent the same object
2016-01-09 00:00:00 UTC
Fri, 08 Jan 2016 19:00:00 EST -05:00
As a proof, you can call
Ride.find(1803).start_time.utc
and you will get the date/time as UTC, that will probably be the same value you see when you print out the full record representation.

Comparing ranges of datetimes in Ruby on Rails against one-another

Right now I'm trying to see if a certain show's start and end times overlap another show that's currently recording => true where 'show' is the TV show the user wants to record.
def self.record_show
shows = Box.first.shows.where(:recording => true).flatten
show_start_and_end_times = shows.collect {|x| x.start_time..x.end_time}
current_show_time = show.start_time..show.end_time
overlap = show_start_and_end_times.select {|c| current_show_time.overlaps?(c)}
if overlap.present?
nil
else
show.update_attributes(:recording => true)
show.save
end
end
It runs the method, but I'm having difficulty figuring out how to get it so that it finds the actual currently recording show that's causing the overlap. So for example, let's say in 'shows' I currently have two shows:
[#<Show id: 181, box_id: 78, title: "The Fox", channel: 22, single_recording: true, created_at: "2014-08-12 19:55:49", updated_at: "2014-08-12 20:09:24", start_time: "2014-08-12 19:55:49", end_time: "2014-08-12 20:25:49", recording: true>, #<Show id: 186, box_id: 78, title: "Funniest Home Videos", channel: 45, single_recording: true, created_at: "2014-08-12 19:55:49", updated_at: "2014-08-12 20:09:27", start_time: "2014-08-12 23:20:49", end_time: "2014-08-13 00:20:49", recording: true>]
In show_start_and_end_times I have:
[Tue, 12 Aug 2014 19:55:49 UTC +00:00..Tue, 12 Aug 2014 20:25:49 UTC +00:00, Tue, 12 Aug 2014 23:20:49 UTC +00:00..Wed, 13 Aug 2014 00:20:49 UTC +00:00]
In current_show_time I have:
Tue, 12 Aug 2014 19:55:49 UTC +00:00..Tue, 12 Aug 2014 20:55:49 UTC +00:00
Which means that in overlap I have the start_time..end_time of the first show_start_and_end_times show, which is the one that is causing the overlap:
[Tue, 12 Aug 2014 19:55:49 UTC +00:00..Tue, 12 Aug 2014 20:25:49 UTC +00:00]
I tried comparing the two times against one-another:
(shows.first.start_time..shows.first.end_time) == (overlap.first)
Which gives me false, even though the times are exactly the same. How can I compare the overlap time against the shows list to figure out which show is causing the overlap?
You'll wand to check out:
http://guides.rubyonrails.org/active_record_querying.html
Using info from that you might be able to do something like:
def self.record_show
overlapping_shows = Box.first.shows.where(recording: true).where("start_time <= :show_end AND end_time >= :show_start", {show_start: show.start_time, show_end: show.end_time}).flatten
if overlapping_shows.present?
nil
else
show.update_attributes(:recording => true)
show.save
end
end
This is a pretty common problem, and I'd recommend checking out this SO question for general algorithm advice on how to do the overlap checking:
Determine Whether Two Date Ranges Overlap
UPDATE:
I would change it to something like this:
shows = Box.first.shows.where(:recording => true).flatten
overlapping_show = nil
current_show_time = show.start_time..show.end_time
shows.each do |s|
if current_show_time.overlaps?(s.start_time..s.end_time)}
overlapping_show = s
break # you could alternatively return an array of overlapping
# if you anticipate more than 1 will overlap
end
end
if overlap.present? #...

Rails and timezone in created_at

ruby-1.9.2-p0 > SalesData.last
=> #<SalesData id: 196347, created_at: "2011-04-05 18:53:15", updated_at: "2011-04-05 18:53:15">
ruby-1.9.2-p0 > SalesData.last.created_at
=> Tue, 05 Apr 2011 20:53:21 CEST +02:00
application.rb:
config.time_zone = 'Copenhagen'
I don't get it - anyone?
I assume you're asking why the created_at datetimestamps appear to differ. In short, they don't.
Rails always stores datetimes in UTC, converting them to your configured timezone on the fly while loading the record. I don't know exactly when that conversion happens, but I'm betting you're just seeing those two states.

Resources