Bug #11621
closedDate.- and Date.+ methods inconsistencies
Description
I noticed today some inconsistencies when using - and + methods of the Date class, that makes the whitespace relevant:
irb(main):001:0> require 'date'
=> true
irb(main):002:0> Date.today - 7
=> #<Date: 2015-10-19 ((2457315j,0s,0n),+0s,2299161j)>
irb(main):003:0> Date.today -7
=> #<Date: 2015-10-26 ((2457322j,0s,0n),+0s,2299161j)>
irb(main):004:0> Date.today-7
=> #<Date: 2015-10-19 ((2457315j,0s,0n),+0s,2299161j)>
It looks like the parser ignores the -7 in the context of Date.today instead of interpreting it as 7 days ago
This can be replicated when using integers as variables:
irb(main):002:0> days = 5
=> 5
irb(main):003:0> p (Date.today - days) == (Date.today -days)
false
=> false
or when creating Date with DateTime.now, but weirdly enough not when the Date is in a variable:
irb(main):004:0> now = Date.today
=> #<Date: 2015-10-26 ((2457322j,0s,0n),+0s,2299161j)>
irb(main):005:0> p (now - 7) == (now-7)
true
=> true
irb(main):006:0> p (now -7) == (now-7)
true
=> true
or when creating a Date with the constructors that force you to set a date (new, ordinal, parse, etc)
The other thing that I discovered while testing this was the behaviour to_date when tried to chain the - method:
irb(main):002:0> Time.new(2001,2,3).to_date
=> #<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>
irb(main):003:0> Time.new(2001,2,3).to_date -7
ArgumentError: wrong number of arguments (1 for 0)
from (irb):3:in `to_date'
from (irb):3
from /opt/boxen/rbenv/versions/2.2.3/bin/irb:11:in `<main>'
irb(main):004:0> Time.new(2001,2,3).to_date - 7
=> #<Date: 2001-01-27 ((2451937j,0s,0n),+0s,2299161j)>
I've attached a file with my tests and commented the output from my machine.
Files
Updated by 0x0dea (D.E. Akers) about 10 years ago
This has nothing to do with Date in particular; observe:
def foo n = nil
n || 48
end
p foo-6 # => 42
p foo -6 # => -6
p foo - 6 # => 42
This is simply a consequence of parentheses for method invocation being (mostly) optional. The solution is to properly (read: consistently) pad your operators.
Updated by andreionut (Andrei Balcanasu) about 10 years ago
Good point, but this still does not explain why in some cases -7 works:
now = Date.today
=> #<Date: 2015-10-26 ((2457322j,0s,0n),+0s,2299161j)>
now -7
=> #<Date: 2015-10-19 ((2457315j,0s,0n),+0s,2299161j)>
Date.new(2001,2,3) -7
=> #<Date: 2001-01-27 ((2451937j,0s,0n),+0s,2299161j)>
Updated by 0x0dea (D.E. Akers) about 10 years ago
Those examples are not ambiguous. Date.today -7 is ambiguous because Date.today takes an optional argument specifying, essentially, which calendar to useāone of ITALY, ENGLAND, JULIAN, or GREGORIAN, if you're using the method correctly. As demonstrated earlier, Ruby resolves this ambiguity by assuming you're not trying to trick the parser.
Updated by shugo (Shugo Maeda) about 10 years ago
- Status changed from Open to Rejected
Andrei Balcanasu wrote:
Good point, but this still does not explain why in some cases
-7works:now = Date.today => #<Date: 2015-10-26 ((2457322j,0s,0n),+0s,2299161j)> now -7 => #<Date: 2015-10-19 ((2457315j,0s,0n),+0s,2299161j)>
If x is a reference to a local variable, x -y is interpreted as x - y.
Otherwise, x -y is interpreted as x(-y).
def x(y)
:x
end
p(x -2) #=> :x
x = 1
p(x -2) #=> -1
This behavior is irrelevant to Date, so if you don't like it, please file another ticket.
Updated by nobu (Nobuyoshi Nakada) about 10 years ago
If you were use -w option, you were warned.
$ ruby -wc -e 'Date.today -7' -e 'now = Date.today' -e 'p now -7'
-e:1: warning: ambiguous first argument; put parentheses or a space even after `-' operator
-e:3: warning: `-' after local variable or literal is interpreted as binary operator
-e:3: warning: even though it seems like unary operator
Syntax OK
Updated by andreionut (Andrei Balcanasu) about 10 years ago
Right, that is clear now for me.
Thanks for explaining.
I don't know how to close the bug, so whomever has access, please close