Comparing dates in rails - ruby-on-rails

Suppose I have a standard Post.first.created_at datetime. Can I compare that directly with a datetime in the format 2009-06-03 16:57:45.608000 -04:00 by doing something like:
Post.first.created_at > Time.parse("2009-06-03 16:57:45.608000 -04:00")
Edit: Both fields are datetimes, not dates.

Yes, you can use comparison operators to compare dates e.g.:
irb(main):018:0> yesterday = Date.new(2009,6,13)
=> #<Date: 4909991/2,0,2299161>
irb(main):019:0> Date.today > yesterday
=> true
But are you trying to compare a date to a datetime?
If that's the case, you'll want to convert the datetime to a date then do the comparison.
I hope this helps.

Yes you can compare directly the value of a created_at ActiveRecord date/time field with a regular DateTime object (like the one you can obtain parsing the string you have).
In a project i have a Value object that has a created_at datetime object:
imac:trunk luca$ script/console
Loading development environment (Rails 2.3.2)
>> Value.first.created_at
=> Fri, 12 Jun 2009 08:00:45 CEST 02:00
>> Time.parse("2009-06-03 16:57:45.608000 -04:00")
=> Wed Jun 03 22:57:45 0200 2009
>> Value.first.created_at > Time.parse("2009-06-03 16:57:45.608000 -04:00")
=> true
The created_at field is defined as:
create_table "values", :force => true do |t|
[...]
t.datetime "created_at"
end
N.B. if your field is a date and not a datetime, then you need to convert it to a time:
Post.first.created_at.to_time > Time.parse("2009-06-03 16:57:45.608000 -04:00")
or parse a date:
Post.first.created_at > Date.parse("2009-06-03 16:57:45.608000 -04:00")
otherwise you'll get a:
ArgumentError: comparison of Date with Time failed

Related

Rails postgres Time attribute not saving

Am I going insane? time attributes lose their value and reset to January 1 2000 after saving the active record object. The db is Postgres. Rails 5.2 and pg gem 1.1.3
2.6.6 :019 > obj.end_time = Date.new(2019, 9,9)
=> Mon, 09 Sep 2019
2.6.6 :020 > obj.save
=> true
2.6.6 :021 > obj.end_time
=> Mon, 09 Sep 2019 00:00:00 UTC +00:00
2.6.6 :022 > obj.end_time.class
=> ActiveSupport::TimeWithZone
But now if I reload from the db, the value is reset:
2.6.6 :023 > obj.reload
2.6.6 :024 > obj.end_time
=> Sat, 01 Jan 2000 00:00:00 UTC +00:00
2.6.6 :025 > obj.end_time.class
=> ActiveSupport::TimeWithZone
The postgres column type is shown in psql as "time without time zone". I guess I just need to specify datetime instead of time in migrations if I want to set the date part?
I tried to change column type in a migration change_column :school_courses, :start_time, :datetime but got:
PG::DatatypeMismatch: ERROR: column "start_time" cannot be cast
automatically to type timestamp without time zone HINT: You might
need to specify "USING start_time::timestamp without time zone"
Not sure how to do this
Use datetime column type to hold a date and time
Only use time in the migration if you don't need the date (only want to store time part)
This is the case with postgres anyway
Migration example:
create_table "school_years" do |t|
t.integer "year"
t.integer "minimum_candidates_per_exam"
t.time "am_start_time"
t.time "pm_start_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Although I generally just use datetime and set the year part as well, and avoid using time

Why does an ActiveRecord object return DateTime.now differently than DateTime.now

Say I have a simple ActiveRecord model with this example schema:
create_table "users", id: :serial do |t|
t.datetime "updated_at"
end
When I run the following code in the console:
user = User.new
user.updated_at = DateTime.now
user.updated_at # => Thu, 27 Feb 2020 09:28:51 GMT +00:00
My question is: why this output is different than the normal return value of DateTime.now, which is
DateTime.now # => Thu, 27 Feb 2020 10:28:51 +0100
Is there some kind of serializer involved? How can I find out more about this?
AR updated_at/created_at are time zone aware attributes. You can read more about them here:
https://api.rubyonrails.org/classes/ActiveRecord/Timestamp.html
If you grab a User record for instance, and call time_zone_aware_types on it, you'll get the timezone aware column types
user = User.first
user.time_zone_aware_types
=> [:datetime, :time]
These types of columns are automatically converted to Time.zone when retrieved from the database even though they are stored in UTC.
The difference with DateTime.now is that it's not timezone aware and just returns the time in UTC
add your time zone in your config/application.rb inside the
class Application < Rails::Application
.......
# it will be like this
config.time_zone = "Asia/Riyadh"
.....
end

Rails Convert UNIX timestamp to SQL DateTime

I have timestamp as "1432927800000"
I want to save it in DateTime column of MySQL. (SQL DateTime column stores date in this format : 2010-06-24 11:30:00)
I have tried
uTime = params[:fromDate] #contains "1432927800000"
Date.new(uTime).to_formatted_s(:db) #Comparison of String with 0 failed.
DateTime.strptime("1318996912",'%s') #Give weird date: Wed, 03 Sep 47377 12:00:00 +0000
Date.parse(uTime).to_s(:db) #Invalid Date
I am expecting 2015-5-30 1:00:00 from "1432927800000"
Instead of strftime will be better to use predefined :db pattern from ActiveSupport:
2.1.0 :002 > Time.at(1432927800000/1000).to_s(:db)
=> "2015-05-29 22:30:00"
to_s is alias for to_formatted_s method and defined in Time and DateTime classes.
Try this I Hope this will help you
I have tried it in my Rails console and I got following.
uTime = 1432927800000
Time.at(uTime/1000).strftime("%Y-%m-%d %I:%M:%S")
## Output
"2015-05-30 01:00:00"
This a link where you which will helps you to convert unix timestamp
http://www.epochconverter.com/

Ruby on Rails time zone strange behaviour

There is task model with attributes when and duration.
create_table "tasks", force: true do |t|
...
t.datetime "when"
t.integer "duration"
...
end
I wrote method for checking if task is active so I can show it on page.
This is active method:
def active?
if (self.when + self.duration) > Time.now
true
end
end
I tried in console to inspect object:
t.when + t.duration
=> Sun, 08 Sep 2013 01:01:00 UTC +00:00
DateTime.now
=> Sun, 08 Sep 2013 01:57:13 +0200
t.active?
=> true
It's true but I entered 1:00 time and 1 minute for duration and I hoped it shouldn't be true.
It seems that when column in database is not saved in correct time zone, so it gives incorrect results. How to solve this issue?
It seems that when column in database is not saved in correct time zone
1) Rails automatically converts times to UTC time before inserting them in the database (which is a good thing), which means the times have an offset of "+0000" . That means if you save a time of 8pm to the database, and your server is located in a timezone with an offset of "+0600", then the equivalent UTC time is 2pm, so 2pm gets saved in the database. In other words, your local server's time is 6 hours ahead of UTC time, which means that when it's 8pm in your server's time zone, it's 2pm in the UTC timezone.
2) When you compare dates, ruby takes the timezone offset into account--in other words ruby converts all times to the same timezone and then compares the times. Here is an example:
2.0.0p247 :086 > x = DateTime.strptime('28-01-2013 08:00:00 PM +6', '%d-%m-%Y %I:%M:%S %p %z')
=> Mon, 28 Jan 2013 20:00:00 +0600
2.0.0p247 :087 > y = DateTime.strptime('28-01-2013 08:20:00 PM +7', '%d-%m-%Y %I:%M:%S %p %z')
=> Mon, 28 Jan 2013 20:20:00 +0700
2.0.0p247 :088 > x < y
=> false
If you just compare the times of the two Datetime objects, x is less than y. However, y has a time of 8:20pm in a timezone that has an offset of +7, which is equivalent to the time 7:20pm in a timezone with an offset of +6. Therefore, y is actually less than x. You need to compare apples to apples, which means you need to mentally compare times that have been converted to the same timezone to get the same results as ruby/rails produces.
3) You can convert Time.now to a UTC time using the rails utc() method:
2.0.0p247 :089 > x = Time.now
=> 2013-09-07 8:00:00 +0600
2.0.0p247 :090 > x.utc
=> 2013-09-07 02:00:00 UTC
That's what ruby does before comparing Time.now to task.when + task.duration
4) You might find it more convenient to create a DateTime object with the time you want using:
DateTime.strptime('28-01-2013 08:00:00 PM +0', '%d-%m-%Y %I:%M:%S %p %z'
Because you are able to specify the offset as zero, you don't have to create a time that anticipates the conversion to UTC time.
Or you can use the change() method, which causes the offset() to change without converting the time:
2.0.0p247 :011 > x = DateTime.now
=> Sun, 08 Sep 2013 00:34:08 +0600
2.0.0p247 :012 > x.change offset: "+0000"
=> Sun, 08 Sep 2013 00:34:08 +0000
ActiveRecord stores timestamps in UTC by default. See How to change default timezone for Active Record in Rails? for changing default time zone.
You can also just use Time#in_time_zone to convert t.when to your timezone, see http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html.

Time fields in Rails coming back blank

I have a simple Rails 3.b1 (Ruby 1.9.1) application running on Sqlite3. I have this table:
create_table :time_tests do |t|
t.time :time
end
And I see this behavior:
irb(main):001:0> tt = TimeTest.new
=> #<TimeTest id: nil, time: nil>
irb(main):002:0> tt.time = Time.zone.now
=> Mon, 03 May 2010 20:13:21 UTC +00:00
irb(main):003:0> tt.save
=> true
irb(main):004:0> TimeTest.find(:first)
=> #<TimeTest id: 1, time: "2000-01-01 20:13:21">
So, the time is coming back blank. Checking the table, the data looks OK:
sqlite> select * from time_tests;
1|2010-05-03 20:13:21.774741
I guess it's on the retrieval part? What's going on here?
Technically, it's not coming back blank. It comes back as a time with a default date. It returns 2000-01-01 20:13:21 as the time, which is expected.
Rails is doing some magic loading of the data into a Time object and clearing out the date (since you only told it to store the time).
If you want to store the date and time then you need to define the column as a datetime. And conversely, if you wanted just a date you would use date.
So to recap:
date => "2010-12-12 00:00:00"
time => "2000-01-01 13:14:15"
datetime => "2010-12-12 13:14:15"

Resources