Read more

Tod: A Gem for handling daytime without a date

Jakob Scholz
April 30, 2019Software engineer at makandra GmbH

Tod is a gem for working with daytimes.

Another additional gem?

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

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. In your model class, you'll have to tell Tod to take care of the serialization of the particular attribute and you're good to go.

class ModelWithTod < ActiveRecord::Base
  serialize :tod_attribute, Tod::TimeOfDay
end

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:

Posted by Jakob Scholz to makandra dev (2019-04-30 07:18)