现在是北京时间 2013 年 11 月 22 日凌晨 1 点 50 分,我在跑测试的时候发现 Date.tomorrow 返回的时间居然也是 2013 年 11 月 22 日……
这个测试的目的是测试用户输入的生日不能晚于今天,测试代码和实现代码如下:
实现:
def birthday_cannot_be_later_than_today
if birthday.present? && birthday > Date.today
errors.add :birthday, '不能晚于今天'
end
end
测试:
it 'should not later than today' do
@user.birthday = Date.tomorrow
expect(@user).not_to be_valid
end
以下是 console 的输出信息。
rails console --sandbox
Loading development environment in sandbox (Rails 4.0.1)
Any modifications you make will be rolled back on exit
Frame number: 0/3
[1] pry(main)> Date.current
=> Thu, 21 Nov 2013
[2] pry(main)> Date.today
=> Fri, 22 Nov 2013
[3] pry(main)> Date.tomorrow
=> Fri, 22 Nov 2013
from (pry):4:in `<main>'
[4] pry(main)> Time.now
=> 2013-11-22 01:50:33 +0800
[5] pry(main)> Time.current
=> Thu, 21 Nov 2013 17:50:45 UTC +00:00
这有点奇怪,于是我查看了 rails 的源码:
...
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
def yesterday
::Date.current.yesterday
end
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
def tomorrow
::Date.current.tomorrow
end
# Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today.
def current
::Time.zone ? ::Time.zone.today : ::Date.today
end
...
发现 tomorrow 和 yesterday 是调用的 Date.current,这就有意思了,Date.current 是有时区概念的,所以我个人分析应该是和我没在 application 中设置 timezone 有关的。(参考了这篇文章 - http://ruby-china.org/topics/5940)
所以,我在将 config.time_zone 设置成 Beijing 之后这个测试跑通了。
但是,这又引发了一个问题:
我在判断生日是否合法的时候,是在后端写的birthday > Date.tomorrow
这种方式,那也就是说,不同时区的人在输入生日的时候会出现:虽然输入的是 Date.today,但是服务器还是认为会出错的情况(好吧,我知道一般没人狗血到写今天作为生日,但是为了严谨……)
那么有什么办法能够解决这个问题呢?求帮助!