diff --git a/lib/dentaku/date_arithmetic.rb b/lib/dentaku/date_arithmetic.rb index 72fddb4..3b81477 100644 --- a/lib/dentaku/date_arithmetic.rb +++ b/lib/dentaku/date_arithmetic.rb @@ -29,7 +29,7 @@ def add(duration) def sub(duration) case duration - when DateTime, Numeric + when Date, DateTime, Numeric @base - duration when Dentaku::AST::Duration::Value case duration.unit @@ -40,6 +40,8 @@ def sub(duration) when :day @base - duration.value end + when Dentaku::TokenScanner::DATE_TIME_REGEXP + @base - Time.parse(duration).to_datetime else raise Dentaku::ArgumentError.for(:incompatible_type, value: duration, for: Numeric), "'#{duration || duration.class}' is not coercible for date arithmetic" diff --git a/lib/dentaku/token_scanner.rb b/lib/dentaku/token_scanner.rb index eb7e15a..5770993 100644 --- a/lib/dentaku/token_scanner.rb +++ b/lib/dentaku/token_scanner.rb @@ -7,7 +7,7 @@ module Dentaku class TokenScanner extend StringCasing - DATE_TIME_REGEXP = /\d{2}\d{2}?-\d{1,2}-\d{1,2}( \d{1,2}:\d{1,2}:\d{1,2})? ?(Z|((\+|\-)\d{2}\:?\d{2}))?(?!\d)/.freeze + DATE_TIME_REGEXP = /\d{2}\d{2}?-\d{1,2}-\d{1,2}([ |T]\d{1,2}:\d{1,2}:\d{1,2}(\.\d*)?)? ?(Z|((\+|\-)\d{2}\:?\d{2}))?(?!\d)/.freeze def initialize(category, regexp, converter = nil, condition = nil) @category = category diff --git a/spec/calculator_spec.rb b/spec/calculator_spec.rb index d6906ed..b7ef8cf 100644 --- a/spec/calculator_spec.rb +++ b/spec/calculator_spec.rb @@ -471,16 +471,20 @@ it 'from string variable' do value = '2023-01-01' + value2 = '2022-12-31' - expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eql(Date.parse('2023-02-01')) - expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eql(Date.parse('2022-12-01')) + expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eq(Date.parse('2023-02-01')) + expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eq(Date.parse('2022-12-01')) + expect(calculator.evaluate!('value - value2', { value: value, value2: value2 })).to eq(1) end it 'from date object' do value = Date.parse('2023-01-01').to_date + value2 = Date.parse('2022-12-31').to_date - expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eql(Date.parse('2023-02-01')) - expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eql(Date.parse('2022-12-01')) + expect(calculator.evaluate!('value + duration(1, month)', { value: value }).to_date).to eq(Date.parse('2023-02-01')) + expect(calculator.evaluate!('value - duration(1, month)', { value: value }).to_date).to eq(Date.parse('2022-12-01')) + expect(calculator.evaluate!('value - value2', { value: value, value2: value2 })).to eq(1) end end diff --git a/spec/tokenizer_spec.rb b/spec/tokenizer_spec.rb index ac5d562..962cc32 100644 --- a/spec/tokenizer_spec.rb +++ b/spec/tokenizer_spec.rb @@ -1,3 +1,4 @@ +require 'dentaku/exceptions' require 'dentaku/tokenizer' describe Dentaku::Tokenizer do @@ -234,9 +235,9 @@ end it 'tokenizes Time literals' do - tokens = tokenizer.tokenize('2017-01-01 2017-01-2 2017-1-03 2017-01-04 12:23:42 2017-1-5 1:2:3 2017-1-06 1:02:30 2017-01-07 12:34:56 Z 2017-01-08 1:2:3 +0800') - expect(tokens.length).to eq(8) - expect(tokens.map(&:category)).to eq([:datetime, :datetime, :datetime, :datetime, :datetime, :datetime, :datetime, :datetime]) + tokens = tokenizer.tokenize('2017-01-01 2017-01-2 2017-1-03 2017-01-04 12:23:42 2017-1-5 1:2:3 2017-1-06 1:02:30 2017-01-07 12:34:56 Z 2017-01-08 1:2:3 +0800 2017-01-08T01:02:03.456Z') + expect(tokens.length).to eq(9) + expect(tokens.map(&:category)).to eq([:datetime, :datetime, :datetime, :datetime, :datetime, :datetime, :datetime, :datetime, :datetime]) expect(tokens.map(&:value)).to eq([ Time.local(2017, 1, 1).to_datetime, Time.local(2017, 1, 2).to_datetime, @@ -245,7 +246,8 @@ Time.local(2017, 1, 5, 1, 2, 3).to_datetime, Time.local(2017, 1, 6, 1, 2, 30).to_datetime, Time.utc(2017, 1, 7, 12, 34, 56).to_datetime, - Time.new(2017, 1, 8, 1, 2, 3, "+08:00").to_datetime + Time.new(2017, 1, 8, 1, 2, 3, "+08:00").to_datetime, + Time.utc(2017, 1, 8, 1, 2, 3, 456000).to_datetime ]) end