Time is a class in Ruby that helps you represent a specific point in time.
After reading this article you’ll learn everything you need to know to become a Ruby time wizard!
Topics covered:
- How to convert strings into time objects
- How to break down a time into components (day/hours/milliseconds…)
- How to use the
Date
,DateTime
&Time
classes in Ruby - How to format time in any way you want
- How to find the difference between two
Time
objects
Let’s do this!
The Ruby Time Class
You can use the Time
class in Ruby to represent a time & date.
This date has three components:
- day
- month
- year
And time:
- hours
- minutes
- seconds
This information 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.now
- You can create a
Time
object using an Unix timestamp & theat
method - You can give the starting date in numbers to
Time.new
(format: year/month/day)
Like this:
Time.now # 2018-10-19 15:43:20 +0200 Time.new(2018, 1, 1) # 2018-01-01 00:00:00 +0100 Time.at(15000000000) # 2017-07-14 04:40:00 +0200
You can ask a time object for any of its components.
For example…
You can ask what day, month or hour a time object is representing:
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, they will return either true
or false
.
Example:
t = Time.now puts t.monday? puts t.sunday? puts t.friday?
Give it a try!
Time Zones
A Time
object 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:
t = Time.now t.zone # "CET" t.utc_offset / 3600 # 1
You can also get the current time in UTC:
Time.now.utc
Ruby Time Formatting
Ruby formats Time
objects in a specific way by default.
But you may want something else.
Something that adapts to your use case.
Good news!
You can use a method to get almost any format you need.
This method is strftime
, which basically means ‘format time’.
It works by passing a string with format specifiers, these specifiers will be replaced by a value. If you have ever used the printf
method the idea is very similar to that.
Let’s see some examples:
time = Time.new time.strftime("%d/%m/%Y") # "05/12/2015" time.strftime("%k:%M") # "17:48" time.strftime("%I:%M %p") # "11:04 PM" 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 get the time without the date, or a nicely formatted date with the year, day & name of the current month.
Strftime Format Table
Format | Description |
---|---|
%d | Day of the month (01..31) |
%m | Month of the year (01..12) Use %-m for (1..12) |
%k | Hour (0..23) |
%M | Minutes |
%S | Seconds (00..60) |
%I | Hour (1..12) |
%p | AM/PM |
%Y | Year |
%A | Day of the week (name) |
%B | Month (name) |
You can find more info on the different formats available on the following links:
Generating a Timestamp
You can generate a time-zone independent timestamp to date specific events.
Here’s how:
Time.now.to_i # 1549054305
This timestamp is a number of seconds in UTC (Coordinated Universal Time).
Time Difference (Addition & Subtraction)
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:
# 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.
Time.new > time
If you want to get something like yesterday’s day then you will need to calculate how many seconds there are in a day.
Like this:
# seconds * minutes * hours 60 * 60 * 24 # 86400
Now with this number we can sustract that from the current date:
Time.now - 86400
If you are using Rails then you can do this:
Time.now - 1.day
The Date Class
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.
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.
Date.today + 1 # Adds one day
A Date
doesn’t know anything about hours, seconds or minutes, so only use this class if you don’t need these.
Date & Time Parsing
The Date.parse
method will try to parse any string 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:
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.
Example:
Date.iso8601("2018-10-01")
You can use the Date.strptime
method & a set of format specifiers to provide your own custom input format. These are the same specifiers that you can use for strftime
.
Example:
Date.strptime("3 of September", "%d of %B") # 2015-09-03
You can parse time using the Time
class.
In other words:
How to convert a string like ‘2018-01-01 00:00’ into a Time object!
Here’s an example:
require 'time' Time.parse("September 20 18:00")
If you want to provide the format of your input string you can use the strptime
method.
Like this:
require 'time' Time.strptime("1 of December 2017", "%d of %B %Y")
The only difference between Time.parse
& Date.parse
is the kind of object that you get back (Time
or Date
).
Date Constants
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.
Date::MONTHNAMES # (index 0 = nil) Date::DAYNAMES.rotate(1)
The DateTime Class
The DateTime
class is a subclass of Date
and it can store seconds in addition to dates.
Example:
require 'date' DateTime.superclass # Date DateTime.now # DateTime: 2018-10-15T16:06:39+02:00
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.
Performance:
Comparison: Time: 2644596.6 i/s DateTime: 231634.8 i/s - 11.42x slower
ActiveSupport – Time & Date Methods
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.hour.to_i # 3600 1.day # ActiveSupport::Duration 3.days.ago # ActiveSupport::TimeWithZone
You can do time math with these & get things like tomorrow’s date:
Time.now + 1.day
Other Rails-exclusive time methods:
date = Time.current date.change(hour: 20) date.at_beginning_of_day
And for formatting:
date = Date.today date.to_formatted_s(:short) # "16 Jul" date.to_formatted_s(:long) # "July 16, 2018"
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.
Summary
In this article you learned about the Time & Date classes, how to parse & format time in Ruby, and how to use the ActiveSupport time extensions.
Thanks for reading!
I love it
Nice post