Demystifying the Time Class of Ruby

Eli Lauffenburger
5 min readMar 26, 2019

--

https://movieweb.com

I’ve been studying almost nothing but the Ruby language for the past five weeks, yet somehow a basic concept like time and the way Ruby uses it has eluded my understanding until the present date. This brief post aims to introduce and simplify the Time class of Ruby. This is by no means a deep dive, but rather an attempt to help you get started.

The Time class is described in the Ruby documentation as being “Stored internally as the number of seconds with fraction since the Epoch, January 1, 1970 00:00 UTC”. I think this is one of the reasons the Time class can initially be confusing. The Epoch that the documentation is referring to is the Unix Epoch, linked here for further reading. What readers of this post need to know is that the Time class calculates object values based off of seconds. This introduces the main difference between the Time and Date classes of Ruby.

The Time class calculates object values using seconds, and hence has precision to operate with hours, minutes, and seconds. All values stored within the Time class may have sub-second fractions associated with them — making them tricky to work with when comparing values that appear to be equal. The Date class operates down to day precision, making it less precise but much more simple to deal with. It goes without saying, but if you need to represent values of time down to the hour, minute or second scope, you’re better off using the Time class. Otherwise, you’re likely better off with the Date class.

Code snippet showing how addition varies between Time and Date classes (adding seconds vs. days)2.6.1 :002 > time = Time.new(2019)
=> 2019-01-01 00:00:00 -0600

2.6.1 :003 > date = Date.new(2019)
=> #<Date: 2019-01-01 ((2458485j,0s,0n),+0s,2299161j)>

2.6.1 :004 > time + 1
=> 2019-01-01 00:00:01 -0600

2.6.1 :005 > date + 1
=> #<Date: 2019-01-02 ((2458486j,0s,0n),+0s,2299161j)>

There are several options for creating a new instance of Time. The most simple method is using the ::new class method. Calling ::new without any arguments (equivalent to ::now) will create an instance of Time at the current system time of your computer. You may add year, month, day, hour, minute, second and timezone as additional arguments.

Demonstrating Time.new2.6.1 :001 > Time.new
=> 2019-03-26 10:55:27 -0500

2.6.1 :002 > Time.new(2019)
=> 2019-01-01 00:00:00 -0600

2.6.1 :003 > Time.new(2019,2)
=> 2019-02-01 00:00:00 -0600

2.6.1 :004 > Time.new(2019,2,3)
=> 2019-02-03 00:00:00 -0600

2.6.1 :005 > Time.new(2019,2,3,4,5,6, "-02:00")
=> 2019-02-03 04:05:06 -0200

A less intuitive (in my opinion) method that is more representative of the class design is using the ::at class method to create a new instance. This method takes the number of seconds that have passed since the Unix Epoch mentioned earlier and returns a new time object.

Demonstrating Time.at2.6.1 :001 > Time.at(0)
=> 1969-12-31 18:00:00 -0600 #beginning of the Unix Epoch

2.6.1 :002 > Time.at(1550000000)
=> 2019-02-12 13:33:20 -0600

Converting your Time instance to values that are useful and readable is simple using the built in instance methods provided by Ruby.

2.6.1 :001 > t = Time.new
=> 2019-03-26 11:15:16 -0500
2.6.1 :002 > t.year
=> 2019
2.6.1 :003 > t.month
=> 3
2.6.1 :004 > t.day
=> 26
2.6.1 :005 > t.hour
=> 11
2.6.1 :006 > t.min
=> 15
2.6.1 :007 > t.sec
=> 16
2.6.1 :008 > t.zone
=> "CDT"
#getutc returns the time value in Coordinated Universal Time, but #doesn't alter the original value
2.6.1 :009 > t.getutc
=> 2019-03-26 16:15:16 UTC
#utc converts the original time object to Coordinated Universal Time
2.6.1 :011 > t.utc
=> 2019-03-26 16:15:16 UTC
#utc? checks if the time is in Coordinated Universal Time
2.6.1 :012 > t.utc?
=> true

A fairly complex method for returning the Time instance as a string is #strftime. Calling #strftime(string) on an instance of Time allows you to pass in a string that represents how you would like that instance of Time to be formatted as a string. A few examples are shown below, but there are many more ways of using this method. Please see the Ruby documentation for more information.

2.6.1 :002 > t
=> 2019-03-26 16:15:16 UTC
#passing in %Y, %m, %d will yield the year, month, and day values #respectively as strings 2.6.1 :003 > t.strftime('%Y')
=> "2019"
2.6.1 :004 > t.strftime('%Y-%m')
=> "2019-03"
#You are free to format the string in different ways2.6.1 :005 > t.strftime('%Y %m')
=> "2019 03"
2.6.1 :006 > t.strftime('%Y/%m/%d')
=> "2019/03/26"
#%B returns the month as the full month name2.6.1 :007 > t.strftime('%B-%Y')
=> "March-2019"

The Time class contains other instance methods that could prove useful when implementing an instance in a project.

2.6.1 :001 > t = Time.new
=> 2019-03-26 11:41:12 -0500
#dst? checks if the value is in daylight savings time
2.6.1 :002 > t.dst?
=> true
#getlocal gets the time value in the local time of the system clock
2.6.1 :004 > y = t.getutc
=> 2019-03-26 16:41:12 UTC
2.6.1 :005 > y.getlocal
=> 2019-03-26 11:41:12 -0500
#saturday? (as well as the other days of the week) returns true if #the value exists on that day of the week
2.6.1 :008 > t.saturday?
=> false
2.6.1 :009 > t.sunday?
=> false
2.6.1 :007 > t.monday?
=> false
2.6.1 :011 > t.tuesday?
=> true
2.6.1 :012 > t.wednesday?
=> false
2.6.1 :010 > t.thursday?
=> false
2.6.1 :003 > t.friday?
=> false
#wday returns the number of the day within the week (Sunday is 0)
2.6.1 :013 > t.wday
=> 2
#mday returns the number of the day within the month
2.6.1 :006 > t.mday
=> 26
#yday returns the number of the day within the year
2.6.1 :014 > t.yday
=> 85
#subsec returns the sub-second fraction for the Time instance
2.6.1 :015 > t.subsec
=> (909491/1000000)
#nsec returns the nanosecond value for the Time instance
2.6.1 :016 > t.nsec
=> 909491000

As stated before, this is no means a deep dive but I hope you feel more comfortable using Ruby’s Time class. If you’re interested in learning more, check out Ruby’s excellent documentation here.

--

--