红宝石返回无效日期(错误DOW)解析日期字符串
,当我与返回日期字符串引用第53周为一年的API时2016年红宝石返回无效日期(错误DOW)解析日期字符串
我发现的唯一的日历,工作时解析它是JULIAN
。
但是,Date.parse("2016-W53", true, Date::JULIAN)
返回Mon, 27 Dec 2016
,这是错误的日期,因为它应该是Mon, 26 Dec 2016
。
这是怎么发生的?
我怎样才能得到它返回正确的日期?
朱利安日历是一个完全不同的日历;在Julian日历上,12/27 周一是,因为在Julian日历上,2016年1月1日是星期四,而在公历上是星期五。
通常情况下,我会说使用Date.strptime('2016-W53','%G-W%V')
...但似乎不起作用。根据该文件,计算当年周的时候,Ruby的使用ISO 8601基于本周年和周数:
ISO 8601基于本周年和周数:
本周YYYY 1开头一个星期一,包括YYYY-01-04。
第一周前一年的日子是去年的最后一周 。
%G - 以周为周期的年份
%V - 以周为基准的年份的周数(01..53)
%g - 以周为基准年的最后2位数(00..99)
如上所述,本系统一年的第一周是包含1月4日的一周;在朱利安日历中,第4日的周日被包含在1月1日的同一周;然而,在公历中,第4个周一为,因此标记为2016年的“计数”的第一周 - 前一周为2015年的第53周。
原因是(大概)不应该算一个星期为2016年的第一周,也是2015年最后一周的;因为如果你想要一段时间,比如10周,那么你最终会在那一周计算两次。之所以选择1月4日作为标记,原因可能是因为如果1月1日这一周包括1月4日,那么这7天的大部分时间将落在新的一年,所以这一周是新年的一部分。
鉴于上述情况,是 2016年第53周,至少根据ISO规则计算周数。你可以实现你自己的系统来确定日期是什么意思,但是你不得不问API的提供者你正在消费他们如何生成这些数字,否则你不知道你是否正确解释它。
您不应该用Julian calendar来解释日期,因为它不能修正我们现在在西方国家使用的最近的Gregorian calendar中记录的时间周期性“漂移”。
Date.parse
应该工作,如果输入的是有效的,它看起来像你的是不是:
Date.parse("2016-W53")
# ArgumentError: invalid date
Date.parse("2020-W53")
# <Date: 2020-12-28 ((2459212j,0s,0n),+0s,2299161j)>
我要说的是,如果默认标准库中parse
方法不能作出这样的价值感,你应该写你自己的解析器。上周
def custom_parse(str)
regex = /\A(?<year>\d{4})-W(?<week>\d{2})\z/
if data = regex.match(str)
year = data[:year].to_i
week = data[:week].to_i
Date.commercial(year, week - 1) + 7
end
end
custom_parse("2016-W53")
# <Date: 2017-01-02 ((2457756j,0s,0n),+0s,2299161j)>
关于根据Wikipedia:
如果12月31日是在周一,周二或周三,这是在明年01周。如果是在星期四,那是刚刚结束的第53周。如果在星期五它是在第52周(或53,如果刚刚结束的一年是闰年);如果在星期六或星期日,则在刚刚结束的第52周。
和:
它12月28日在里面。因此最早可能的最早时间是从12月21日星期一延长到1月28日星期日,最新的可能性从12月28日星期一延续到1月3日(下一个阳历年)。
因此,如果您想查看一年中有多少周,那么您可以请求YYYY-12-28
的周数。如果你这样做在Ruby中,它应该是这样的:
2014.upto(2016) do |i|
date = Date.new(i, 12, 28)
puts "#{date} - in week #{date.cweek}"
end
# 2014-12-28 - in week 52
# 2015-12-28 - in week 53
# 2016-12-28 - in week 52
正如你可以看到有没有53周在2016年这样你得到的日期可能是错误的。我建议联系您的API提供商,因为我认为推出自己的方法来处理这种情况并不明智。
如果你需要需要推出自己的解决方案,你可以用的东西,看起来像这样(正则表达式从tompave的例子)去:
class MyCustomDateParser
FORMAT = /\A(?<year>\d{4})-W(?<week>\d{2})\z/
def self.parse!(date)
raise ArgumentError, "invalid date" unless m = date.match(FORMAT)
Date.parse(date)
rescue ArgumentError => e
fail e unless m[2] == "53"
Date.parse("#{m[1]}-W52")
end
end