MS Access获得ISO标准周数

时间:2016-01-12 11:06:52

标签: ms-access iso week-number

我很惊讶我在网上找不到任何现有的解决方案,但我只需要一个返回ISO标准周数的SQL函数(即第1周的开始始终是一年中的第一个星期一)。

没有DatePart函数选项始终返回正确的结果。我曾经想过选择“vbFirstFourDays - 从第一周开始,在新的一年至少有四天。”但今天(1月12日)测试它会返回第3周,而不是第2周(我的表达式是DatePart("ww",Now(),2)

今年ISO第1周于1月4日开始,明年1月2日开始,去年是1月5日。

非常感谢

3 个答案:

答案 0 :(得分:3)

DatePart函数确实在 firstdayofweek 参数{{1>}使用vbMonday时正确地计算了ISO-8601周数 * {1>}用于 firstweekofyear 参数,例如

vbFirstFourDays

或直接在Access查询中使用

DatePart("ww", Date(), vbMonday, vbFirstFourDays)

* 请注意,here记录的错误显然从未修复过,因此21 st 世纪的以下星期一报告为第53周根据ISO-8601,它们应该在下一年的第1周:

2003-12-29
2007-12-31
2019年12月30日
2031年12月29日
2035年12月31日
2047年12月30日
2059年12月29日
2063年12月31日
2075年12月30日
2087年12月29日
2091-12-31

答案 1 :(得分:2)

为了跟进Gord Thompson,微软提供了一种解决方法,可以在所有情况下返回正确的ISO周。它只是将第53周更改为第1周。只需将其放入VBA模块中,然后您就可以在Excel / Access中使用该功能。

Public Function ISOWeek(MyDate As Date) As Integer

      ISOWeek = Format(MyDate, "ww", vbMonday, vbFirstFourDays)
      If ISOWeek > 52 Then
         If Format(MyDate + 7, "ww", vbMonday, vbFirstFourDays) = 2 Then ISOWeek = 1
      End If

End Function

答案 2 :(得分:0)

ISO 周数的问题不仅仅是 DatePart 返回的 2 周数字。

1 月 1 日的星期五应该是上一年的第 53 周

12 月 31 日的星期一应该是下一年的第 1 周

欧洲的许多企业都使用四位数来表示年份和星期。在这些情况下:

星期五 #01/01/2021# 应显示为“2153”周

星期一 #12/31/2018# 应显示为“1901”周

我在 DatePart 函数周围创建了 2 个包装器,以添加正确的年份并显示正确的周数,以防 DatePart 出错。

Public Function ISO_YYWW(dat As Date) As String ' ISO 8601 / NEN 2772
    Dim ww As Integer
    ww = CInt(ISO_WW(dat))
    If ww >= 52 And Val(Format(dat, "ww")) <= 2 Then
       ISO_YYWW = Format(((Year(dat) - 1) Mod 100), "00") & Format(ww, "00")
    ElseIf ww = 1 And Month(dat) = 12 Then
       ISO_YYWW = Format(((Year(dat) + 1) Mod 100), "00") & Format(ww, "00")
    Else
       ISO_YYWW = Format(dat, "YY") & Format(ww, "00")
    End If
End Function
Public Function ISO_WW(dat As Date) As String ' ISO 8601 / NEN 2772
    If Format(dat, "DD-MM") = "31-12" And DatePart("W", dat, vbMonday, vbFirstFourDays) = 1 Then ' 31-dec on a monday
       ISO_WW = "01"
    ElseIf Format(dat, "DD-MM") = "30-12" And DatePart("W", dat, vbMonday, vbFirstFourDays) = 1 Then ' 30-dec on a monday
       ISO_WW = "01"
    ElseIf Format(dat, "DD-MM") = "29-12" And DatePart("W", dat, vbMonday, vbFirstFourDays) = 1 Then ' 29-dec on a monday
       ISO_WW = "01"
    Else
       ISO_WW = Format(DatePart("ww", dat, 2, 2), "00")
    End If
End Function

我从 1970 年到 2021 年进行了测试,使用此代码没有发现任何问题

Sub test()
    Dim dat As Date, yy As Integer, f As Integer
    f = FreeFile
    Open CodeDb.Name & ".txt" For Output As #f
    Print #f, "date", "day", "ISO_WW / DOW", "ISO_YYWW"
    For yy = 1970 To 2021
        For dat = CDate("31/12/" & yy) - 7 To CDate("31/12/" & yy) + 7
            If ISO_WW(dat) >= 52 Or ISO_WW(dat) = "53" Or Val(ISO_WW(dat)) = 1 Then
               Print #f, Format(dat, "yyyy-mm-dd"), Format(dat, "DDD"), ISO_WW(dat) & " / " & DatePart("W", dat, vbMonday, vbFirstFourDays), ISO_YYWW(dat)
            End If
        Next dat
        Print #f, ""
    Next yy
    Close #f
End Sub