If you want to do anything related with time you probably want to use some sort of class that can store and work with this type of data. In this article you will learn what time-related classes and methods are available in Ruby and how to use them.
To manage time in Ruby you can use the Time
class. This class can represent a date (day/month/year) and a time (hours/minutes/seconds). This is stored by the Time
class as the number of seconds since the Epoch, also known as Unix time.
There are a few ways to initialize a Time
object. You can get an object that represents the current time using Time.new
or Time.now
.
You can also create a Time
object using an Unix timestamp and the at
method.
1 |
time = Time.at(14000000000) |
You can ask a time object for any of its components. For example, you can ask what day and month a time object is representing.
1 2 3 4 |
t = Time.now puts t.day puts t.month puts t.hour |
In addition, you can also ask if this date corresponds to a certain day of the week. For example: “Is this date a Sunday?”. These are predicate methods, meaning that they will return either true or false.
1 2 3 4 |
t = Time.now puts t.monday? puts t.sunday? puts t.friday? |
A Time
object also has a time zone associated with it, you can check the current time zone for a Time
object using the zone
method. This will give you the time zone abbreviation.
If you want the time zone offset you can use the utc_offset
method. The output for this method is in seconds, but you can divide by 3600 to get it in hours.
Example:
1 2 3 4 5 6 7 |
t = Time.now t.zone # "CET" t.utc_offset / 3600 # 1 |
The default string representation for the time & date given to you by the Ruby Time class might not be what you want. Fortunately, there is a method you can use to get almost any format you need. This method is strftime
, which basically means ‘format time’.
The way it works is by passing in a string with format specifiers, these specifiers will be replaced by a value from the time object. If you have ever used the printf
method the idea is very similar to that.
Let’s see some examples:
1 2 3 4 5 6 7 |
time = Time.new time.strftime("%d/%m/%Y") # "05/12/2015" time.strftime("%k:%M") # "17:48" time.strftime("Today is %A") # "Today is Sunday" time.strftime("%d of %B, %Y") # "21 of December, 2015" time.strftime("Unix time is %s") # "Unix time is 1449336630" |
As you can see, this method is very flexible. You can find more info on the different formats available on the following links:
Sometimes you don’t want the current time, but a time in the future or the past. You can do addition with time objects. Remember that the internal representation for Time
is in seconds, so you can do this:
1 2 |
# Add ten seconds time = Time.new + 10 |
In this example you get a time object that is set 10 seconds from the current time. Then you can check if that time has passed yet.
1 |
Time.new > time |
The Date
class has no concept of minutes, seconds or hours. This class stores everything internally in terms of days. To use the Date
class you need to require 'date'
.
You can get the current date using Date.today
. Unlike time, Date.new
is not an alias for today
, so keep that in mind.
1 2 |
Date.today # Current date Date.new # Returns a negative date |
Date arithmetic is similar to the Time
class, the difference is that you add days instead of seconds.
1 |
Date.today + 1 # Adds one day |
The Date.parse
method will try to parse anything that looks like a date. It uses a simple heuristic algorithm that tries to detect the input format. Sometimes this will give unwanted results.
Examples:
1 2 3 |
Date.parse("10/10/2010") # -> 2010-10-10 Date.parse("September 3") # -> 2015-09-03 Date.parse("May I have a cup of coffee, please?") # -> 1 of May |
If you need something more strict you can use the Date.iso8601
method. An iso8601
date has the following format: year-month-day
. An ArgumentError
exception will be raised on invalid input.
You can use the Date.strptime
method and a set of format specifiers to provide your own custom input format. These are the same specifiers that you can use for strftime
.
Example:
1 |
Date.strptime("3 of September", "%d of %B") # 2015-09-03 |
The Time
class can also parse strings to turn then into Time
objects. You will need to require 'time'
to enable this functionality.
The Date
class has some constants that you may find useful. For example, there is an array with the months of the year and another with the days of the week. Months start at index 1 so you can get a direct month number -> month name
mapping.
The days start with Sunday, but you can use the rotate
method to have the week start on Monday.
1 2 |
Date::MONTHNAMES # (index 0 = nil) Date::DAYNAMES.rotate(1) |
The DateTime
class is a subclass of Date
and it can store seconds in addition to dates. Both Time
and DateTime
can get the same job done, with the main difference being that Time
is implemented in C
, so it will be faster.
If you have used rails you are probably familiar with things like 3.days.ago
. These methods are not available in pure Ruby, they are added by the ActiveSupport
component of Rails.
Here you can find some examples, notice how these methods don’t return Time
or Date
objects, but a custom ActiveSupport
class.
1 2 3 4 |
1.hour.to_i # 3600 1.day # ActiveSupport::Duration 3.days.ago # ActiveSupport::TimeWithZone |
The code for these methods is actually pretty simple, you should take a look. The source code for TimeWithZone is also worth taking a look at.