Tod is a gem for working with daytimes. That's a tuple of (hour, minute second)
without a day, month or year.
Another additional gem?
Thus SQL has a time
datatype for storing time of day in the format hh:mm:ss
, neither Ruby nor Rails themselves offer an elegant way to deal with day times.
Time
and DateTime
both handle daytime values AND calendar date, using them to only store the time of day will end in inconsistent and thus confusing data, e. g. Time.new
will initialize with the current Time in your Timezone, DateTime.new
initializes at January 1, at an undefined year, without a timezone offset. Comparing or calculating with both datastructures mixed is prone to fail in unpredictable situations, because of the sometimes different time zones and the different behaviors of day times, which sometimes might not even exists (think of time switch from summertime to wintertime in different locations, etc.).
Try to avoid using time zones whenever possible.
When you want to only deal with day times, the handy gem
Tod
Show archive.org snapshot
(Time of day) will make your day.
Tod
Show archive.org snapshot
will add methods to the Time
and DayTime
classes to extract hours, minutes and seconds and convert them to a Tod::TimeOfDay
class. You wont have to worry about different time zones anymore.
Tod offers you
many convenient methods
Show archive.org snapshot
for parsing, comparing, adding/subtracting and formatting time of day objects, some of them are listed below:
Tod::TimeOfDay.parse "15:30" # => 15:30:00
Tod::TimeOfDay.parse "3:30:45pm" # => 15:30:45
Tod::TimeOfDay.new(8) < Tod::TimeOfDay.new(9) # => true
Tod::TimeOfDay.new(23,59,45) + 30 # => 00:00:15
Tod::TimeOfDay.new(22,5,15).strftime("%I:%M:%S %p") # => "10:05:15 PM"
Converting from different time representations is straightforward, too:
Time.now.to_time_of_day # => 11:35:20
DateTime.now.to_time_of_day # => 11:35:20
DateTime.new.to_time_of_day # => 00:00:00
Tod::TimeOfDay(Tod::TimeOfDay.new(8, 30)) # => 08:30:00
Tod::TimeOfDay("09:45") # => 09:45:00
Tod::TimeOfDay.parse("09:45") # => 09:45:00
Tod::TimeOfDay(Time.new(2014, 1, 1, 12, 30)) # => 12:30:00
Tod::TimeOfDay(Date.new(2014, 1, 1)) # => 00:00:00
Using Tod with ActiveRecord
When storing time of day data in your ActiveRecord
model, you can simply use :time
, which is an SQL datatype.
To automatically cast values from and to a Tod::TimeOfDay
, use one of the following methods:
- The ActiveRecord Attribute API Show archive.org snapshot with Tod.
- Use a
serialize :tod_attribute, Tod::TimeOfDay
macro in your model.
Tod and time zones
If necessary, you can convert Tod::TimeOfDay
objects to ActiveSupport::TimeWithZone
. Avoid time zones if possible. It will make things complicated.
In case you have to consider time zones in your application anyway, here are some useful resources:
- https://makandracards.com/makandra/40101-how-to-work-with-time-zones-in-rails
- https://makandracards.com/makandra/646-how-rails-and-mysql-are-handling-time-zones
- https://makandracards.com/makandra/67330-why-you-can-t-use-timezone-codes-like-pst-or-bst-for-time-objects
- https://makandracards.com/makandra/4601-use-time-current-date-current-datetime-current-on-projects-that-have-a-time-zone
- https://makandracards.com/makandra/46009-working-with-or-without-time-zones-in-rails-applications