3

Idiosyncratic Ruby: What the Time?

 3 years ago
source link: https://idiosyncratic-ruby.com/57-what-the-time.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

What the Time?

%a %A %b %B %c %C %d %D %e %F %g %G %h %H %I %j %k %l %L %m %M %n %N %p %P %Q %r %R %s %S %t %T %u %U %v %V %w %W %x %X %y %Y %z %Z %+ %% - _ 0 ^ # :

Date and time formatting is traditionally done with strftime. Not any different in Ruby, which includes a public domain based strftime implementation accessible via Time#strftime. Ruby would not be Ruby if it would not add some confusion: There is a second implementation included in the standard library which is used by Date#strftime and DateTime#strftime. It behaves similarly in most cases, but also differs in some nuances (for example, additional formatting directives like %Q are supported).

Usage

strftime() is called on time objects to convert them to strings:

Time.utc(2016, 05, 24, 15).strftime("%a %b %e %T %Y")
# => "Tue May 24 15:00:00 2016"

Similar to format strings or String.unpack() you have to pass a template string which contains formatting directives (like %Y for year). Many of the directives are combined directives (like %T for time), constructed from multiple base directives ("atoms"). The following tables give an overview, scroll further down for an explanation of every directive.

Atoms

Point of Time Atoms (Example) Year %Y (2016)
%C (20)
%y (16) Month %m (05) Day %d (31)
%j (365) Hour/Daytime %H (23)
%I (11)
%P (am) Minute %M (59) Second %S (59) Fraction %N (479254327)

English

Name Atoms (Example) English Month Name %B (January)
%b (Jan) English Weekday Name %A (Monday)
%a (Mon)

Week Based

Point of Time Atoms (Example) Year (by Week) %G (2016)
%g (16) Week %W (52)
%U (52)
%V (52) Weekday %u (3)
%w (3)

Other

Name Atoms (Example) Time Zone %z (+0000)
%Z (UTC) Unix Timestamp %s (1464188400) Unix Timestamp (Milliseconds)¹ %Q (1464188400)

¹ Only available in Date/DateTime's strftime() implementation

Formatting Flags and Padding

Time formatting directives support some basic padding and formatting options via flags that appear between % and the directive type. Padding is the minimum length of the output, if the value is smaller, the remaining space will be filled with spaces or zeros.

Flag Description - Do not apply default padding _ Use spaces for padding 0 Use zeros for padding ^ Upcase # Swap case

Examples:

time = Time.utc(2016, 05, 25, 15) #=> 2016-05-25 15:00:00 UTC

time.strftime("%P") # => "pm"
time.strftime("%^P") # => "PM"
time.strftime("%#P") # => "PM"
time.strftime("%10P") # =>  "        pm"
time.strftime("%010P") # => "00000000pm"
time.strftime("%_10P") # =>  "        pm"

time.strftime("%m") # => "05"
time.strftime("%-m") # => "5"
time.strftime("%10m") #=> "0000000005"
time.strftime("%010m") #=> "0000000005"
time.strftime("%_10m") #=> "         5"

Combined Directives and Aliases

Directive Alias/From Atoms %c %a %b %e %T %Y %D %m/%d/%y %e %_d %F %Y-%m-%d %h %b %k %_H %l %_I %L %3N %n "\n" %p %^P %r %I:%M:%S %p %R %H:%M %t "\t" %T %H:%M:%S %v Time#strftime: %e-%^b-%4Y
Date#strftime: %e-%b-%4Y %x %m/%d/%y %X %H:%M:%S %+¹ %a %b %e %H:%M:%S %Z %Y

¹ Only available in Date/DateTime's strftime() implementation

Years Directives

%Y | Year, with Century

Will display the time's year with a default padding of 4:

Time.utc(2016).strftime("%Y") # => "2016"
Time.utc(20000).strftime("%Y") # => "20000"
Time.utc(2).strftime("%Y") # => "0002"
Time.utc(2).strftime("%-Y") # => "2"

%y | Year, without Century

Will display the time's year modulo 100 with a default padding of 2:

Time.utc(2016).strftime("%y") # => "16"
Time.utc(20000).strftime("%y") # => "00"
Time.utc(2).strftime("%y") # => "02"
Time.utc(2).strftime("%-y") # => "2"

%C | Century

Will display the time's year divided by 100 with a default padding of 2:

Time.utc(2016).strftime("%C") # => "20"
Time.utc(20000).strftime("%C") # => "000"
Time.utc(2).strftime("%C") # => "00"
Time.utc(2).strftime("%-C") # => "0"

%G | Year (Week based), with Century

Returns the year based on which year the time's week belongs to:

Time.utc(2014, 12, 29).strftime("%G") # => "2015"
Time.utc(2017, 1, 1).strftime("%G") #=> "2016"

%g | Year (Week based), without Century

Returns the year based on which year the time's week belongs to:

Time.utc(2014, 12, 29).strftime("%g") # => "15"
Time.utc(2017, 1, 1).strftime("%g") #=> "16"

Months Directives

%m | Month as Number

Number of month, with a default padding of 2:

Time.utc(2016, 5).strftime("%m") # => "05"
Time.utc(2016, 5).strftime("%-m") # => "5"

%B | Month Name

Locale-independent (English) month name:

Time.utc(2016, 1).strftime("%B") # => "January"

%b, %h | Month Name (Abbreviated)

Locale-independent (English) three-letter month name:

Time.utc(2016, 1).strftime("%b") # => "Jan"
Time.utc(2016, 1).strftime("%h") # => "Jan"

Weeks Directives

See ISO 8601 for an explanation of week number construction.

%U | Week Number (Sunday Starts Week) | 00..53

Considers Sunday the first day of the week. Will return 00 if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%U") # => "00" # Thursday
Time.utc(2016, 1, 1).strftime("%U") # => "00" # Friday
Time.utc(2017, 1, 1).strftime("%U") # => "01" # Sunday

%V | Week Number (Week Based Year) | 01..53

Considers Sunday the first day of the week. Will return last years week number if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%V") # => "01" # Thursday
Time.utc(2016, 1, 1).strftime("%V") # => "53" # Friday
Time.utc(2017, 1, 1).strftime("%V") # => "52" # Sunday

%W | Week Number (Monday Starts Weeks) | 00..53

Considers Sunday the last day of the week. Will return 00 if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%W") # => "00" # Thursday
Time.utc(2016, 1, 1).strftime("%W") # => "00" # Friday
Time.utc(2017, 1, 1).strftime("%W") # => "00" # Sunday

Days Directives

%j | Day of Year | 001..366

Which day of the year with a default padding of 3:

Time.utc(2016, 5, 24).strftime("%j") # => "145"
Time.utc(2016, 1, 1).strftime("%j") # => "001"
Time.utc(2016, 1, 1).strftime("%-j") # => "1"

%d | Day of Month | 01..31

Which day of the month with a default (zero) padding of 2:

Time.utc(2016, 5, 24).strftime("%d") # => "24"
Time.utc(2016, 1, 1).strftime("%d") # => "01"
Time.utc(2016, 1, 1).strftime("%-d") # => "1"

%e | Day of Month (Space Padded) | 01..31

Which day of the month with a default (space) padding of 2:

Time.utc(2016, 5, 24).strftime("%e") # => "24"
Time.utc(2016, 1, 1).strftime("%e") # => " 1"
Time.utc(2016, 1, 1).strftime("%-e") # => "1"

%u | Weekday as Number (Monday Starts Week) | 1..7

Number of day in the week, value of Sunday is 7:

Time.utc(2016, 5, 22).strftime("%u") # => 7 # Sunday
Time.utc(2016, 5, 23).strftime("%u") # => 1 # Monday
Time.utc(2016, 5, 24).strftime("%u") # => 2 # Tuesday
Time.utc(2016, 5, 25).strftime("%u") # => 3 # Wednesday
Time.utc(2016, 5, 26).strftime("%u") # => 4 # Thursday
Time.utc(2016, 5, 27).strftime("%u") # => 5 # Friday
Time.utc(2016, 5, 28).strftime("%u") # => 6 # Saturday

%w | Weekday as Number (Sunday Starts Week) | 0..6

Number of day in the week, value of Sunday is 0:

Time.utc(2016, 5, 22).strftime("%u") # => 0 # Sunday
Time.utc(2016, 5, 23).strftime("%u") # => 1 # Monday
Time.utc(2016, 5, 24).strftime("%u") # => 2 # Tuesday
Time.utc(2016, 5, 25).strftime("%u") # => 3 # Wednesday
Time.utc(2016, 5, 26).strftime("%u") # => 4 # Thursday
Time.utc(2016, 5, 27).strftime("%u") # => 5 # Friday
Time.utc(2016, 5, 28).strftime("%u") # => 6 # Saturday

%A | Weekday Name

Locale-independent (English) name of weekday:

Time.utc(2016, 5, 22).strftime("%A") # => "Sunday"
Time.utc(2016, 5, 23).strftime("%A") # => "Monday"
Time.utc(2016, 5, 24).strftime("%A") # => "Tuesday"
Time.utc(2016, 5, 25).strftime("%A") # => "Wednesday"
Time.utc(2016, 5, 26).strftime("%A") # => "Thursday"
Time.utc(2016, 5, 27).strftime("%A") # => "Friday"
Time.utc(2016, 5, 28).strftime("%A") # => "Saturday"

%a | Weekday Name (Abbreviated)

Locale-independent (English) three-letter name of weekday:

Time.utc(2016, 5, 22).strftime("%a") # => "Sun"
Time.utc(2016, 5, 23).strftime("%a") # => "Mon"
Time.utc(2016, 5, 24).strftime("%a") # => "Tue"
Time.utc(2016, 5, 25).strftime("%a") # => "Wed"
Time.utc(2016, 5, 26).strftime("%a") # => "Thu"
Time.utc(2016, 5, 27).strftime("%a") # => "Fri"
Time.utc(2016, 5, 28).strftime("%a") # => "Sat"

%D, %x | Date, American

%m/%d/%y

  • Month
  • Day of Month
  • Year without Century
Time.utc(2016, 5, 24).strftime("%D") # => "05/24/16"
Time.utc(2016, 5, 24).strftime("%x") # => "05/24/16"

%F | Date, ISO 8601

%Y-%m-%d

  • Month
  • Day of Month
Time.utc(2016, 5, 24).strftime("%F") # => "2016-05-24"

%v | Date, VMS

With Time#strftime

%_d-%^b-%Y

  • Space Padded Day of Month
  • Uppercased Month Name
Time.utc(2016, 5, 24).strftime("%v") # => "24-MAY-2016"

With Date#strftime and DateTime#strftime

%_d-%b-%Y

  • Space Padded Day of Month
  • Month Name
require "date"
Time.utc(2016, 5, 24).to_date.strftime("%v") # => "24-May-2016"

Daytime Directives

%P | Meridian Indicator (Lowercase)

Returns "am" for hours between 0 and 11, returns "pm" for hours between 12 and 23:

Time.utc(2016, 5, 24, 15).strftime("%P") # => "pm"
Time.utc(2016, 5, 24, 3).strftime("%P") # => "am"

%p | Meridian Indicator (Uppercase)

Returns "AM" for hours between 0 and 11, returns "PM" for hours between 12 and 23:

Time.utc(2016, 5, 24, 15).strftime("%p") # => "PM"
Time.utc(2016, 5, 24, 3).strftime("%p") # => "AM"

Hours Directives

%H | Hour of Day, 24h (Zero Padded) | 0..23

Time's hour on the 24h clock:

Time.utc(2016, 5, 24, 15).strftime("%H") # => "15"
Time.utc(2016, 5, 24, 3).strftime("%H") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%-H") # => "3"

%k | Hour of Day, 24h (Space Padded) | 0..23

Time's hour on the 24h clock:

Time.utc(2016, 5, 24, 15).strftime("%k") # => "15"
Time.utc(2016, 5, 24, 3).strftime("%k") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%-k") # => "3"

%I | Hour of Day, 12h (Zero Padded) | 0..11

Time's hour on the 12h clock:

Time.utc(2016, 5, 24, 15).strftime("%I") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%I") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%-I") # => "3"

%l | Hour of Day, 12h (Space Padded) | 0..11

Time's hour on the 12h clock:

Time.utc(2016, 5, 24, 15).strftime("%l") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%l") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%-l") # => "3"

Minutes Directives

%M | Minute of Hour | 00..59

Time's minutes with default padding of 2:

Time.utc(2016, 5, 24, 15, 29).strftime("%M") # => "29"
Time.utc(2016, 5, 24, 15, 1).strftime("%M") # => "01"
Time.utc(2016, 5, 24, 15, 1).strftime("%-M") # => "1"

%R | Time, Hour + Minute

%H:%M

  • Hour (24h)
  • Minute
Time.utc(2016, 5, 24, 15, 29).strftime("%R") # => "15:29"

Seconds Directives

%S | Second of Minute | 00..60

Time's seconds with default padding of 2:

Time.utc(2016, 5, 24, 15, 29, 59).strftime("%S") # => "59"
Time.utc(2016, 5, 24, 15, 29, 1).strftime("%S") # => "01"
Time.utc(2016, 5, 24, 15, 29, 1).strftime("%-S") # => "1"

%s | Seconds Since Unix Epoch

Number of seconds since 1970-01-01 00:00:00 UTC. This known as Unix timestamps. It returns the same value (as string) like Time#to_i:

Time.utc(2016, 5, 24, 15, 29, 59).strftime("%s") # => "1464103799"
Time.utc(2016, 5, 24, 15, 29, 59).to_i # => 1464103799

%r | Time, Hour + Minute + Second + Daytime

%I:%M:%S %p

  • Hour (12h)
  • Minute
  • Second
  • Daytime
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%r") # => "03:29:59 PM"

%T, %X | Time, Hour + Minute + Second

%H:%M:%S

  • Hour (24h)
  • Minute
  • Second
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%T") # => "15:29:59"
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%X") # => "15:29:59"

%c | Date, Weekday + Month + Day of Month + Time + Year

%a %b %e %T %Y

  • Weekday (Short)
  • Month (Short)
  • Day of Month
  • Time (24h)
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%c") # => "Tue May 24 15:29:59 2016"

%+ | Date, date(1) Style

Only available in Date/DateTime's strftime() implementation

%a %b %e %T %Z %Y

  • Weekday (Short)
  • Month (Short)
  • Day of Month
  • Time (24h)
  • Numerical Time Zone Offset
require "date"
Time.utc(2016, 5, 24, 15, 29, 59).to_datetime.strftime("%+")
# => "Tue May 24 15:29:59 +00:00 2016"

Smaller Than Seconds Directives

%L | Millisecond | 000..999

Millisecond with default padding of 3. More precise fractions will be truncated:

Time.utc(2016, 5, 24, 15, 29, 0.1239).strftime("%L") # => "123"

%N | Fraction, Default: Nanosecond

Specifies time fractions like milliseconds (precision of 3), microseconds (precision of 6), or nanoseconds (precision of 9). More precise fractions will be truncated. Cannot be combined with padding:

Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%3N") # => "123"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%6N") # => "123456"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%9N") # => "123456789"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%N") # => "123456789"

%Q | Milliseconds Since Unix Epoch

Only available in Date/DateTime's strftime() implementation

Number of milliseconds since 1970-01-01 00:00:00 UTC:

require "date"
Time.utc(2016, 5, 24, 15, 29, 59.012).to_datetime.strftime("%Q") #=> "1464103799012"

Time Zone Directives

%z | Time Zone, Offset from UTC

A numerical time zone identifier in the format of

  • Two-digit Hour
  • Two-digit Minute

which describes the offset from UTC:

Time.utc(2016, 5, 24).strftime("%z") # => "+0000"
Time.local(2016, 5, 24).strftime("%z") # => "+0200"

The output separates hours and minutes when using a single : flag:

Time.local(2016, 5, 24).strftime("%:z") # => "+02:00"

It will also show the seconds offset when using two :: colons:

Time.local(2016, 5, 24).strftime("%::z") # => "+02:00:00"

When using :::, it will only return significant information (no zero minutes or seconds):

Time.local(2016, 5, 24).strftime("%:::z") # => "+02"

%Z | Time Zone, Abbreviated, OS Dependent

With Time#strftime

Big %Z displays a platform dependent time zone string:

Time.utc(2016, 5, 24).strftime("%Z") # => "UTC"
Time.local(2016, 5, 24).strftime("%Z") # => "CEST"

Ruby's documentation disencourages %Z, because it has a different result on different platforms and also does not properly identify the time zone:

While all directives are locale independent since Ruby 1.9, %Z is platform dependent. So, the result may differ even if the same format string is used in other systems such as C.

%z is recommended over %Z. %Z doesn’t identify the timezone. For example, "CST" is used at America/Chicago (-06:00), America/Havana (-05:00), Asia/Harbin (+08:00), Australia/Darwin (+09:30) and Australia/Adelaide (+10:30). Also, %Z is highly dependent on the operating system. For example, it may generate a non ASCII string on Japanese Windows. i.e. the result can be different to "JST". So the numeric time zone offset, %z, is recommended.

With Date#strftime and DateTime#strftime

Date's strftime() implementation outputs a numerical offset, similar to %:z:

require "date"
Time.utc(2016, 5, 24).to_datetime.strftime("%Z") # => "+00:00"
Time.local(2016, 5, 24).to_datetime.strftime("%Z") # => "+02:00"

Non Interpolating Directives

%n | Newline

Output a newline:

Time.utc(2016).strftime("%n") # => "\n"

%t | Tab

Output a tab:

Time.utc(2016).strftime("%t") # => "\t"

%% | %

A single % needs to be escaped:

Time.utc(2016).strftime("%%") # => "%"

Resources

Also See

More Idiosyncratic Ruby


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK