Formats for Dates and Times
Several Ruby time-related classes have instance method strftime
, which returns a formatted string representing all or part of a date or time:
-
Date#strftime.
-
DateTime#strftime.
-
Time#strftime.
Each of these methods takes optional argument format
, which has zero or more embedded format specifications (see below).
Each of these methods returns the string resulting from replacing each format specification embedded in format
with a string form of one or more parts of the date or time.
A simple example:
Time.now.strftime('%H:%M:%S') # => "14:02:07"
A format specification has the form:
%[flags][width]conversion
It consists of:
-
A leading percent character.
-
Zero or more flags (each is a character).
-
An optional width specifier (an integer).
-
A conversion specifier (a character).
Except for the leading percent character, the only required part is the conversion specifier, so we begin with that.
Conversion Specifiers
Date (Year, Month, Day)
-
%Y
- Year including century, zero-padded:Time.now.strftime('%Y') # => "2022" Time.new(-1000).strftime('%Y') # => "-1000" # Before common era. Time.new(10000).strftime('%Y') # => "10000" # Far future. Time.new(10).strftime('%Y') # => "0010" # Zero-padded by default.
-
%y
- Year without century, in range (0.99), zero-padded:Time.now.strftime('%y') # => "22" Time.new(1).strftime('%y') # => "01" # Zero-padded by default.
-
%C
- Century, zero-padded:Time.now.strftime('%C') # => "20" Time.new(-1000).strftime('%C') # => "-10" # Before common era. Time.new(10000).strftime('%C') # => "100" # Far future. Time.new(100).strftime('%C') # => "01" # Zero-padded by default.
-
%m
- Month of the year, in range (1..12), zero-padded:Time.new(2022, 1).strftime('%m') # => "01" # Zero-padded by default. Time.new(2022, 12).strftime('%m') # => "12"
-
%B
- Full month name, capitalized:Time.new(2022, 1).strftime('%B') # => "January" Time.new(2022, 12).strftime('%B') # => "December"
-
%b
- Abbreviated month name, capitalized:Time.new(2022, 1).strftime('%b') # => "Jan" Time.new(2022, 12).strftime('%h') # => "Dec"
-
%h
- Same as%b
. -
%d
- Day of the month, in range (1..31), zero-padded:Time.new(2002, 1, 1).strftime('%d') # => "01" Time.new(2002, 1, 31).strftime('%d') # => "31"
-
%e
- Day of the month, in range (1..31), blank-padded:Time.new(2002, 1, 1).strftime('%e') # => " 1" Time.new(2002, 1, 31).strftime('%e') # => "31"
-
%j
- Day of the year, in range (1..366), zero-padded:Time.new(2002, 1, 1).strftime('%j') # => "001" Time.new(2002, 12, 31).strftime('%j') # => "365"
Time (Hour, Minute, Second, Subsecond)
-
%H
- Hour of the day, in range (0..23), zero-padded:Time.new(2022, 1, 1, 1).strftime('%H') # => "01" Time.new(2022, 1, 1, 13).strftime('%H') # => "13"
-
%k
- Hour of the day, in range (0..23), blank-padded:Time.new(2022, 1, 1, 1).strftime('%k') # => " 1" Time.new(2022, 1, 1, 13).strftime('%k') # => "13"
-
%I
- Hour of the day, in range (1..12), zero-padded:Time.new(2022, 1, 1, 1).strftime('%I') # => "01" Time.new(2022, 1, 1, 13).strftime('%I') # => "01"
-
%l
- Hour of the day, in range (1..12), blank-padded:Time.new(2022, 1, 1, 1).strftime('%l') # => " 1" Time.new(2022, 1, 1, 13).strftime('%l') # => " 1"
-
%P
- Meridian indicator, lowercase:Time.new(2022, 1, 1, 1).strftime('%P') # => "am" Time.new(2022, 1, 1, 13).strftime('%P') # => "pm"
-
%p
- Meridian indicator, uppercase:Time.new(2022, 1, 1, 1).strftime('%p') # => "AM" Time.new(2022, 1, 1, 13).strftime('%p') # => "PM"
-
%M
- Minute of the hour, in range (0..59), zero-padded:Time.new(2022, 1, 1, 1, 0, 0).strftime('%M') # => "00"
-
%S
- Second of the minute in range (0..59), zero-padded:Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%S') # => "00"
-
%L
- Millisecond of the second, in range (0..999), zero-padded:Time.new(2022, 1, 1, 1, 0, 0, 0).strftime('%L') # => "000"
-
%N
- Fractional seconds, default width is 9 digits (nanoseconds):t = Time.now # => 2022-06-29 07:10:20.3230914 -0500 t.strftime('%N') # => "323091400" # Default.
Use width specifiers to adjust units:
t.strftime('%3N') # => "323" # Milliseconds. t.strftime('%6N') # => "323091" # Microseconds. t.strftime('%9N') # => "323091400" # Nanoseconds. t.strftime('%12N') # => "323091400000" # Picoseconds. t.strftime('%15N') # => "323091400000000" # Femptoseconds. t.strftime('%18N') # => "323091400000000000" # Attoseconds. t.strftime('%21N') # => "323091400000000000000" # Zeptoseconds. t.strftime('%24N') # => "323091400000000000000000" # Yoctoseconds.
-
%s
- Number of seconds since the epoch:Time.now.strftime('%s') # => "1656505136"
Timezone
-
%z
- Timezone as hour and minute offset from UTC:Time.now.strftime('%z') # => "-0500"
-
%Z
- Timezone name (platform-dependent):Time.now.strftime('%Z') # => "Central Daylight Time"
Weekday
-
%A
- Full weekday name:Time.now.strftime('%A') # => "Wednesday"
-
%a
- Abbreviated weekday name:Time.now.strftime('%a') # => "Wed"
-
%u
- Day of the week, in range (1..7), Monday is 1:t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500 t.strftime('%a') # => "Sun" t.strftime('%u') # => "7"
-
%w
- Day of the week, in range (0..6), Sunday is 0:t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500 t.strftime('%a') # => "Sun" t.strftime('%w') # => "0"
Week Number
-
%U
- Week number of the year, in range (0..53), zero-padded, where each week begins on a Sunday:t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500 t.strftime('%a') # => "Sun" t.strftime('%U') # => "26"
-
%W
- Week number of the year, in range (0..53), zero-padded, where each week begins on a Monday:t = Time.new(2022, 6, 26) # => 2022-06-26 00:00:00 -0500 t.strftime('%a') # => "Sun" t.strftime('%W') # => "25"
Week Dates
See ISO 8601 week dates.
t0 = Time.new(2023, 1, 1) # => 2023-01-01 00:00:00 -0600
t1 = Time.new(2024, 1, 1) # => 2024-01-01 00:00:00 -0600
-
%G
- Week-based year:t0.strftime('%G') # => "2022" t1.strftime('%G') # => "2024"
-
%g
- Week-based year without century, in range (0..99), zero-padded:t0.strftime('%g') # => "22" t1.strftime('%g') # => "24"
-
%V
- Week number of the week-based year, in range (1..53), zero-padded:t0.strftime('%V') # => "52" t1.strftime('%V') # => "01"
Literals
-
%n
- Newline character “n”:Time.now.strftime('%n') # => "\n"
-
%t
- Tab character “t”:Time.now.strftime('%t') # => "\t"
-
%%
- Percent character ‘%’:Time.now.strftime('%%') # => "%"
Shorthand Conversion Specifiers
Each shorthand specifier here is shown with its corresponding longhand specifier.
-
%c
- Date and time:Time.now.strftime('%c') # => "Wed Jun 29 08:01:41 2022" Time.now.strftime('%a %b %e %T %Y') # => "Wed Jun 29 08:02:07 2022"
-
%D
- Date:Time.now.strftime('%D') # => "06/29/22" Time.now.strftime('%m/%d/%y') # => "06/29/22"
-
%F
- ISO 8601 date:Time.now.strftime('%F') # => "2022-06-29" Time.now.strftime('%Y-%m-%d') # => "2022-06-29"
-
%v
- VMS date:Time.now.strftime('%v') # => "29-JUN-2022" Time.now.strftime('%e-%^b-%4Y') # => "29-JUN-2022"
-
%x
- Same as%D
. -
%X
- Same as%T
. -
%r
- 12-hour time:Time.new(2022, 1, 1, 1).strftime('%r') # => "01:00:00 AM" Time.new(2022, 1, 1, 1).strftime('%I:%M:%S %p') # => "01:00:00 AM" Time.new(2022, 1, 1, 13).strftime('%r') # => "01:00:00 PM" Time.new(2022, 1, 1, 13).strftime('%I:%M:%S %p') # => "01:00:00 PM"
-
%R
- 24-hour time:Time.new(2022, 1, 1, 1).strftime('%R') # => "01:00" Time.new(2022, 1, 1, 1).strftime('%H:%M') # => "01:00" Time.new(2022, 1, 1, 13).strftime('%R') # => "13:00" Time.new(2022, 1, 1, 13).strftime('%H:%M') # => "13:00"
-
%T
- 24-hour time:Time.new(2022, 1, 1, 1).strftime('%T') # => "01:00:00" Time.new(2022, 1, 1, 1).strftime('%H:%M:%S') # => "01:00:00" Time.new(2022, 1, 1, 13).strftime('%T') # => "13:00:00" Time.new(2022, 1, 1, 13).strftime('%H:%M:%S') # => "13:00:00"
-
%+
(not supported in Time#strftime) - Date and time:DateTime.now.strftime('%+') # => "Wed Jun 29 08:31:53 -05:00 2022" DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y') # => "Wed Jun 29 08:32:18 -05:00 2022"
Flags
Flags may affect certain formatting specifications.
Multiple flags may be given with a single conversion specified; order does not matter.
Padding Flags
-
0
- Pad with zeroes:Time.new(10).strftime('%0Y') # => "0010"
-
_
- Pad with blanks:Time.new(10).strftime('%_Y') # => " 10"
-
-
- Don’t pad:Time.new(10).strftime('%-Y') # => "10"
Casing Flags
-
^
- Upcase result:Time.new(2022, 1).strftime('%B') # => "January" # No casing flag. Time.new(2022, 1).strftime('%^B') # => "JANUARY"
-
#
- Swapcase result:Time.now.strftime('%p') # => "AM" Time.now.strftime('%^p') # => "AM" Time.now.strftime('%#p') # => "am"
Timezone Flags
-
:
- Put timezone as colon-separated hours and minutes:Time.now.strftime('%:z') # => "-05:00"
-
::
- Put timezone as colon-separated hours, minutes, and seconds:Time.now.strftime('%::z') # => "-05:00:00"
Width Specifiers
The integer width specifier gives a minimum width for the returned string:
Time.new(2002).strftime('%Y') # => "2002" # No width specifier.
Time.new(2002).strftime('%10Y') # => "0000002002"
Time.new(2002, 12).strftime('%B') # => "December" # No width specifier.
Time.new(2002, 12).strftime('%10B') # => " December"
Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
Specialized Format Strings
Here are a few specialized format strings, each based on an external standard.
HTTP Format
The HTTP date format is based on RFC 2616, and treats dates in the format '%a, %d %b %Y %T GMT'
:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
# Return HTTP-formatted string.
httpdate = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT"
# Return new date parsed from HTTP-formatted string.
Date.httpdate(httpdate) # => #<Date: 2001-02-03>
# Return hash parsed from HTTP-formatted string.
Date._httpdate(httpdate)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
RFC 3339 Format
The RFC 3339 date format is based on RFC 3339:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
# Return 3339-formatted string.
rfc3339 = d.rfc3339 # => "2001-02-03T00:00:00+00:00"
# Return new date parsed from 3339-formatted string.
Date.rfc3339(rfc3339) # => #<Date: 2001-02-03>
# Return hash parsed from 3339-formatted string.
Date._rfc3339(rfc3339)
# => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
RFC 2822 Format
The RFC 2822 date format is based on RFC 2822, and treats dates in the format '%a, %-d %b %Y %T %z'
]:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
# Return 2822-formatted string.
rfc2822 = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
# Return new date parsed from 2822-formatted string.
Date.rfc2822(rfc2822) # => #<Date: 2001-02-03>
# Return hash parsed from 2822-formatted string.
Date._rfc2822(rfc2822)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"+0000", :offset=>0}
JIS X 0301 Format
The JIS X 0301 format includes the Japanese era name, and treats dates in the format '%Y-%m-%d'
with the first letter of the romanized era name prefixed:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
# Return 0301-formatted string.
jisx0301 = d.jisx0301 # => "H13.02.03"
# Return new date parsed from 0301-formatted string.
Date.jisx0301(jisx0301) # => #<Date: 2001-02-03>
# Return hash parsed from 0301-formatted string.
Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
ISO 8601 Format Specifications
This section shows format specifications that are compatible with ISO 8601. Details for various formats may be seen at the links.
Examples in this section assume:
t = Time.now # => 2022-06-29 16:49:25.465246 -0500
Dates
See ISO 8601 dates.
-
-
Basic year (
YYYY
):t.strftime('%Y') # => "2022"
-
Expanded year (
±YYYYY
):t.strftime('+%5Y') # => "+02022" t.strftime('-%5Y') # => "-02022"
-
-
-
Basic date (
YYYYMMDD
):t.strftime('%Y%m%d') # => "20220629"
-
Extended date (
YYYY-MM-DD
):t.strftime('%Y-%m-%d') # => "2022-06-29"
-
Reduced extended date (
YYYY-MM
):t.strftime('%Y-%m') # => "2022-06"
-
-
-
Basic date (
YYYYWww
orYYYYWwwD
):t.strftime('%Y%Ww') # => "202226w" t.strftime('%Y%Ww%u') # => "202226w3"
-
Extended date (
YYYY-Www
or <tt>YYYY-Www-D<tt>):t.strftime('%Y-%Ww') # => "2022-26w" t.strftime('%Y-%Ww-%u') # => "2022-26w-3"
-
-
-
Basic date (
YYYYDDD
):t.strftime('%Y%j') # => "2022180"
-
Extended date (
YYYY-DDD
):t.strftime('%Y-%j') # => "2022-180"
-
Times
See ISO 8601 times.
-
Times:
-
Basic time (
Thhmmss.sss
,Thhmmss
,Thhmm
, orThh
):t.strftime('T%H%M%S.%L') # => "T164925.465" t.strftime('T%H%M%S') # => "T164925" t.strftime('T%H%M') # => "T1649" t.strftime('T%H') # => "T16"
-
Extended time (
Thh:mm:ss.sss
,Thh:mm:ss
, orThh:mm
):t.strftime('T%H:%M:%S.%L') # => "T16:49:25.465" t.strftime('T%H:%M:%S') # => "T16:49:25" t.strftime('T%H:%M') # => "T16:49"
-
-
-
Timezone (
time
represents a valid time,hh
represents a valid 2-digit hour, andmm
represents a valid 2-digit minute):-
Basic timezone (
time±hhmm
,time±hh
, ortimeZ
):t.strftime('T%H%M%S%z') # => "T164925-0500" t.strftime('T%H%M%S%z').slice(0..-3) # => "T164925-05" t.strftime('T%H%M%SZ') # => "T164925Z"
-
Extended timezone (
time±hh:mm
):t.strftime('T%H:%M:%S%z') # => "T16:49:25-0500"
-
-
See also:
-
Combined Date and Time
See ISO 8601 Combined date and time representations.
An ISO 8601 combined date and time representation may be any ISO 8601 date and any ISO 8601 time, separated by the letter T
.
For the relevant strftime
formats, see Dates and Times above.