When should i use DateTime vs date, time fields in ruby/rails?
The general idea is to use a DateTime as a general purpose representation of time. Where you might be confused is that Time also includes a date component as it is an encapsulation of the UNIX time_t
concept of seconds since epoch, or UNIX_TIME()
in MySQL terms.
As I explain in another answer, Time is a more limited representation than DateTime and can only represent dates and times up to Jan 18, 2038. A DateTime can represent 4,712 BCE as well as 21,000 years in the future.
If you want a separate field that represents time of day, which it seems like you might want here, you should create a single numerical field that represents either seconds past midnight if that kind of precision is required, or a more convenient "HHMM" representation that doesn't concern itself with the differences between base-60 and base-10.
Another alternative is to have two fields, one being a DateTime and one being a Date. If you're creating a calendar entry with no particular time, populate only the Date field. If it has a time, populate both.
Remember that a date field is populated with a literal date and does not concern itself with time zones, so this can cause trouble if it is not expressed in the user's local time. A DateTime can always be converted to a user's local time if required.
In Ruby on Rails, what's the difference between DateTime, Timestamp, Time and Date?
The difference between different date/time formats in ActiveRecord has little to do with Rails and everything to do with whatever database you're using.
Using MySQL as an example (if for no other reason because it's most popular), you have DATE
, DATETIME
, TIME
and TIMESTAMP
column data types; just as you have CHAR
, VARCHAR
, FLOAT
and INTEGER
.
So, you ask, what's the difference? Well, some of them are self-explanatory. DATE
only stores a date, TIME
only stores a time of day, while DATETIME
stores both.
The difference between DATETIME
and TIMESTAMP
is a bit more subtle: DATETIME
is formatted as YYYY-MM-DD HH:MM:SS
. Valid ranges go from the year 1000 to the year 9999 (and everything in between. While TIMESTAMP
looks similar when you fetch it from the database, it's really a just a front for a unix timestamp. Its valid range goes from 1970 to 2038. The difference here, aside from the various built-in functions within the database engine, is storage space. Because DATETIME
stores every digit in the year, month day, hour, minute and second, it uses up a total of 8 bytes. As TIMESTAMP
only stores the number of seconds since 1970-01-01, it uses 4 bytes.
You can read more about the differences between time formats in MySQL here.
In the end, it comes down to what you need your date/time column to do:
- Do you need to store dates and times before 1970 or after 2038? => Use
DATETIME
. - Do you need to worry about database size and you're within that timerange? => Use
TIMESTAMP
. - Do you only need to store a date? => Use
DATE
. - Do you only need to store a time? => Use
TIME
.
Having said all of this, Rails actually makes some of these decisions for you. Both :timestamp
and :datetime
will default to DATETIME
, while :date
and :time
corresponds to DATE
and TIME
, respectively.
This means that within Rails, you only have to decide whether you need to store date, time or both.
Difference between DateTime and Time in Ruby
Newer versions of Ruby (2.0+) do not really have significant differences between the two classes. Some libraries will use one or the other for historical reasons, but new code does not necessarily need to be concerned. Picking one for consistency is probably best, so try and mesh with what your libraries expect. For example, ActiveRecord prefers DateTime.
In versions prior to Ruby 1.9 and on many systems Time is represented as a 32-bit signed value describing the number of seconds since January 1, 1970 UTC, a thin wrapper around a POSIX-standard time_t
value, and is bounded:
Time.at(0x7FFFFFFF)
# => Mon Jan 18 22:14:07 -0500 2038
Time.at(-0x7FFFFFFF)
# => Fri Dec 13 15:45:53 -0500 1901
Newer versions of Ruby are able to handle larger values without producing errors.
DateTime is a calendar-based approach where the year, month, day, hour, minute and second are stored individually. This is a Ruby on Rails construct that serves as a wrapper around SQL-standard DATETIME fields. These contain arbitrary dates and can represent nearly any point in time as the range of expression is typically very large.
DateTime.new
# => Mon, 01 Jan -4712 00:00:00 +0000
So it's reassuring that DateTime can handle blog posts from Aristotle.
When choosing one, the differences are somewhat subjective now. Historically DateTime has provided better options for manipulating it in a calendar fashion, but many of these methods have been ported over to Time as well, at least within the Rails environment.
Which should I always parse date times with? DateTime, Time, Time.zone?
Go with Time.zone.parse if you just want to write into ActiveRecord.
DateTime should be avoided. If you're handling dates, you should use Date.parse instead.
Beyond that, it depends on whether the input comes with timezone information, what the current timezone is set to, and whether you want timezones in your data.
Time.zone.parse will return an ActiveSupport::TimeWithZone, defaulting to UTC.
> Time.zone.parse("12:30")
=> Thu, 10 May 2012 12:30:00 UTC +00:00
Time.parse will return a Time, with a zone if it's specified in the input, or the local TZ.
> Time.parse("12:30")
=> 2012-05-09 12:30:00 -0700
For a more detailed explanation of Ruby time comparisons and precision, read this blog post:
http://blog.solanolabs.com/rails-time-comparisons-devil-details-etc/
Why my time field in rails app showing the date as well?
I think that's because Ruby and/or Rails doesn't have any data type to represent time of the day objects without the date component.
You will have to develop your own application logic to deal with the fact that the object that comes from ActiveRecord for that column is, indeed, a DateTime object (even if in the database is only stored the time of day component).
There is already a good answer for a similar question that you can check it out here: https://stackoverflow.com/a/34979912/1781212
ruby on rails parameter compare date with datetime?
This is a type-coercion problem. Because the created_at
field contains a date and time, your date is being converted into 2017-03-04 00:00:00
for the query. Anything that doesn't exactly match that timestamp will be excluded.
There are two approaches to solving this problem.
Database agnostic
Turn your date into a Range object. ActiveSupport provides the Date#all_day
helper for this use-case.
date = Date.parse(params[:date])
MyModel.where(created_at: date.all_day)
Since Date::parse
throws an exception if parsing fails, the real-world implementation would have to account for that
my_models = begin
date = Date.parse(params[:date])
MyModel.where(created_at: date.all_day)
rescue ArgumentError
MyModel.all
end
Postgres
You can cast your created_at
field to date
so that only the date part will be matched.
MyModel.where("created_at::date = ?", params[:date])
Ruby on rails convention for naming date/time fields
I don't know of any specific rails convention, and it doesn't really matter since there's nothing in rails that keys off of datetime fields. The convention I've always gone with is suffix datetime columns with _at
and date columns with _on
. It always seemed more natural to say on a day and at a time.
What difference between the DATE, TIME, DATETIME, and TIMESTAMP Types
DATE: It is used for values with a date part but no time part. MySQL retrieves and displays DATE values in YYYY-MM-DD format. The supported range is 1000-01-01
to 9999-12-31
.
DATETIME: It is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in YYYY-MM-DD HH:MM:SS format. The supported range is 1000-01-01 00:00:00
to 9999-12-31 23:59:59
.
TIMESTAMP: It is also used for values that contain both date and time parts, and includes the time zone. TIMESTAMP has a range of 1970-01-01 00:00:01
UTC to 2038-01-19 03:14:07
UTC.
TIME: Its values are in HH:MM:SS format (or HHH:MM:SS format for large hours values). TIME values may range from -838:59:59
to 838:59:59
. The hours part may be so large because the TIME type can be used not only to represent a time of day (which must be less than 24 hours), but also elapsed time or a time interval between two events (which may be much greater than 24 hours, or even negative).
In Mongoid, are there any differences in the Date, Time, DateTime, and TimeWithZone field types?
There are almost no difference between them, all of them wrap Time type.
You can change DateTime, Date or TimeWithZone to get instances of this types after unserializing from mongo.
Mongoid extends this classes to add demongoize/mongoize methods for data binding. So the only difference is in implementation.
So Time implementation
def demongoize(object)
return nil if object.blank?
object = object.getlocal unless Mongoid::Config.use_utc?
if Mongoid::Config.use_activesupport_time_zone?
object = object.in_time_zone(Mongoid.time_zone)
end
object
end
def mongoize(object)
return nil if object.blank?
begin
time = object.__mongoize_time__
if object.respond_to?(:sec_fraction)
::Time.at(time.to_i, object.sec_fraction * 10**6).utc
elsif time.respond_to?(:subsec)
::Time.at(time.to_i, time.subsec * 10**6).utc
else
::Time.at(time.to_i, time.usec).utc
end
rescue ArgumentError
EPOCH
end
end
Date implementation
def demongoize(object)
::Date.new(object.year, object.month, object.day) if object
end
def mongoize(object)
unless object.blank?
begin
time = object.__mongoize_time__
::Time.utc(time.year, time.month, time.day)
rescue ArgumentError
EPOCH
end
end
end
You can check other implemetations
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/date.rb#L46
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/date_time.rb#L49
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/time.rb#L48
https://github.com/mongoid/mongoid/blob/master/lib/mongoid/extensions/time_with_zone.rb#L32
Related Topics
Using Poltergeist with a Proxy
Trouble on Eager Loading "Second Degree" Associated Objects
Use [].Replace to Make a Copy of an Array
How to Push a Custom Gem to Heroku Master
Defined' and 'Unless' Not Working as Expected
Wicked_Pdf Is Not Rendering Header
Access Local Variables from a Different Binding in Ruby
What's a Semantically-Correct Way to Parse CSV from SQL Server 2008
Any Ruby Library to Inspect What Are the Arguments That a Certain Methods Take
How to Download File from Google Drive API with Service Account
Rvm Isnt Setting Environment with Cron
"Bad Ecpoint" Ssl Error on Fresh Rvm Ruby 1.9.3 Install on Osx Mountain Lion
Iterate JSON with Ruby and Get a Key,Value in an Array
Searching from a Range of Ids in Activerecord
Ruby Popen3 -- How to Repeatedly Write to Stdin & Read Stdout Without Re-Opening Process
Encoding::Undefinedconversionerror: "\Xc2" from Ascii-8Bit to Utf-8