EventKitを使う準備として日付の操作を試していていて気づいた注意点です。
日付を設定する時に以前は、NSDateのイニシャライザに
onvenience init?(string description: String)
というメソッドが用意されていましたが、OSX10.10 でdepriciated になってしまいました。現在 NSDate クラスで日付を設定するために使用できるイニシャライザは、
- init(timeIntervalSinceNow secs: NSTimeInterval)
- init(timeInterval secsToBeAdded: NSTimeInterval,
sinceDate date: NSDate) - init(timeIntervalSinceReferenceDate ti: NSTimeInterval)
- init(timeIntervalSince1970 secs: NSTimeInterval)
になり、全て特定の日付からの TimeInterval での指定になりました。
従って必要な日付のNSDateインスタンスは、 NSDate()
でそのときの日付時刻を得て、そこからNSCalendar のメソッドを使って欲しい日付のNSDate インスタンスを得る方法にほぼ限定されています。
これに使用できそうなNSCalendar のメソッドは
- dateByAddingComponents:toDate:options:
- dateByAddingUnit:value:toDate:options:
- dateFromComponents:
- dateBySettingHour:minute:second:ofDate:options:
- dateBySettingUnit:value:ofDate:options:
といったところです。
この中で dateBySettingUnit:value:ofDate:option:
は注意が必要です。Class Reference では与えられた日付のコンポーネントを与えられた値に設定すると説明されていますが、このメソッドの実行結果は与えられた日付よりも後の日付にしかなりません。
var myCalendar = NSCalendar.currentCalendar()
let today = NSDate()
// "Oct 24, 2015, 9:43 PM"
var day1 = myCalendar.dateBySettingUnit(NSCalendarUnit.Day, value: 1, ofDate: today, options: NSCalendarOptions())
// "Nov 1, 2015, 12:00 AM"
var day30 = myCalendar.dateBySettingUnit(NSCalendarUnit.Day, value: 30, ofDate: today, options: NSCalendarOptions())
// "Oct 30, 2015, 12:00 AM"
var day20 = myCalendar.dateBySettingUnit(NSCalendarUnit.Day, value: 20, ofDate: today, options: NSCalendarOptions())
// "Nov 20, 2015, 12:00 AM"
day1 = myCalendar.dateBySettingUnit(NSCalendarUnit.Month, value: 1, ofDate: day1!, options: NSCalendarOptions())
// "Jan 1, 2016, 12:00 AM"
day1 = myCalendar.dateBySettingUnit(NSCalendarUnit.Year, value: 2015, ofDate: day1!, options: NSCalendarOptions())
// nil
let firstDayOf2015Comp = NSDateComponents()
firstDayOf2015Comp.day = 1
firstDayOf2015Comp.month = 1
firstDayOf2015Comp.year = 2015
day1 = myCalendar.dateFromComponents(firstDayOf2015Comp)
// "Jan 1, 2015, 12:00 AM"
上の例のday1のように10月24日の日付に対して"Day" を1に設定すると11月1日になります。day30のように10月24日に対して"Day"を30にすると10月30日になります。day20 のように10月24日の"Day"を20にすると11月20日になります。11月1日になっているday1 の"Month" を1に設定すると2016年1月1日になります。さらにこのday1の"Year" を2015に設定すると nil
になってしまいます。2016年以後に2015年にはならないのでnil
になってしまいます。
ということで、日付を設定する時には例えばNSDate() を基準にして、
- dateByAddingComponents:toDate:options:
- dateByAddingUnit:value:toDate:options:
を使用する方がよいようです。
なお、例の最後にあるようにNSDateComponets で日付コンポーネントを用意してやれば、
- dateFromComponents:
で直接日付を設定することができます。
DateByAddingComponets を使うと、月初めの日付から月末の日付を得るには、NSDateComponets インスタンスの month に1、day に-1 を設定して
dateByAddingComponents を使うと簡単に計算できます。
let endOfMonthComp = NSDateComponents()
endOfMonthComp.month = 1
endOfMonthComp.day = -1
let endOfMonth = myCalendar.dateByAddingComponents(endOfMonthComp, toDate: day1!, options: NSCalendarOptions())
// "Jan 31, 2015, 12:00 AM"