Lost in Code.

Ruby’s strftime options.

I always forget which metacharacters Ruby's version of strftime accepts and what they do. Complicating this is the fact that Ruby's strftime (at least in 1.8.x) tries to be consistent with the strftime in the standard C library, but that actually varies depending on whether you're on Linux (which typically carries the GNU version of libc) or OS X (which essentially carries BSD libc). The thing I always get bit by is that compared to GNU's libc, the BSD version is kinda lame. For instance, the GNU version has a %p and %P option, whereas BSD's has only %p. Also in the GNU version, you can say e.g. %-I and that will return a version of the hour without leading zeroes or spaces, whereas with BSD's you have to go with %l, which omits a leading zero, but still leaves a leading space. To be fair, GNU actually extends strftime beyond the official standard, so there's no reason they should be in BSD, but still, once you get used to these features it's hard going back.

With that in mind I thought it would be informative to run through all the possible metacharacters on OS X and Linux, and see which ones did what. Like this:

time = Time.local(2010, 1, 1, 15, 30, 0)
chars = (("A".."Z").to_a + ("a".."z").to_a)
fmtstr = chars.map {|l| "%%#{l} = %#{l}" }.join("\n")
puts time.strftime(fmtstr)
...

And here are the results:

Char OS X Linux
%A "Friday" "Friday"
%B "January" "January"
%C "20" "20"
%D "01/01/10" "01/01/10"
%E "E" "%E"
%F "2010-01-01" "2010-01-01"
%G "2009" "2009"
%H "15" "15"
%I "03" "03"
%J "J" "%J"
%K "K" "%K"
%L "L" "%L"
%M "30" "30"
%N "N" "%N"
%O "O" "%O"
%P "P" "pm"
%Q "Q" "%Q"
%R "15:30" "15:30"
%S "00" "00"
%T "15:30:00" "15:30:00"
%U "00" "00"
%V "53" "53"
%W "00" "00"
%X "15:30:00" "15:30:00"
%Y "2010" "2010"
%Z "CST" "CST"
%a "Fri" "Fri"
%b "Jan" "Jan"
%c "Fri Jan 1 15:30:00 2010" "Fri Jan 1 15:30:00 2010"
%d "01" "01"
%e " 1" " 1"
%f "f" "%f"
%g "09" "09"
%h "Jan" "Jan"
%i "i" "%i"
%j "001" "001"
%k "15" "15"
%l " 3" " 3"
%m "01" "01"
%n "\n" "\n"
%o "o" "%o"
%p "PM" "PM"
%q "q" "%q"
%r "03:30:00 PM" "03:30:00 PM"
%s "1262381400" "1262381400"
%t "\t" "\t"
%u "5" "5"
%v " 1-Jan-2010" "%v"
%w "5" "5"
%x "01/01/10" "01/01/10"
%y "10" "10"
%z "-0500" "-0600"

Out of interest I also decided to tabulate the possible metacharacters on Linux involving the special GNU libc extensions, namely the "-", "_" and "0" prefixes. I did this like so:

time = Time.local(2010, 1, 1, 15, 30, 0)
chars = (("A".."Z").to_a + ("a".."z").to_a).map {|l| ["_#{l}", "-#{l}", "0#{l}"] }.flatten
fmtstr = chars.map {|c| "%%#{c} = %#{c}" }.join("\n")
puts time.strftime(fmtstr)
...

Here are the results (skipping the ones that don't do anything):

Char String
%_A "Friday"
%-A "Friday"
%0A "Friday"
%_B "January"
%-B "January"
%0B "January"
%_C "20"
%-C "20"
%0C "20"
%_D "01/01/10"
%-D "01/01/10"
%0D "01/01/10"
%_F "2010-01-01"
%-F "2010-01-01"
%0F "2010-01-01"
%_G "2009"
%-G "2009"
%0G "2009"
%_H "15"
%-H "15"
%0H "15"
%_I " 3"
%-I "3"
%0I "03"
%_M "30"
%-M "30"
%0M "30"
%_P "pm"
%-P "pm"
%0P "pm"
%_R "15:30"
%-R "15:30"
%0R "15:30"
%_S " 0"
%-S "0"
%0S "00"
%_T "15:30:00"
%-T "15:30:00"
%0T "15:30:00"
%_U " 0"
%-U "0"
%0U "00"
%_V "53"
%-V "53"
%0V "53"
%_W " 0"
%-W "0"
%0W "00"
%_X "15:30:00"
%-X "15:30:00"
%0X "15:30:00"
%_Y "2010"
%-Y "2010"
%0Y "2010"
%_Z "CST"
%-Z "CST"
%0Z "CST"
%_a "Fri"
%-a "Fri"
%0a "Fri"
%_b "Jan"
%-b "Jan"
%0b "Jan"
%_c "Fri Jan 1 15:30:00 2010"
%-c "Fri Jan 1 15:30:00 2010"
%0c "Fri Jan 1 15:30:00 2010"
%_d " 1"
%-d "1"
%0d "01"
%_e " 1"
%-e "1"
%0e "01"
%_g " 9"
%-g "9"
%0g "09"
%_h "Jan"
%-h "Jan"
%0h "Jan"
%_j " 1"
%-j "1"
%0j "001"
%_k "15"
%-k "15"
%0k "15"
%_l " 3"
%-l "3"
%0l "03"
%_m " 1"
%-m "1"
%0m "01"
%_n "\n"
%-n "\n"
%0n "\n"
%_p "PM"
%-p "PM"
%0p "PM"
%_r "03:30:00 PM"
%-r "03:30:00 PM"
%0r "03:30:00 PM"
%_s "1262381400"
%-s "1262381400"
%0s "1262381400"
%_t "\t"
%-t "\t"
%0t "\t"
%_u "5"
%-u "5"
%0u "5"
%_w "5"
%-w "5"
%0w "5"
%_x "01/01/10"
%-x "01/01/10"
%0x "01/01/10"
%_y "10"
%-y "10"
%0y "10"
%_z "- 600"
%-z "-600"
%0z "-0600"