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 9 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 9 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 9 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 9 years ago
- Status changed from Open to Rejected
Andrei Balcanasu wrote:
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)>
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 9 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 9 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