2010-02-04 60 views
8

我最近遇到了一个大问题,因为我有一个每周向客户付费的系统。ISO-8601周编号与PHP中的“Outlook”编号

众所周知,一年有52周,并且有标准。我使用PHP又名日期('W')来获取日期中的星期数,该日期根据标准ISO-8601进行计算。

这里有一些参考:

但这里有一个问题:2009年有53个星期。看来通过公元400年内的公历有71年,有53周。这是我不知道的一件事,可能很多事情都不是这样。

根据维基百科:

2009-12-31 2009年是-W53-4(ISO 2009年全年有53周,2009年扩大了西历,开始与结束日,在两端结束三天)。

和PHP中的日期函数完全尊重它。

如果您查看MS Outlook,并在日历视图中显示星期几,则将出现52周 考虑2009年12月28日至2010年1月3日第1周。这是另一个标准吗?美国标准还是什么?

如果是这样,那么为什么PHP不能支持它呢?有没有人提供支持这个功能的功能?

有53周是否正确?我们有欧洲和美国的客户。

+0

有趣的问题。我注意到Outlook在2011年有53周的时间。它看起来像是将“第一周”定义为包含1月1日的第一周。由于周可以在周日或周一基于设置开始,因此实际上可能会因不同而有所不同用户。 – 2010-02-04 18:16:53

+0

我刚试过。 Outlook将允许您选择任何一天作为星期开始日,而星期编号仅从包含Jan 1的那一周开始。因此Outlook中有七种不同的编号方案。 – 2010-02-04 18:19:05

回答

4

我不认为你会有问题在这里。事实是,您正在遵循日期和时间格式化和计数的国际标准(ISO8601)。如果您有任何抱怨的客户,只需将他们引用至标准。

Outlook的周编号为有些等同于以下:

$dummyWeek = floor((date('z') + (date('N') - 1))/7) + 1; 

为了计费,你最好使用ISO8601作为标准。事实上,如果你看看你今年要填补的税款,他们会将上一个财政年度描述为53周。

与Outlook的计数方式的问题是,一周不能保证是7天。例如,OW01-2010只有2天的损失:1月1日星期五,1月2日星期六。这是一个星期非常短的结算周期。

ISO8601周保证长达7天,这就是为什么我们每4/5/6年需要一个闰周的原因。

这些选项中的一个,你会喜欢哪:

  • ISO8601:在同时具有53周一次,但他们中的每一一个长7天。
  • Outlook:每年随机抽取52/53周,但每半年需要支付两次“半周”费用。
+0

日期'z'和'N'? – nathanchere 2014-09-12 08:08:41

5

Outlook不遵循任何星期编号标准。它有两个确定星期编号的设置,分别称为“星期几”和“第一个星期”。

通过将“星期几”设置为星期一和“第一个星期”到“第一个星期”,可以模拟ISO标准。

每个用户必须进行此调整才能遵循ISO标准。

我知道没有单独的美国标准,显然,Outlook也没有。

0

美国以外的地区比美国还要多 - ISO 8601在美国以外的地区可能比在美国境内使用的要广泛得多。正如你现在发现的那样,“一年有52周”的初步陈述只是部分正确的。就ISO周而言,您可以在第53周结束,如维基百科中所述。您可以在N年的第52周或第N年的第53周获得N + 1年的最多三天.N年的第1周也可以有最多三天的N-1年。您需要确定ISO“周年”以及“周” - 因为当公历年为N时,ISO周年可以是年N-1或N + 1(取决于哪一年你正在使用的一年)。这就是为什么在strftime()中有单独的格式说明符('%Y','%y','%g','%G')(但请注意,POSIX标准认为在1月的第一个星期一之前的几天是在当年的第0周,而不是在前一年的第52或53周)。

“周”似乎没有任何可靠的'美国标准'。取决于您使用的软件,您会得到不同的结果。如果你看一周的定义Oracle,那么今年的前七天是第一周;你在一年的53周末有1或2天。

另请参阅SO 274861以获取ISO星期数字代码的实现。即使你不用语言编码,算法也应该容易理解。

0

只是警告一句话,如果您使用PHP,您可能也会使用MySQL。 MySQL确实不是按照ISO-8601周的惯例,但它足够接近,你可能会认为它的确如此。正如其他人正在关注Outlook一样,试图模仿计算周数的不规范的方式并不值得!

2

这是我解决它的方法。 注意:我使用PHP编码,但在SQL中实现的算法是我的代码的相关部分。另请注意,我分别处理'2028-12-31',因为它是一个特殊的日期,它给出了54周的数字。

// generate an sql that calculates the outlook week of $date (until 2033) 
function sqlWeek ($date) { 
    $week = "if(". $date . " = '2028-12-31', 54, (week(" . $date . ", 0) + if((year(" . $date . ") - 1) in (2011, 2016, 2022, 2033), 0, 1)) MOD (if (year(". $date .") = 2028, 54, if((year(".$date.") - 1) in (2011, 2016, 2022, 2033), 53, 52))))"; 

    return "concat(if(char_length(".$week.") < 2, concat('0', ".$week."), ".$week."), '/', year($date))"; 
} 
+0

此外,请注意,我使用了“Week('2011-11-09',0)”,意思是星期一从星期天开始。如果从星期一开始,则应使用“Week('2011-11-09',1)”。 – Amit 2011-11-09 13:31:29