When Should I Use Datetime VS Date, Time Fields in Ruby/Rails

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



Leave a reply



Submit