DateComponentsの各要素について調べてみた

投稿者: | 2016年2月3日

xcalのWindows PowerShell移植版であるwcalには週表示オプションが追加されています。この機能、xcalへの逆輸入を検討してみましょうか。

年月日や曜日の取得に使ったDateオブジェクトで週番号わかるかな?と思って調べてみたら、結構いろんなプロパティがあるようです。weekOfYearが週番号のようですが、いまいち意味がよくわからないプロパティもあるのでちょっと調べてみましょう。(曜日関連プロパティのみ抜粋)

  • weekday:曜日
  • weekdayOrdinal:第何曜日
  • weekOfMonth:当月の週番号
  • weekOfYear:当年の週番号
  • yearForWeekOfYear:週番号の対象年

weekdayはこれまでも使っているのでいいとして、weekdayOrdinalって何だ?答えは当月何番目のweekdayであるかというものでした。第3月曜日とかいうアレです。ちなみに第3月曜日は

weekday=2, weekdayOrdinal=3

となります。

普通週番号というとweekOfYearですが、weekOfMonthってのもあるんだね。使いどころがよくわからないけど。。。

で、問題なのがyearForWeekOfYear。これの意味がよくわからなかったので、理解するためにコードを書いてみました。

#! /usr/bin/swift
import Foundation
let now: Date = Date()
let cal: NSCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
var cal_comp: DateComponents = cal.components([.era, .year, .month, .day,
                                                .hour, .minute, .second, .nanosecond], from:now)
let arguments: [String] = CommandLine.arguments
if (arguments.count == 4) {
    cal_comp.year = Int(arguments[1])!
    cal_comp.month = Int(arguments[2])!
    cal_comp.day = Int(arguments[3])!
}
var calen: Date = Calendar.current.date(from:cal_comp)!
cal_comp = cal.components([.era, .year, .month, .day,
                                                .hour, .minute, .second,
                                                .weekday, .weekdayOrdinal, .quarter,
                                                .weekOfMonth, .weekOfYear, .yearForWeekOfYear,
                                                .nanosecond, .calendar, .timeZone], from:calen)
let weekday: [String] = ["日","月","火","水","木","金","土"]
print("\(cal_comp.year!)年\(cal_comp.month!)月\(cal_comp.day!)日\(weekday[cal_comp.weekday! - 1])曜日")
print(".era:",cal_comp.era!)
print(".year:",cal_comp.year!)
print(".month:",cal_comp.month!)
print(".day:",cal_comp.day!)
print(".hour:",cal_comp.hour!)
print(".minute:",cal_comp.minute!)
print(".second:",cal_comp.second!)
print(".weekday:",cal_comp.weekday!)
print(".weekdayOrdinal:",cal_comp.weekdayOrdinal!)
print(".quarter:",cal_comp.quarter!)
print(".weekOfMonth:",cal_comp.weekOfMonth!)
print(".weekOfYear:",cal_comp.weekOfYear!)
print(".yearForWeekOfYear:",cal_comp.yearForWeekOfYear!)
print(".nanosecond:",cal_comp.nanosecond!)
print(".calendar:",cal_comp.calendar!)
print(".timeZone:",cal_comp.timeZone!)

ところで、年末って第何週になるんでしょうね?例えば2015年1月1日は木曜日なので、当然2014年12月31日は水曜日。そしてこの両日は同一週ですね。では2014年12月31日の週番号は?

答えはweekOfYear=1です。53じゃないの?違和感あるなぁ。。。とyearForWeekOfYearを見てみると2015。つまり2014年12月31日は2015年の第1週となっているのです。

$ swift chkdate.swift 2014 12 31 | grep -e "OfYear"
.weekOfYear: 1
.yearForWeekOfYear: 2015
$ swift chkdate.swift 2015 1 1 | grep -e "OfYear"
.weekOfYear: 1
.yearForWeekOfYear: 2015

というわけでyearForWeekOfYearはweekOfYearの対象年なのでした。

なお、週番号の詳細についてはISO 8601に規定されています。

  • 第1週はその年の第1木曜日を含む週である
  • 年末の7日間に満たない最終週は翌年の第1週として扱う

ふ?ん。週番号に馴染みのない我々日本人にとって「そもそもなんで第1木曜日なの?」という疑問がありますが、そういう定義なのでここは突っ込みナシで。

ただし、Dateの週番号はISO方式とは少し異なるUS方式です。第1週は1月1日を含む週ということでこちらのほうが受け入れやすいですね。したがって1月1日が金曜日である2016年はアメリカとそれ以外で週番号がずれています。

wcal実行結果

ちなみにwcalの週番号は自前で計算しているので年末最終週で間違った値を表示します。今度直しておこう。

ほかにもいろいろあるんですが、とりあえず今回はこんなところで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です