require "../spec_helper" require "../../support/time" require "spec/helpers/string" def parse_time(format, string) Time.parse_utc(format, string) end def parse_time(string) Time.parse_utc(string, "%F %T.%N") end describe Time::Format do it "formats" do with_zoneinfo do t = Time.utc 2014, 1, 2, 3, 4, 5, nanosecond: 6_000_000 t2 = Time.utc 2014, 1, 2, 15, 4, 5, nanosecond: 6_000_000 t3 = Time.utc 2014, 1, 2, 12, 4, 5, nanosecond: 6_000_000 assert_prints t.to_s("%Y"), "2014" assert_prints Time.utc(1, 1, 2, 3, 4, 5, nanosecond: 6).to_s("%Y"), "0001" assert_prints t.to_s("%C"), "20" assert_prints t.to_s("%y"), "14" assert_prints t.to_s("%m"), "01" assert_prints t.to_s("%_m"), " 1" assert_prints t.to_s("%_%_m2"), "%_ 12" assert_prints t.to_s("%-m"), "1" assert_prints t.to_s("%-%-m2"), "%-12" assert_prints t.to_s("%B"), "January" assert_prints t.to_s("%^B"), "JANUARY" assert_prints t.to_s("%^%^B2"), "%^JANUARY2" assert_prints t.to_s("%b"), "Jan" assert_prints t.to_s("%^b"), "JAN" assert_prints t.to_s("%h"), "Jan" assert_prints t.to_s("%^h"), "JAN" assert_prints t.to_s("%d"), "02" assert_prints t.to_s("%-d"), "2" assert_prints t.to_s("%e"), " 2" assert_prints t.to_s("%j"), "002" assert_prints t.to_s("%H"), "03" assert_prints t.to_s("%k"), " 3" assert_prints t2.to_s("%k"), "15" assert_prints t.to_s("%I"), "03" assert_prints t2.to_s("%I"), "03" assert_prints t3.to_s("%I"), "12" assert_prints t.to_s("%l"), " 3" assert_prints t2.to_s("%l"), " 3" assert_prints t3.to_s("%l"), "12" # Note: we purposely match %p to am/pm and %P to AM/PM (makes more sense) assert_prints t.to_s("%p"), "am" assert_prints t2.to_s("%p"), "pm" assert_prints t.to_s("%P"), "AM" assert_prints t2.to_s("%P"), "PM" assert_prints t.to_s("%M"), "04" assert_prints t.to_s("%S"), "05" assert_prints t.to_s("%L"), "006" assert_prints t.to_s("%N"), "006000000" assert_prints t.to_s("%3N"), "006" assert_prints t.to_s("%6N"), "006000" assert_prints t.to_s("%9N"), "006000000" assert_prints t.to_s("%z"), "+0000" assert_prints t.to_s("%:z"), "+00:00" assert_prints t.to_s("%::z"), "+00:00:00" assert_prints t.to_s("%^Z"), "UTC" assert_prints t.to_s("%Z"), "UTC" with_zoneinfo do zoned = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.load("Europe/Berlin")) assert_prints zoned.to_s("%z"), "+0100" assert_prints zoned.to_s("%:z"), "+01:00" assert_prints zoned.to_s("%::z"), "+01:00:00" assert_prints zoned.to_s("%^Z"), "CET" assert_prints zoned.to_s("%Z"), "Europe/Berlin" zoned = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.load("America/Argentina/Buenos_Aires")) assert_prints zoned.to_s("%z"), "-0300" assert_prints zoned.to_s("%:z"), "-03:00" assert_prints zoned.to_s("%::z"), "-03:00:00" assert_prints zoned.to_s("%^Z"), "-03" assert_prints zoned.to_s("%Z"), "America/Argentina/Buenos_Aires" end offset = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.fixed(9000)) assert_prints offset.to_s("%z"), "+0230" assert_prints offset.to_s("%:z"), "+02:30" assert_prints offset.to_s("%::z"), "+02:30:00" assert_prints offset.to_s("%^Z"), "+02:30" assert_prints offset.to_s("%Z"), "+02:30" offset = Time.local(2017, 11, 24, 13, 5, 6, location: Time::Location.fixed(9001)) assert_prints offset.to_s("%z"), "+0230" assert_prints offset.to_s("%:z"), "+02:30" assert_prints offset.to_s("%::z"), "+02:30:01" assert_prints offset.to_s("%^Z"), "+02:30:01" assert_prints offset.to_s("%Z"), "+02:30:01" assert_prints t.to_s("%A"), "Thursday" assert_prints t.to_s("%^A"), "THURSDAY" assert_prints t.to_s("%a"), "Thu" assert_prints t.to_s("%^a"), "THU" assert_prints t.to_s("%u"), "4" assert_prints t.to_s("%w"), "4" t4 = Time.utc 2014, 1, 5 # A Sunday assert_prints t4.to_s("%u"), "7" assert_prints t4.to_s("%w"), "0" assert_prints Time.utc(1985, 4, 12).to_s("%G-W%V-%u"), "1985-W15-5" assert_prints Time.utc(2005, 1, 1).to_s("%G-W%V-%u"), "2004-W53-6" assert_prints Time.utc(2005, 1, 2).to_s("%G-W%V-%u"), "2004-W53-7" assert_prints Time.utc(2005, 12, 31).to_s("%G-W%V-%u"), "2005-W52-6" assert_prints Time.utc(2006, 1, 1).to_s("%G-W%V-%u"), "2005-W52-7" assert_prints Time.utc(2006, 1, 2).to_s("%G-W%V-%u"), "2006-W01-1" assert_prints Time.utc(2006, 12, 31).to_s("%G-W%V-%u"), "2006-W52-7" assert_prints Time.utc(2007, 1, 1).to_s("%G-W%V-%u"), "2007-W01-1" assert_prints Time.utc(2007, 12, 30).to_s("%G-W%V-%u"), "2007-W52-7" assert_prints Time.utc(2007, 12, 31).to_s("%G-W%V-%u"), "2008-W01-1" assert_prints Time.utc(2008, 1, 1).to_s("%G-W%V-%u"), "2008-W01-2" assert_prints Time.utc(2008, 12, 28).to_s("%G-W%V-%u"), "2008-W52-7" assert_prints Time.utc(2008, 12, 29).to_s("%G-W%V-%u"), "2009-W01-1" assert_prints Time.utc(2008, 12, 30).to_s("%G-W%V-%u"), "2009-W01-2" assert_prints Time.utc(2008, 12, 31).to_s("%G-W%V-%u"), "2009-W01-3" assert_prints Time.utc(2009, 1, 1).to_s("%G-W%V-%u"), "2009-W01-4" assert_prints Time.utc(2009, 12, 31).to_s("%G-W%V-%u"), "2009-W53-4" assert_prints Time.utc(2010, 1, 1).to_s("%G-W%V-%u"), "2009-W53-5" assert_prints Time.utc(2010, 1, 2).to_s("%G-W%V-%u"), "2009-W53-6" assert_prints Time.utc(2010, 1, 3).to_s("%G-W%V-%u"), "2009-W53-7" assert_prints Time.utc(1985, 4, 12).to_s("%g-W%V-%u"), "85-W15-5" # TODO %U # TODO %W # TODO %s assert_prints t.to_s("%n"), "\n" assert_prints t.to_s("%t"), "\t" # TODO %% assert_prints t.to_s("%%"), "%" assert_prints t.to_s("%c"), t.to_s("%a %b %e %T %Y") assert_prints t.to_s("%D"), t.to_s("%m/%d/%y") assert_prints t.to_s("%F"), t.to_s("%Y-%m-%d") # TODO %v assert_prints t.to_s("%x"), t.to_s("%D") assert_prints t.to_s("%X"), t.to_s("%T") assert_prints t.to_s("%r"), t.to_s("%I:%M:%S %P") assert_prints t.to_s("%R"), t.to_s("%H:%M") assert_prints t.to_s("%T"), t.to_s("%H:%M:%S") assert_prints t.to_s("%Y-%m-hello"), "2014-01-hello" t5 = Time.utc 2014, 1, 2, 3, 4, 5, nanosecond: 6 assert_prints t5.to_s("%s"), "1388631845" end end it "formats standard formats" do time = Time.utc(2016, 2, 15) assert_prints time.to_rfc3339, "2016-02-15T00:00:00Z" Time.parse_rfc3339(time.to_rfc3339).should eq time assert_prints time.to_rfc2822, "Mon, 15 Feb 2016 00:00:00 +0000" Time.parse_rfc2822(time.to_rfc2822).should eq time end it "formats rfc3339 with different fraction digits" do time = Time.utc(2016, 2, 15, 8, 23, 45, nanosecond: 123456789) assert_prints time.to_rfc3339, "2016-02-15T08:23:45Z" assert_prints time.to_rfc3339(fraction_digits: 0), "2016-02-15T08:23:45Z" assert_prints time.to_rfc3339(fraction_digits: 3), "2016-02-15T08:23:45.123Z" assert_prints time.to_rfc3339(fraction_digits: 6), "2016-02-15T08:23:45.123456Z" assert_prints time.to_rfc3339(fraction_digits: 9), "2016-02-15T08:23:45.123456789Z" expect_raises(ArgumentError, "Invalid fraction digits: 5") { time.to_rfc3339(fraction_digits: 5) } expect_raises(ArgumentError, "Invalid fraction digits: -1") { time.to_rfc3339(fraction_digits: -1) } time = Time.utc(2016, 2, 15, 8, 23, 45) assert_prints time.to_rfc3339, "2016-02-15T08:23:45Z" assert_prints time.to_rfc3339(fraction_digits: 0), "2016-02-15T08:23:45Z" assert_prints time.to_rfc3339(fraction_digits: 3), "2016-02-15T08:23:45.000Z" assert_prints time.to_rfc3339(fraction_digits: 6), "2016-02-15T08:23:45.000000Z" assert_prints time.to_rfc3339(fraction_digits: 9), "2016-02-15T08:23:45.000000000Z" end it "parses empty" do t = Time.parse("", "", Time::Location.local) t.year.should eq(1) t.month.should eq(1) t.day.should eq(1) t.hour.should eq(0) t.minute.should eq(0) t.second.should eq(0) t.millisecond.should eq(0) t.local?.should be_true end it "parse fails without time zone" do expect_raises(Time::Format::Error, "no default location provided") do Time.parse!("2017-12-01 20:15:13", "%F %T") end Time.parse("2017-12-01 20:15:13", "%F %T", Time::Location.local).to_s("%F %T").should eq "2017-12-01 20:15:13" Time.parse!("2017-12-01 20:15:13 +01:00", "%F %T %:z").to_s("%F %T %:z").should eq "2017-12-01 20:15:13 +01:00" end it "gives nice error message when end of input is reached (#12047)" do expect_raises(Time::Format::Error, "Expected '-' but the end of the input was reached") do Time.parse!("2021-01", "%F") end end it "parses" do parse_time("2014", "%Y").year.should eq(2014) parse_time("19", "%C").year.should eq(1900) parse_time("14", "%y").year.should eq(2014) parse_time("09", "%m").month.should eq(9) parse_time(" 9", "%_m").month.should eq(9) parse_time("9", "%-m").month.should eq(9) parse_time("February", "%B").month.should eq(2) parse_time("March", "%B").month.should eq(3) parse_time("MaRcH", "%B").month.should eq(3) parse_time("MaR", "%B").month.should eq(3) parse_time("MARCH", "%^B").month.should eq(3) parse_time("Mar", "%b").month.should eq(3) parse_time("Mar", "%^b").month.should eq(3) parse_time("MAR", "%^b").month.should eq(3) parse_time("MAR", "%h").month.should eq(3) parse_time("MAR", "%^h").month.should eq(3) parse_time("2", "%d").day.should eq(2) parse_time("02", "%d").day.should eq(2) parse_time("02", "%-d").day.should eq(2) parse_time(" 2", "%e").day.should eq(2) parse_time("9", "%H").hour.should eq(9) parse_time(" 9", "%k").hour.should eq(9) parse_time("09", "%I").hour.should eq(9) parse_time(" 9", "%l").hour.should eq(9) parse_time("9pm", "%l%p").hour.should eq(21) parse_time("9PM", "%l%P").hour.should eq(21) parse_time("12PM", "%l%P").hour.should eq(12) parse_time("9am", "%l%p").hour.should eq(9) parse_time("9AM", "%l%P").hour.should eq(9) parse_time("12AM", "%l%P").hour.should eq(0) parse_time("09", "%M").minute.should eq(9) parse_time("09", "%S").second.should eq(9) parse_time("123", "%L").millisecond.should eq(123) parse_time("1", "%L").millisecond.should eq(100) parse_time("000000321", "%N").nanosecond.should eq(321) parse_time("321", "%N").nanosecond.should eq(321000000) parse_time("321999", "%3N").nanosecond.should eq(321000000) parse_time("321", "%6N").nanosecond.should eq(321000000) parse_time("000321999", "%6N").nanosecond.should eq(321000) parse_time("000000321999", "%9N").nanosecond.should eq(321) parse_time("321", "%9N").nanosecond.should eq(321000000) parse_time("3214569879999", "%N").nanosecond.should eq(321456987) parse_time("Fri Oct 31 23:00:24 2014", "%c").to_s.should eq("2014-10-31 23:00:24 UTC") parse_time("10/31/14", "%D").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("10/31/69", "%D").to_s.should eq("1969-10-31 00:00:00 UTC") parse_time("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("2014-10-31", "%F").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("10/31/14", "%x").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("10:11:12", "%X").to_s.should eq("0001-01-01 10:11:12 UTC") parse_time("11:14:01 PM", "%r").to_s.should eq("0001-01-01 23:14:01 UTC") parse_time("11:14", "%R").to_s.should eq("0001-01-01 11:14:00 UTC") parse_time("11:12:13", "%T").to_s.should eq("0001-01-01 11:12:13 UTC") parse_time("This was done on Friday, October 31, 2014", "This was done on %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("今は Friday, October 31, 2014", "今は %A, %B %d, %Y").to_s.should eq("2014-10-31 00:00:00 UTC") parse_time("epoch: 1459864667", "epoch: %s").to_unix.should eq(1459864667) parse_time("epoch: -1459864667", "epoch: %s").to_unix.should eq(-1459864667) parse_time("1985-W15-5", "%G-W%V-%u").should eq(Time.utc(1985, 4, 12)) parse_time("2004-W53-6", "%G-W%V-%u").should eq(Time.utc(2005, 1, 1)) parse_time("2004-W53-7", "%G-W%V-%u").should eq(Time.utc(2005, 1, 2)) parse_time("2005-W52-6", "%G-W%V-%u").should eq(Time.utc(2005, 12, 31)) parse_time("2005-W52-7", "%G-W%V-%u").should eq(Time.utc(2006, 1, 1)) parse_time("2006-W01-1", "%G-W%V-%u").should eq(Time.utc(2006, 1, 2)) parse_time("2006-W52-7", "%G-W%V-%u").should eq(Time.utc(2006, 12, 31)) parse_time("2007-W01-1", "%G-W%V-%u").should eq(Time.utc(2007, 1, 1)) parse_time("2007-W52-7", "%G-W%V-%u").should eq(Time.utc(2007, 12, 30)) parse_time("2008-W01-1", "%G-W%V-%u").should eq(Time.utc(2007, 12, 31)) parse_time("2008-W01-2", "%G-W%V-%u").should eq(Time.utc(2008, 1, 1)) parse_time("2008-W52-7", "%G-W%V-%u").should eq(Time.utc(2008, 12, 28)) parse_time("2009-W01-1", "%G-W%V-%u").should eq(Time.utc(2008, 12, 29)) parse_time("2009-W01-2", "%G-W%V-%u").should eq(Time.utc(2008, 12, 30)) parse_time("2009-W01-3", "%G-W%V-%u").should eq(Time.utc(2008, 12, 31)) parse_time("2009-W01-4", "%G-W%V-%u").should eq(Time.utc(2009, 1, 1)) parse_time("2009-W53-4", "%G-W%V-%u").should eq(Time.utc(2009, 12, 31)) parse_time("2009-W53-5", "%G-W%V-%u").should eq(Time.utc(2010, 1, 1)) parse_time("2009-W53-6", "%G-W%V-%u").should eq(Time.utc(2010, 1, 2)) parse_time("2009-W53-7", "%G-W%V-%u").should eq(Time.utc(2010, 1, 3)) end it "parses am/pm" do parse_time("12:00 am", "%I:%M %P").to_s("%H:%M").should eq("00:00") parse_time("12:01 am", "%I:%M %P").to_s("%H:%M").should eq("00:01") parse_time("01:00 am", "%I:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 am", "%I:%M %P").to_s("%H:%M").should eq("11:00") parse_time("00:00 pm", "%I:%M %P").to_s("%H:%M").should eq("12:00") parse_time("00:01 pm", "%I:%M %P").to_s("%H:%M").should eq("12:01") parse_time("12:00 pm", "%I:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 pm", "%I:%M %P").to_s("%H:%M").should eq("12:01") parse_time("01:00 pm", "%I:%M %P").to_s("%H:%M").should eq("13:00") parse_time("11:00 pm", "%I:%M %P").to_s("%H:%M").should eq("23:00") expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("00:00 am", "%I:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("00:01 am", "%I:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00 am", "%I:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00 pm", "%I:%M %P") end parse_time("12:00", "%I:%M").to_s("%H:%M").should eq("00:00") parse_time("12:01", "%I:%M").to_s("%H:%M").should eq("00:01") parse_time("01:00", "%I:%M").to_s("%H:%M").should eq("01:00") parse_time("11:00", "%I:%M").to_s("%H:%M").should eq("11:00") expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("00:00", "%I:%M") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("00:01", "%I:%M") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00", "%I:%M") end parse_time("12:00 am", "%l:%M %P").to_s("%H:%M").should eq("00:00") parse_time("12:01 am", "%l:%M %P").to_s("%H:%M").should eq("00:01") parse_time(" 1:00 am", "%l:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 am", "%l:%M %P").to_s("%H:%M").should eq("11:00") parse_time(" 0:00 pm", "%l:%M %P").to_s("%H:%M").should eq("12:00") parse_time(" 0:01 pm", "%l:%M %P").to_s("%H:%M").should eq("12:01") parse_time("12:00 pm", "%l:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 pm", "%l:%M %P").to_s("%H:%M").should eq("12:01") parse_time(" 1:00 pm", "%l:%M %P").to_s("%H:%M").should eq("13:00") parse_time("11:00 pm", "%l:%M %P").to_s("%H:%M").should eq("23:00") expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time(" 0:00 am", "%l:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time(" 0:01 am", "%l:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00 am", "%l:%M %P") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00 pm", "%l:%M %P") end parse_time("12:00", "%l:%M").to_s("%H:%M").should eq("00:00") parse_time("12:01", "%l:%M").to_s("%H:%M").should eq("00:01") parse_time("01:00", "%l:%M").to_s("%H:%M").should eq("01:00") parse_time("11:00", "%l:%M").to_s("%H:%M").should eq("11:00") expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time(" 0:00", "%l:%M") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time(" 0:01", "%l:%M") end expect_raises Time::Format::Error, "Invalid hour for 12-hour clock" do parse_time("13:00", "%l:%M") end end it "parses 24h clock" do parse_time("00:00", "%H:%M").to_s("%H:%M").should eq("00:00") parse_time("00:01", "%H:%M").to_s("%H:%M").should eq("00:01") parse_time("01:00", "%H:%M").to_s("%H:%M").should eq("01:00") parse_time("11:00", "%H:%M").to_s("%H:%M").should eq("11:00") parse_time("12:00", "%H:%M").to_s("%H:%M").should eq("12:00") parse_time("12:01", "%H:%M").to_s("%H:%M").should eq("12:01") parse_time("13:00", "%H:%M").to_s("%H:%M").should eq("13:00") parse_time("23:00", "%H:%M").to_s("%H:%M").should eq("23:00") parse_time("24:00", "%H:%M").to_s("%H:%M").should eq("00:00") parse_time("2020-05-21 24:00", "%F %H:%M").should eq(Time.utc(2020, 5, 22, 0, 0)) parse_time(" 0:00", "%k:%M").to_s("%H:%M").should eq("00:00") parse_time(" 0:01", "%k:%M").to_s("%H:%M").should eq("00:01") parse_time(" 1:00", "%k:%M").to_s("%H:%M").should eq("01:00") parse_time("11:00", "%k:%M").to_s("%H:%M").should eq("11:00") parse_time("12:00", "%k:%M").to_s("%H:%M").should eq("12:00") parse_time("12:01", "%k:%M").to_s("%H:%M").should eq("12:01") parse_time("13:00", "%k:%M").to_s("%H:%M").should eq("13:00") parse_time("23:00", "%k:%M").to_s("%H:%M").should eq("23:00") parse_time("24:00", "%k:%M").to_s("%H:%M").should eq("00:00") parse_time("2020-05-21 24:00", "%F %k:%M").should eq(Time.utc(2020, 5, 22, 0, 0)) end it "parses 24h clock with am/pm" do parse_time("00:00 AM", "%H:%M %P").to_s("%H:%M").should eq("00:00") parse_time("00:01 AM", "%H:%M %P").to_s("%H:%M").should eq("00:01") parse_time("01:00 AM", "%H:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 AM", "%H:%M %P").to_s("%H:%M").should eq("11:00") parse_time("12:00 AM", "%H:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 AM", "%H:%M %P").to_s("%H:%M").should eq("12:01") parse_time("13:00 AM", "%H:%M %P").to_s("%H:%M").should eq("13:00") parse_time("23:00 AM", "%H:%M %P").to_s("%H:%M").should eq("23:00") parse_time("24:00 AM", "%H:%M %P").to_s("%H:%M").should eq("00:00") parse_time(" 0:00 AM", "%k:%M %P").to_s("%H:%M").should eq("00:00") parse_time(" 0:01 AM", "%k:%M %P").to_s("%H:%M").should eq("00:01") parse_time(" 1:00 AM", "%k:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 AM", "%k:%M %P").to_s("%H:%M").should eq("11:00") parse_time("12:00 AM", "%k:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 AM", "%k:%M %P").to_s("%H:%M").should eq("12:01") parse_time("13:00 AM", "%k:%M %P").to_s("%H:%M").should eq("13:00") parse_time("23:00 AM", "%k:%M %P").to_s("%H:%M").should eq("23:00") parse_time("24:00 AM", "%k:%M %P").to_s("%H:%M").should eq("00:00") parse_time("00:00 PM", "%H:%M %P").to_s("%H:%M").should eq("00:00") parse_time("00:01 PM", "%H:%M %P").to_s("%H:%M").should eq("00:01") parse_time("01:00 PM", "%H:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 PM", "%H:%M %P").to_s("%H:%M").should eq("11:00") parse_time("12:00 PM", "%H:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 PM", "%H:%M %P").to_s("%H:%M").should eq("12:01") parse_time("13:00 PM", "%H:%M %P").to_s("%H:%M").should eq("13:00") parse_time("23:00 PM", "%H:%M %P").to_s("%H:%M").should eq("23:00") parse_time("24:00 PM", "%H:%M %P").to_s("%H:%M").should eq("00:00") parse_time(" 0:00 PM", "%k:%M %P").to_s("%H:%M").should eq("00:00") parse_time(" 0:01 PM", "%k:%M %P").to_s("%H:%M").should eq("00:01") parse_time(" 1:00 PM", "%k:%M %P").to_s("%H:%M").should eq("01:00") parse_time("11:00 PM", "%k:%M %P").to_s("%H:%M").should eq("11:00") parse_time("12:00 PM", "%k:%M %P").to_s("%H:%M").should eq("12:00") parse_time("12:01 PM", "%k:%M %P").to_s("%H:%M").should eq("12:01") parse_time("13:00 PM", "%k:%M %P").to_s("%H:%M").should eq("13:00") parse_time("23:00 PM", "%k:%M %P").to_s("%H:%M").should eq("23:00") parse_time("24:00 PM", "%k:%M %P").to_s("%H:%M").should eq("00:00") end it "parses timezone" do patterns = {"%z", "%:z", "%::z"} {"+0000", "+00:00", "+00:00:00"}.zip(patterns) do |string, pattern| time = Time.parse!(string, pattern) time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true end {"-0000", "-00:00", "-00:00:00"}.zip(patterns) do |string, pattern| time = Time.parse!(string, pattern) time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true end {"-0200", "-02:00", "-02:00:00"}.zip(patterns) do |string, pattern| time = Time.parse!(string, pattern) time.offset.should eq -2 * 3600 time.utc?.should be_false time.location.fixed?.should be_true end {"Z", "Z", "Z"}.zip(patterns) do |string, pattern| time = Time.parse!(string, pattern) time.offset.should eq 0 time.utc?.should be_true time.location.fixed?.should be_true end {"UTC", "UTC", "UTC"}.zip(patterns) do |string, pattern| time = Time.parse!(string, pattern) time.offset.should eq 0 time.utc?.should be_true time.location.fixed?.should be_true end time = Time.parse!("+04:12:39", "%::z") time.offset.should eq 4 * 3600 + 12 * 60 + 39 time.utc?.should be_false time.location.fixed?.should be_true time = Time.parse!("-04:12:39", "%::z") time.offset.should eq -1 * (4 * 3600 + 12 * 60 + 39) time.utc?.should be_false time.location.fixed?.should be_true end it "parses zone name" do ["%^Z", "%Z"].each do |pattern| time = Time.parse!("UTC", pattern) time.offset.should eq 0 time.utc?.should be_true time.location.fixed?.should be_true time = Time.parse!("-00:00", pattern) time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true time = Time.parse!("+00:00", pattern) time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true time = Time.parse!("+00:00:00", pattern) time.offset.should eq 0 time.utc?.should be_false time.location.fixed?.should be_true with_zoneinfo do time = Time.parse!("CET", pattern) time.location.should eq Time::Location.load("CET") time = Time.parse!("Europe/Berlin", pattern) time.location.should eq Time::Location.load("Europe/Berlin") expect_raises(Time::Location::InvalidLocationNameError) do Time.parse!("INVALID", pattern) end end end end it "raises when time zone missing" do expect_raises(Time::Format::Error, "Invalid timezone") do Time.parse!("", "%z") end expect_raises(Time::Format::Error, "Invalid timezone") do Time.parse!("123456+01:00", "%3N%z") end end it "parses day of year" do parse_time("2006-001", "%Y-%j").should eq(Time.utc(2006, 1, 1)) parse_time("2006-032", "%Y-%j").should eq(Time.utc(2006, 2, 1)) parse_time("2006-059", "%Y-%j").should eq(Time.utc(2006, 2, 28)) parse_time("2006-060", "%Y-%j").should eq(Time.utc(2006, 3, 1)) parse_time("2006-200", "%Y-%j").should eq(Time.utc(2006, 7, 19)) parse_time("2006-365", "%Y-%j").should eq(Time.utc(2006, 12, 31)) parse_time("2004-001", "%Y-%j").should eq(Time.utc(2004, 1, 1)) parse_time("2004-032", "%Y-%j").should eq(Time.utc(2004, 2, 1)) parse_time("2004-059", "%Y-%j").should eq(Time.utc(2004, 2, 28)) parse_time("2004-060", "%Y-%j").should eq(Time.utc(2004, 2, 29)) parse_time("2004-061", "%Y-%j").should eq(Time.utc(2004, 3, 1)) parse_time("2004-200", "%Y-%j").should eq(Time.utc(2004, 7, 18)) parse_time("2004-365", "%Y-%j").should eq(Time.utc(2004, 12, 30)) parse_time("2004-366", "%Y-%j").should eq(Time.utc(2004, 12, 31)) expect_raises(Time::Format::Error, "Invalid day of year") do parse_time("2006-000", "%Y-%j") end expect_raises(Time::Format::Error, "Invalid day of year") do parse_time("2004-000", "%Y-%j") end expect_raises(Time::Format::Error, "Invalid day of year") do parse_time("2006-366", "%Y-%j") end expect_raises(Time::Format::Error, "Invalid day of year") do parse_time("2004-367", "%Y-%j") end end # TODO %Z # TODO %G # TODO %g # TODO %V # TODO %U # TODO %W # TODO %s it "parses whitespace" do [" ", "\t", "\n", "\v", "\f", "\r", "%n", "%t"].each do |space| parse_time("20250530", "%Y#{space}%m#{space}%d").should eq(Time.utc(2025, 5, 30)) parse_time("2025 05 30", "%Y#{space}%m#{space}%d").should eq(Time.utc(2025, 5, 30)) parse_time("2025 \t\n\v\f\r05 \t\n\v\f\r30", "%Y#{space}%m#{space}%d").should eq(Time.utc(2025, 5, 30)) end parse_time("20250530", "%Y \t\n\v\f\r%n%t%m \t\n\v\f\r%n%t%d").should eq(Time.utc(2025, 5, 30)) parse_time("2025 05 30", "%Y \t\n\v\f\r%n%t%m \t\n\v\f\r%n%t%d").should eq(Time.utc(2025, 5, 30)) parse_time("2025 \t\n\v\f\r05 \t\n\v\f\r30", "%Y \t\n\v\f\r%n%t%m \t\n\v\f\r%n%t%d").should eq(Time.utc(2025, 5, 30)) parse_time("Fri Oct 31 23:00:24 2014", "%c").should eq(Time.utc(2014, 10, 31, 23, 0, 24)) parse_time("Fri\tOct\n31\v23:00:24\f\r 2014", "%c").should eq(Time.utc(2014, 10, 31, 23, 0, 24)) parse_time("11:14:01PM", "%r").should eq(Time.utc(1, 1, 1, 23, 14, 1)) parse_time("11:14:01 PM", "%r").should eq(Time.utc(1, 1, 1, 23, 14, 1)) parse_time("11:14:01 \t\n\v\f\rPM", "%r").should eq(Time.utc(1, 1, 1, 23, 14, 1)) end # TODO %% # TODO %v it do time = Time.parse!("2014-10-31 10:11:12 Z hi", "%F %T %z hi") time.utc?.should be_true time.to_utc.to_s.should eq("2014-10-31 10:11:12 UTC") end it do time = Time.parse!("2014-10-31 10:11:12 UTC hi", "%F %T %z hi") time.utc?.should be_true time.to_utc.to_s.should eq("2014-10-31 10:11:12 UTC") end it do time = Time.parse!("2014-10-31 10:11:12 -06:00 hi", "%F %T %z hi") time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 time.to_utc.to_s.should eq("2014-10-31 16:11:12 UTC") end it do time = Time.parse!("2014-10-31 10:11:12 +05:00 hi", "%F %T %z hi") time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq 5 * 3600 time.to_utc.to_s.should eq("2014-10-31 05:11:12 UTC") end it do time = Time.parse!("2014-10-31 10:11:12 -06:00:00 hi", "%F %T %z hi") time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 time.to_utc.to_s.should eq("2014-10-31 16:11:12 UTC") end it do time = Time.parse!("2014-10-31 10:11:12 -060000 hi", "%F %T %z hi") time.utc?.should be_false time.location.fixed?.should be_true time.offset.should eq -6 * 3600 time.to_utc.to_s.should eq("2014-10-31 16:11:12 UTC") end it "parses centiseconds" do time = Time.parse!("2016-09-09T17:03:28.45+01:00", "%FT%T.%L%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.millisecond.should eq(450) time.nanosecond.should eq(450000000) end it "parses milliseconds with %L" do time = Time.parse!("2016-09-09T17:03:28.456+01:00", "%FT%T.%L%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.millisecond.should eq(456) time.nanosecond.should eq(456000000) end it "parses milliseconds with %3N" do time = Time.parse!("2016-09-09T17:03:28.456+01:00", "%FT%T.%3N%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.millisecond.should eq(456) time.nanosecond.should eq(456000000) end it "parses microseconds with %6N" do time = Time.parse!("2016-09-09T17:03:28.456789+01:00", "%FT%T.%6N%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.millisecond.should eq(456) time.nanosecond.should eq(456789000) end it "parses nanoseconds" do time = Time.parse!("2016-09-09T17:03:28.456789123+01:00", "%FT%T.%N%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.nanosecond.should eq(456789123) end it "parses nanoseconds with %9N" do time = Time.parse!("2016-09-09T17:03:28.456789123+01:00", "%FT%T.%9N%z").to_utc time.to_s.should eq("2016-09-09 16:03:28 UTC") time.nanosecond.should eq(456789123) end it "parses discarding additional decimals" do time = Time.parse("2016-09-09T17:03:28.456789123999", "%FT%T.%3N", Time::Location::UTC) time.nanosecond.should eq(456000000) time = Time.parse("2016-09-09T17:03:28.456789123999", "%FT%T.%6N", Time::Location::UTC) time.nanosecond.should eq(456789000) time = Time.parse("2016-09-09T17:03:28.456789123990", "%FT%T.%9N", Time::Location::UTC) time.nanosecond.should eq(456789123) time = Time.parse!("2016-09-09T17:03:28.456789123999999+01:00", "%FT%T.%N%z") time.to_s.should eq("2016-09-09 17:03:28 +01:00") time.nanosecond.should eq(456789123) time = Time.parse("4567892016-09-09T17:03:28", "%6N%FT%T", Time::Location::UTC) time.year.should eq(2016) time.nanosecond.should eq(456789000) end it "parses if some decimals are missing" do time = Time.parse!("2016-09-09T17:03:28.45+01:00", "%FT%T.%3N%z").to_utc time.nanosecond.should eq(450000000) time = Time.parse!("2016-09-09T17:03:28.45678+01:00", "%FT%T.%6N%z").to_utc time.nanosecond.should eq(456780000) time = Time.parse!("2016-09-09T17:03:28.4567891+01:00", "%FT%T.%9N%z").to_utc time.nanosecond.should eq(456789100) end it "parses the correct amount of digits (#853)" do time = Time.parse("20150624", "%Y%m%d", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(24) end it "parses month blank padded" do time = Time.parse("2015 624", "%Y%_m%d", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(24) end it "parses day of month blank padded" do time = Time.parse("201506 4", "%Y%m%e", Time::Location::UTC) time.year.should eq(2015) time.month.should eq(6) time.day.should eq(4) end it "parses hour 24 blank padded" do time = Time.parse(" 31112", "%k%M%S", Time::Location::UTC) time.hour.should eq(3) time.minute.should eq(11) time.second.should eq(12) end it "parses hour 12 blank padded" do time = Time.parse(" 31112", "%l%M%S", Time::Location::UTC) time.hour.should eq(3) time.minute.should eq(11) time.second.should eq(12) end it "can parse in location" do with_zoneinfo do time = Time.parse("2014-10-31 11:12:13", "%F %T", Time::Location::UTC) time.utc?.should be_true location = Time::Location.load("Europe/Berlin") time = Time.parse("2016-11-24 14:32:02", "%F %T", location) time.location.should eq location time = Time.parse("2016-11-24 14:32:02 +01:00", "%F %T %:z", location) time.location.should eq Time::Location.fixed(3600) end end end