為了某些專案的進度追蹤,改成逐周方式確認。在溝通過程中,發現週數老是對不上,原來大家的週數計算方式都不太一樣。我的紙本行事曆跟電腦行事曆也不太一樣。

原來,計算一週之始有好幾種方法,例如

  • 1/1 日開始一定算第一周。
  • 不管 1/1,從一年的第一個星期天開始算第一周。
  • 不管 1/1,從一年的第一個星期一開始算第一周。

像是波斯灣阿拉伯國家是週六開始算第一周,巴基斯坦跟愛沙尼亞是把 1/7 當作一年開始來計算。即便是上述的幾種方式,在同一個國家內也有不同的偏好阿。像我的行事曆就是 1/1 開始當作第一周,而我的電腦則是把週日開始算為第一周。兩個相較起來就差了一週。

在 Linux 上,其實 en_US 跟 zh_TW 兩種不同的語系設定,開始週數是不同的。en_US 使用的是 1/1 開始那周算第一周,而 zh_TW 則是設定成第一個週一是第一周。用 ncal 看起來像是這樣

$ LC_TIME=en_US.UTF8 ncal -w  1 2009
    January 2009
Mo     5 12 19 26
Tu     6 13 20 27
We     7 14 21 28
Th  1  8 15 22 29
Fr  2  9 16 23 30
Sa  3 10 17 24 31
Su  4 11 18 25
    1  2  3  4  5
$ LC_TIME=zh_TW.UTF8 ncal -w  1 2009
    一月 2009
一     5 12 19 26
二     6 13 20 27
三     7 14 21 28
四  1  8 15 22 29
五  2  9 16 23 30
六  3 10 17 24 31
日  4 11 18 25
   52  1  2  3  4

上述的算法,時常造成同一周被定義兩次,他可能是去年的 53 周,又是今年的第 1 周。這樣很容易造成困擾。

為了避免這種糾紛產生,其實有一份 ISO 8601 定義了週數的算法。ISO 8601 除了制定時間字串的格式之外,也定義了週數的計算方式。規則稍微複雜一點,但是是為了避免一個周被計算兩次。

ISO 8601 的計算方式是

  • 包含第一個週四的算第一周。
  • 包含 1/4 的那一週。
  • 第一週超過四天以上。
  • 12/29 後的第一個週一。

詳細算法請見 ISO Week Date。你在 Linux 上,可以用 date 指令查到以下依照週一、週日、ISO 算法的週數

$ date +"Sunday %U Monday %W ISO %V" -d '2010-01-01'
Sunday 00 Monday 00 ISO 53
$ date +"Sunday %U Monday %W ISO %V" -d '2010-01-03'
Sunday 01 Monday 00 ISO 53
$ date +"Sunday %U Monday %W ISO %V" -d '2010-01-04'
Sunday 01 Monday 01 ISO 01