date = [calendar nextDateAfterDate:valentines matchingComponents:components options:NSCalendarMatchNextTimePreservingSmallerUnits];
// Mar 1, 2015, 9:00 AM
最后, 使用 .MatchPreviousTimePreservingSmallerUnits
选项会在 另一个 方向上解决缺失的时间问题, 和前面一样,保留较小的单元,然后找到匹配的前一天:
Swift
Objective-C
calendar.nextDateAfterDate(valentines, matchingComponents: components, options: .MatchPreviousTimePreservingSmallerUnits)
// Feb 28, 2015, 9:00 AM
date = [calendar nextDateAfterDate:valentines matchingComponents:components options:NSCalendarMatchPreviousTimePreservingSmallerUnits];
// Feb 28, 2015, 9:00 AM
除了这里的 NDateComponents
外,还值得注意的是 nextDateAfterDate
方法有两种变化:
Swift
Objective-C
// 匹配指定的日历单元
cal.nextDateAfterDate(valentines, matchingUnit: .CalendarUnitDay, value: 31, options: .MatchStrictly)
// March 31, 2015, 12:00 AM
// 匹配时,分,秒
cal.nextDateAfterDate(valentines, matchingHour: 15, minute: 30, second: 0, options: .MatchNextTime)
// Feb 14, 2015, 3:30 PM
// 匹配指定的日历单元
date = [calendar nextDateAfterDate:valentines matchingUnit:NSCalendarUnitDay value:31 options:NSCalendarMatchStrictly];
// March 31, 2015, 12:00 AM
// 匹配时,分,秒
date = [calendar nextDateAfterDate:valentines matchingHour:15 minute:30 second:0 options:NSCalendarMatchNextTime];
// Feb 14, 2015, 3:30 PM
枚举插值日期
NSCalendar
提供了一个API去枚举日期, 所以大家没有必要反复的调用 nextDateAfterDate
方法。enumerateDatesStartingAfterDate(_:matchingComponents:options:usingBlock:)
方法根据提供的日期组件和选项,依次获取匹配的日期。可以将 stop
属性设为 true
去停止枚举。
来试试这个 NSCalendarOptions
的新方法吧,下面展示了一种获取随后50个闰年的方法:
Swift
Objective-C
let leapYearComponents = NSDateComponents()
leapYearComponents.month = 2
leapYearComponents.day = 29
var dateCount = 0
cal.enumerateDatesStartingAfterDate(NSDate(), matchingComponents: leapYearComponents, options: .MatchStrictly | .SearchBackwards)
{ (date: NSDate!, exactMatch: Bool, stop: UnsafeMutablePointer<ObjCBool>) in
println(date)
if ++dateCount == 50 {
// .memory 用来获取一个 UnsafeMutablePointer 属性的值
stop.memory = true
// 2012-02-29 05:00:00 +0000
// 2008-02-29 05:00:00 +0000
// 2004-02-29 05:00:00 +0000
// 2000-02-29 05:00:00 +0000
// ...
NSDateComponents *leapYearComponents = [[NSDateComponents alloc] init];
leapYearComponents.month = 2;
leapYearComponents.day = 29;
__block int dateCount = 0;
[calendar enumerateDatesStartingAfterDate:[NSDate date]
matchingComponents:leapYearComponents
options:NSCalendarMatchStrictly | NSCalendarSearchBackwards
usingBlock:^(NSDate *date, BOOL exactMatch, BOOL *stop) {
NSLog(@"%@", date);
if (++dateCount == 50) {
*stop = YES;
// 2012-02-29 05:00:00 +0000
// 2008-02-29 05:00:00 +0000
// 2004-02-29 05:00:00 +0000
// 2000-02-29 05:00:00 +0000
// ...
要想找周末的话,记住下面两个 NSCalendar
方法就行:
nextWeekendStartDate(_:interval:options:afterDate)
: 根据传入的前两个参数返回下个周末的开始时间个长度。如果当前的地区和日历未提供对周末属性的支持,该方法会返回 false
。唯一相关的属性是 .SearchBackwards
。(例子在下面。)
rangeOfWeekendStartDate(_:interval:containingDate)
: 根据传入的前两个参数返回 包含 该日期的周末。如果传入的日期并不在周末或者当前的地区和日历未提供对周末属性的支持,该方法会返回 false
。
本地化日期符号
似乎所有这些新功能还不够丰富似的, NSCalendar
还提供了一整套的本地化日期符号,用来快速获取月份名称,星期名称等等。每组符号都列举在两个轴上:(1) 符号的长度 (2) 它是作为标准名称还是日期的一部分。
理解这两个属性对本地化来说十分的重要,有些语言,特别是斯拉夫语言,会依据不同的内容使用不同的名词格。举例来说,一个日期要使用某个 standaloneMonthSymbols
的变体作为头,而不是使用 monthSymbols
去格式化日期。
下面这张表包含了 NSCalendar
提供的所有符号,供大家阅览,请注意俄语列中独立符号的不同之处:
weekdaySymbols
Sunday, Monday, Tuesday, Wednesday…
воскресенье, понедельник, вторник, среда…
shortWeekdaySymbols
Sun, Mon, Tue, Wed…
вс, пн, вт, ср…
veryShortWeekdaySymbols
S, M, T, W…
вс, пн, вт, ср…
standaloneWeekdaySymbols
Sunday, Monday, Tuesday, Wednesday…
Воскресенье, Понедельник, Вторник, Среда…
shortStandaloneWeekdaySymbols
Sun, Mon, Tue, Wed…
Вс, Пн, Вт, Ср…
veryShortStandaloneWeekdaySymbols
S, M, T, W…
В, П, В, С…
AMSymbol
PMSymbol
quarterSymbols
1st quarter, 2nd quarter, 3rd quarter, 4th quarter
1-й квартал, 2-й квартал, 3-й квартал, 4-й квартал
shortQuarterSymbols
Q1, Q2, Q3, Q4
1-й кв., 2-й кв., 3-й кв., 4-й кв.
standaloneQuarterSymbols
1st quarter, 2nd quarter, 3rd quarter, 4th quarter
1-й квартал, 2-й квартал, 3-й квартал, 4-й квартал
shortStandaloneQuarterSymbols
Q1, Q2, Q3, Q4
1-й кв., 2-й кв., 3-й кв., 4-й кв.
eraSymbols
BC, AD
до н. э., н. э.
longEraSymbols
Before Christ, Anno Domini
до н.э., н.э.
你的每周Swift化
在 NSHipster 我们讨论 API 的时候会有一些 Swift 的版本,这渐渐变成了我们的特色。 甚至是在讨论这些全新的 NSCalendar
API的时候,我们需要把前面的方法再打磨一下,将 UnsafeMutablePointer
参数替换为更符合语言习惯的元组返回值。
这里给大家介绍一个非常好用的 NSCalendar
扩展集( 点 我 ),有了它我们使用访问日期组件和搜索周末方法时,可以不用把值传进又传出。比如,获取指定的日期组件就变得简单的多:
// built-in
var hour = 0
var minute = 0
calendar.getHour(&hour, minute: &minute, second: nil, nanosecond: nil, fromDate: NSDate())
// Swift化
let (hour, minute, _, _) = calendar.getTimeFromDate(NSDate())
获取下一个周末的日期范围:
// built-in
var startDate: NSDate?
var interval: NSTimeInterval = 0
let success = cal.nextWeekendStartDate(&startDate, interval: &interval, options: nil, afterDate: NSDate())
if success, let startDate = startDate {
println("start: \(startDate), interval: \(interval)")
// Swift化
if let nextWeekend = cal.nextWeekendAfterDate(NSDate()) {
println("start: \(nextWeekend.startDate), interval: \(nextWeekend.interval)")
这下复杂的日历计算吓不到你们了。有了 NSCalendar
提供的这些新功能,你可以很快的解决你碰到的问题。