require 'spec_helper' describe Timeliness::Parser do before(:all) do Timecop.freeze(2010,1,1,0,0,0) end describe "parse" do it "should return Time object for valid datetime string" do parse("2000-01-01 12:13:14").should be_kind_of(Time) end it "should return nil for empty string" do parse("").should be_nil end it "should return nil for nil value" do parse(nil).should be_nil end it "should return return same value if value not a string" do value = Time.now parse(value).should == value end it "should return time object for valid date string" do parse("2000-01-01").should be_kind_of(Time) end it "should return nil for invalid date string" do should_not_parse("2000-02-30") end it "should return nil for invalid date string where month is '0'" do should_not_parse("0/01/2000") end it "should return nil for invalid date string where month is '00'" do should_not_parse("00/01/2000") end it "should return time object for valid time string" do parse("12:13:14").should be_kind_of(Time) end it "should return nil for invalid time string" do should_not_parse("25:00:00") end it "should return nil for datetime string with invalid date part" do should_not_parse("2000-02-30 12:13:14") end it "should return nil for datetime string with invalid time part" do should_not_parse("2000-02-01 25:13:14") end context "string with zone offset value" do context "when current timezone is earler than string zone" do it 'should return value shifted by positive offset in default timezone' do value = parse("2000-06-01T12:00:00+02:00") value.should == Time.local(2000,6,1,20,0,0) value.utc_offset.should == 10.hours end it 'should return value shifted by negative offset in default timezone' do value = parse("2000-06-01T12:00:00-01:00") value.should == Time.local(2000,6,1,23,0,0) value.utc_offset.should == 10.hours end end context "when current timezone is later than string zone" do before(:all) do Timeliness.default_timezone = :current Time.zone = 'America/Phoenix' end it 'should return value shifted by positive offset in default timezone' do value = parse("2000-06-01T12:00:00+02:00") value.should == Time.zone.local(2000,6,1,3,0,0) value.utc_offset.should == -7.hours end it 'should return value shifted by negative offset in default timezone' do value = parse("2000-06-01T12:00:00-01:00") value.should == Time.zone.local(2000,6,1,6,0,0) value.utc_offset.should == -7.hours end after(:all) do Time.zone = nil Timeliness.default_timezone = :local end end end context "string with zone abbreviation" do before do Time.zone = 'Melbourne' end it 'should return value using string zone adjusted to default :local timezone' do Timeliness.default_timezone = :local value = parse("Thu, 01 Jun 2000 03:00:00 MST") value.should == Time.local(2000,6,1,20,0,0) value.utc_offset.should == 10.hours end it 'should return value using string zone adjusted to default :current timezone' do Timeliness.default_timezone = :current Time.zone = 'Adelaide' value = parse("Thu, 01 Jun 2000 03:00:00 MST") value.should == Time.zone.local(2000,6,1,19,30,0) value.utc_offset.should == 9.5.hours end it 'should return value using string zone adjusted to :zone option string timezone' do Timeliness.default_timezone = :local value = parse("Thu, 01 Jun 2000 03:00:00 MST", :zone => 'Perth') value.should == Time.use_zone('Perth') { Time.zone.local(2000,6,1,18,0,0) } value.utc_offset.should == 8.hours end after do Time.zone = nil end end context "with :datetime type" do it "should return time object for valid datetime string" do parse("2000-01-01 12:13:14", :datetime).should == Time.local(2000,1,1,12,13,14) end it "should return nil for invalid date string" do parse("0/01/2000", :datetime).should be_nil end end context "with :date type" do it "should return time object for valid date string" do parse("2000-01-01", :date).should == Time.local(2000,1,1) end it "should ignore time in datetime string" do parse('2000-02-01 12:13', :date).should == Time.local(2000,2,1) end it "should return nil for invalid date string" do parse("0/01/2000", :date).should be_nil end end context "with :time type" do it "should return time object with a dummy date values" do parse('12:13', :time).should == Time.local(2010,1,1,12,13) end it "should ignore date in datetime string" do parse('2010-02-01 12:13', :time).should == Time.local(2010,1,1,12,13) end it "should raise error if time hour is out of range for AM meridian" do parse('13:14 am', :time).should be_nil end end context "with :now option" do it 'should use date parts if string does not specify' do time = parse("12:13:14", :now => Time.local(2010,1,1)) time.should == Time.local(2010,1,1,12,13,14) end end context "with time value argument" do it 'should use argument as :now option value' do time = parse("12:13:14", Time.local(2010,1,1)) time.should == Time.local(2010,1,1,12,13,14) end end context "with :zone option" do context ":utc" do it "should return time object in utc timezone" do time = parse("2000-06-01 12:13:14", :datetime, :zone => :utc) time.utc_offset.should == 0 end it 'should return nil for partial invalid time component' do parse("2000-06-01 12:60", :datetime, :zone => :utc).should be_nil end end context ":local" do it "should return time object in local system timezone" do time = parse("2000-06-01 12:13:14", :datetime, :zone => :local) time.utc_offset.should == 10.hours end it 'should return nil for partial invalid time component' do parse("2000-06-01 12:60", :datetime, :zone => :local).should be_nil end end context ":current" do it "should return time object in current timezone" do Time.zone = 'Adelaide' time = parse("2000-06-01 12:13:14", :datetime, :zone => :current) time.utc_offset.should == 9.5.hours end it 'should return nil for partial invalid time component' do parse("2000-06-01 12:60", :datetime, :zone => :current).should be_nil end end context "named zone" do it "should return time object in the timezone" do time = parse("2000-06-01 12:13:14", :datetime, :zone => 'London') time.utc_offset.should == 1.hour end it 'should return nil for partial invalid time component' do parse("2000-06-01 12:60", :datetime, :zone => 'London').should be_nil end end context "without ActiveSupport loaded" do it 'should output message' do expect { Time.should_receive(:zone).and_raise(NoMethodError.new("undefined method `zone' for Time:Class")) parse("2000-06-01 12:13:14", :zone => :current) }.should raise_error(Timeliness::Parser::MissingTimezoneSupport) expect { Time.should_receive(:current).and_raise(NoMethodError.new("undefined method `current' for Time:Class")) parse("12:13:14", :zone => :current) }.should raise_error(Timeliness::Parser::MissingTimezoneSupport) expect { Time.should_receive(:use_zone).and_raise(NoMethodError.new("undefined method `use_zone' for Time:Class")) parse("2000-06-01 12:13:14", :zone => 'London') }.should raise_error(Timeliness::Parser::MissingTimezoneSupport) end end end context "for time type" do context "with date from date_for_time_type" do before do @original = Timeliness.date_for_time_type end it 'should return date array' do Timeliness.date_for_time_type = [2010,1,1] parse('12:13:14', :time).should == Time.local(2010,1,1,12,13,14) end it 'should return date array evaluated lambda' do Timeliness.date_for_time_type = lambda { Time.local(2010,2,1) } parse('12:13:14', :time).should == Time.local(2010,2,1,12,13,14) end after do Timeliness.date_for_time_type = @original end end context "with :now option" do it 'should use date from :now' do parse('12:13:14', :time, :now => Time.local(2010, 6, 1)).should == Time.local(2010,6,1,12,13,14) end end context "with :zone option" do it "should use date from the specified zone" do time = parse("12:13:14", :time, :zone => :utc) time.year.should == 2009 time.month.should == 12 time.day.should == 31 end end end end describe "_parse" do context "with no type" do it "should return date array from date string" do time_array = parser._parse('2000-02-01') time_array.should == [2000,2,1,nil,nil,nil,nil,nil] end it "should return time array from time string" do time_array = parser._parse('12:13:14', :time) time_array.should == [nil,nil,nil,12,13,14,nil,nil] end it "should return datetime array from datetime string" do time_array = parser._parse('2000-02-01 12:13:14') time_array.should == [2000,2,1,12,13,14,nil,nil] end end context "with type" do it "should return date array from date string" do time_array = parser._parse('2000-02-01', :date) time_array.should == [2000,2,1,nil,nil,nil,nil,nil] end it "should not return time array from time string for :date type" do time_array = parser._parse('12:13:14', :date) time_array.should == nil end it "should return time array from time string" do time_array = parser._parse('12:13:14', :time) time_array.should == [nil,nil,nil,12,13,14,nil,nil] end it "should not return date array from date string for :time type" do time_array = parser._parse('2000-02-01', :time) time_array.should == nil end it "should return datetime array from datetime string when type is date" do time_array = parser._parse('2000-02-01 12:13:14', :date) time_array.should == [2000,2,1,12,13,14,nil,nil] end it "should return date array from date string when type is datetime" do time_array = parser._parse('2000-02-01', :datetime) time_array.should == [2000,2,1,nil,nil,nil,nil,nil] end it "should not return time array from time string when type is datetime" do time_array = parser._parse('12:13:14', :datetime) time_array.should == nil end end context "with :strict => true" do it "should return nil from date string when type is datetime" do time_array = parser._parse('2000-02-01', :datetime, :strict => true) time_array.should be_nil end it "should return nil from datetime string when type is date" do time_array = parser._parse('2000-02-01 12:13:14', :date, :strict => true) time_array.should be_nil end it "should return nil from datetime string when type is time" do time_array = parser._parse('2000-02-01 12:13:14', :time, :strict => true) time_array.should be_nil end it "should parse date string when type is date" do time_array = parser._parse('2000-02-01', :date, :strict => true) time_array.should_not be_nil end it "should parse time string when type is time" do time_array = parser._parse('12:13:14', :time, :strict => true) time_array.should_not be_nil end it "should parse datetime string when type is datetime" do time_array = parser._parse('2000-02-01 12:13:14', :datetime, :strict => true) time_array.should_not be_nil end it "should ignore strict parsing if no type specified" do time_array = parser._parse('2000-02-01', :strict => true) time_array.should_not be_nil end end context "with :format option" do it "should return values if string matches specified format" do time_array = parser._parse('2000-02-01 12:13:14', :datetime, :format => 'yyyy-mm-dd hh:nn:ss') time_array.should == [2000,2,1,12,13,14,nil,nil] end it "should return nil if string does not match specified format" do time_array = parser._parse('2000-02-01 12:13', :datetime, :format => 'yyyy-mm-dd hh:nn:ss') time_array.should be_nil end end context "date with ambiguous year" do it "should return year in current century if year below threshold" do time_array = parser._parse('01-02-29', :date) time_array.should == [2029,2,1,nil,nil,nil,nil,nil] end it "should return year in last century if year at or above threshold" do time_array = parser._parse('01-02-30', :date) time_array.should == [1930,2,1,nil,nil,nil,nil,nil] end it "should allow custom threshold" do default = Timeliness.ambiguous_year_threshold Timeliness.ambiguous_year_threshold = 40 time_array = parser._parse('01-02-39', :date) time_array.should == [2039,2,1,nil,nil,nil,nil,nil] time_array = parser._parse('01-02-40', :date) time_array.should == [1940,2,1,nil,nil,nil,nil,nil] Timeliness.ambiguous_year_threshold = default end end end describe "make_time" do it "should return time object for valid time array" do time = parser.make_time([2010,9,8,12,13,14]) time.should == Time.local(2010,9,8,12,13,14) end it "should return nil for invalid date in array" do time = parser.make_time([2010,13,8,12,13,14]) time.should be_nil end it "should return nil for invalid time in array" do time = parser.make_time([2010,9,8,25,13,14]) time.should be_nil end context "default timezone" do before do @default_timezone = Timeliness.default_timezone end it "should be used if no zone value" do Timeliness.default_timezone = :utc time = parser.make_time([2000,6,1,12,0,0]) time.utc_offset.should == 0 end after do Timeliness.default_timezone = @default_timezone end end context "with zone value" do context ":utc" do it "should return time object in utc timezone" do time = parser.make_time([2000,6,1,12,0,0], :utc) time.utc_offset.should == 0 end end context ":local" do it "should return time object in local system timezone" do time = parser.make_time([2000,6,1,12,0,0], :local) time.utc_offset.should == 10.hours end end context ":current" do it "should return time object in current timezone" do Time.zone = 'Adelaide' time = parser.make_time([2000,6,1,12,0,0], :current) time.utc_offset.should == 9.5.hours end end context "named zone" do it "should return time object in the timezone" do time = parser.make_time([2000,6,1,12,0,0], 'London') time.utc_offset.should == 1.hour end end end end describe "current_date" do context "with no options" do it 'should return date_for_time_type values with no options' do current_date.should == Timeliness.date_for_time_type end end context "with :now option" do it 'should return date array from Time value' do time = Time.now date_array = [time.year, time.month, time.day] current_date(:now => time).should == date_array end end context "with :zone option" do it 'should return date array for utc zone' do time = Time.now.getutc date_array = [time.year, time.month, time.day] current_date(:zone => :utc).should == date_array end it 'should return date array for local zone' do time = Time.now date_array = [time.year, time.month, time.day] current_date(:zone => :local).should == date_array end it 'should return date array for current zone' do Time.zone = 'London' time = Time.current date_array = [time.year, time.month, time.day] current_date(:zone => :current).should == date_array end it 'should return date array for named zone' do time = Time.use_zone('London') { Time.current } date_array = [time.year, time.month, time.day] current_date(:zone => 'London').should == date_array end end end after(:all) do Timecop.return end end