Time
The Time class provides methods for working with dates and times in Ruby. It’s part of the standard library and offers powerful date/time manipulation capabilities.
Overview
Ruby’s Time class represents dates and times:
- Create: Generate times from strings, timestamps, or components
- Parse: Convert strings into Time objects
- Manipulate: Add, subtract, and modify time values
- Format: Display times in various formats
Creating time objects
Current Time
Time.now # => 2026-03-13 14:52:00 +0000
Time.current # => Same as now, but respects Rails timezone
Time.now gives you the current system time, while Time.current is an ActiveSupport addition that respects the configured Rails time zone. Both return a Time object, but Time.current is what you should reach for inside a Rails application where time-zone awareness matters.
From string
The Time.parse method converts a string representation into a Time object. It handles several common date formats automatically, including ISO 8601 and natural-looking timestamps. When you pass only a date without a time component, the parser defaults to midnight UTC. Adding an explicit time portion gives you a full timestamp you can use for scheduling, logging, or comparison with other Time values.
Time.parse("2026-03-13")
# => 2026-03-13 00:00:00 +0000
Time.parse("2026-03-13 10:30:00")
# => 2026-03-13 10:30:00 +0000
The Time.parse examples above demonstrate parsing from string representations, but Ruby also lets you construct a Time from individual numeric components. This approach is useful when you already have separate year, month, and day values — for example, when processing user input from a form or reading structured data from a file. The constructor accepts up to seven arguments: year, month, day, hour, minute, second, and optional UTC offset.
From components
Time.new(2026, 3, 13, 14, 30, 0)
# => 2026-03-13 14:30:00 +0000
From timestamp
Time.at converts a Unix timestamp (seconds since the epoch) into a Time object. This is especially useful when you receive timestamps from APIs, databases, or log files that store time as an integer. Passing the :millisecond symbol as the second argument tells Ruby to interpret the number as milliseconds, which several modern systems use for sub-second precision. Without that argument, the value is treated as seconds.
Time.at(1700000000)
# => 2023-11-14 22:13:20 +0000
Time.at(1700000000, :millisecond)
# => 2023-11-14 22:13:20.000 +0000
Once you have a Time object, you rarely need the raw timestamp again — instead you pull out specific fields. Ruby provides accessor methods for every component you might need, from the year and month down to the second and time zone.
Time components
You can extract individual components from a Time object:
time = Time.now
time.year # => 2026
time.month # => 3
time.day # => 13
time.hour # => 14
time.min # => 52
time.sec # => 0
time.wday # => 5 (0 = Sunday)
time.yday # => 72 (day of year)
time.zone # => "UTC"
The component accessors shown above are read-only — they describe the moment but don’t modify it. Once you’ve extracted the fields you need, arithmetic and comparison methods let you derive new times from the existing one.
Time calculations
Adding and subtracting
Arithmetic on Time objects uses seconds as the unit. Adding 3600 advances the time by exactly one hour, and subtracting 86400 moves it back by exactly one day. The result is always a new Time object — Ruby never mutates the original. This second-based arithmetic is straightforward but remember that “one day” in calendar terms sometimes means 23 or 25 hours due to daylight saving shifts, so using exact second counts carries that assumption with it.
time = Time.now
time + 3600 # One hour from now
time - 86400 # One day ago
Arithmetic on Time objects returns a new Time rather than mutating the original. The result preserves the same time zone as the source, so adding or subtracting seconds is safe across zone boundaries as long as both operands are in the same zone.
Comparing times
past = Time.parse("2020-01-01")
future = Time.parse("2030-01-01")
future > past # => true
past <=> future # => -1 (past is earlier)
Ruby’s Time objects implement Comparable, which means you can use them directly with <, >, <=, >=, and between?. Sorting a collection of timestamps is as simple as calling sort on the array — no custom block is required.
Formatting times
strftime
The strftime method formats time using directives:
time = Time.now
time.strftime("%Y-%m-%d") # => "2026-03-13"
time.strftime("%H:%M:%S") # => "14:52:00"
time.strftime("%B %d, %Y") # => "March 13, 2026"
time.strftime("%d/%m/%Y") # => "13/03/2026"
time.strftime("%A") # => "Friday"
Each %-prefixed code in the format string maps to a specific component of the timestamp. You can combine them with literal characters — hyphens, slashes, colons, and spaces — to produce any layout your application needs. The full set of directives is larger than the table below, but these eight cover the vast majority of real-world formatting tasks.
| Directive | Meaning | Example |
|---|---|---|
%Y | Year | 2026 |
%m | Month (01-12) | 03 |
%d | Day | 13 |
%H | Hour (24h) | 14 |
%M | Minute | 52 |
%S | Second | 00 |
%A | Weekday | Friday |
%B | Month name | March |
The directives are case-sensitive: %m produces the month number while %M produces minutes. You can combine multiple directives with literal punctuation and spaces to build any date layout your application needs. For locale-specific month or weekday names, Ruby supports the %^ modifier on some platforms, though strftime behavior varies slightly across operating systems.
Predefined formats
time.iso8601 # => "2026-03-13T14:52:00Z"
time.rfc2822 # => "Fri, 13 Mar 2026 14:52:00 +0000"
time.xmlschema # => "2026-03-13T14:52:00Z"
These convenience methods produce well-known string formats suitable for APIs, email headers, and database interchange. iso8601 and xmlschema are aliases for each other, while rfc2822 follows the older email-standard format that includes the weekday name and an abbreviated month.
Time zones
Working with time zones
require "time"
# Parse with timezone
Time.parse("2026-03-13 10:00:00 EST")
# => 2026-03-13 10:00:00 -0500
# Get time in specific zone
Time.use_zone("Pacific Time (US & Canada)") do
Time.zone.now
end
Time.use_zone is an ActiveSupport method that temporarily overrides the application’s time zone for the duration of the block. The block’s return value is unaffected — only time-sensitive calls inside the block see the zone change. This pattern is useful for generating reports or emails in a user’s local time without permanently switching the global configuration.
Converting between zones
time = Time.now.utc
time.getlocal("-0800") # Convert to PST
time.utc # Convert to UTC
getlocal and utc both mutate the receiver in place, so if you need to preserve the original timestamp, call dup first. A common pattern is to store everything in UTC and apply the local offset only at the presentation layer — this eliminates an entire class of time-zone bugs that arise from mixing offsets in the same code path.
Practical examples
Age calculation
birthday = Time.parse("1990-06-15")
age = ((Time.now - birthday) / 365.25 / 24 / 60 / 60).to_i
# => 35
The age calculation above divides the elapsed seconds by the number of seconds in a year (using 365.25 to account for leap years). This gives a rough integer age; for exact birthday logic, you would compare month and day fields rather than relying on arithmetic alone.
Day boundaries
time = Time.now
time.beginning_of_day # => 2026-03-13 00:00:00 +0000
time.end_of_day # => 2026-03-13 23:59:59 +0000
beginning_of_day and end_of_day are ActiveSupport methods that clamp a Time to the start or end of its calendar day. They are useful for constructing inclusive date-range queries, such as finding all records created “today” by filtering with created_at: time.beginning_of_day..time.end_of_day.
Date arithmetic
require "date"
date = Date.today
next_week = date + 7
last_month = date << 1
The examples above mix Date and Time objects, which is common in real Ruby code. Date handles calendar math natively — shifting months with << and stepping weeks with + — while Time captures the precise instant. Choosing the right type for each task keeps the code clearer and prevents subtle bugs around daylight saving transitions.
These date-arithmetic examples show how the Time and Date libraries often meet in real code. One handles a precise moment, while the other keeps the calendar math simple. Keeping them separate until the last possible moment helps you avoid mixing clock time with whole-day logic by accident.
Working with time safely
Time values are more precise than dates, so they are useful for logs, scheduling, and elapsed-time measurements. When you need a true moment in time, Time is usually the right tool because it can track hours, minutes, seconds, and zone offsets together. That makes it a better fit for events that happen at a specific instant.
For duration calculations, be clear about whether you want calendar time or elapsed seconds. The distinction matters when daylight saving changes, time zones shift, or a timestamp crosses midnight. Keeping those rules explicit in the code prevents surprising results later.
It also helps to decide early whether you want an exact timestamp or a day on the calendar. A timestamp is better for logging and scheduling, while a date is easier for human-facing planning and reports. Choosing the right layer first keeps the rest of the code much easier to reason about.