红宝石返回无效日期(错误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