Introduction
About Dates and Times
Date和Time对象允许你存储对时间轴上任意一刻的引用。你可以使用Date和time对象进行计算和比较
At a Glance
和dates和times打交道主要有三个类
- NSDate允许你代表时间上的一个绝对值
- NSCalendar允许你代表一个特殊的日历,例如格列高利历或者希伯来历。它提供了大多数基于日期的计算接口,允许你在NSDate和NSDateComponents对象间转换。
- NSDateComponents允许你代表一个特定日期的成分,例如小时,分钟,日,年等等。
除了这些类,NSTimeZone允许你代表一个地理区域的时区信息。这消除了在不同时区工作由于夏时制引起的时间转换。
Creating and Using Date Objects to Represent Absolute Points in Time
日期对象在Cocoa历代表日期和时间。日期对象允许你存储时间中的绝对值。
Working with Calendars and Date Components
日期成分允许你将一个日期拆分为不同的部分,例如日,月,年,小时等等。日历对象允许你在日期对象和日期成分对象之间转换。
Performing Date and Time Calculations
日历和日期成分允许你计算例如日期对象之间的日间隔或者小时间隔,也能够让你找到当前周的星期日。
Working with Different Time Zones
Special Considerations for Historical Dates
Dates
日期对象允许你代表一个日期和时间,日期对象可以用来计算和转换。作为时间上的绝对值,日期对象在不同的区域,时区和日历中都是有意义的。
Date Fundamentals
Cocoa用NSDate对象代表时间和日期。一个日期对象代表时间轴上的一个不变的点。因为日期是时间轴上的一个点,它意味着有日期和时间,所以没有办法定义一个date对象来表示一天但是没有时间。
为了理解Cocoa如何处理dates,你需要考虑NSCalendar和NSDateComponents。在一个不涉及技术的环境,时间轴上的一个点通常是用某个日历上的一天加上时钟来表示。支持不同的日历对于本土化非常重要。在Cocoa,你使用一个特殊的日历来分解date对象,使其具有年,月,日,小时和分。反之,你可以使用一个日历从date成分组建一个date对象。
NSDate提供了创建dates,比较dates和计算间隔的方法。Date对象是不可变的。date对象的时间单位是以NSTimeInterval类型的浮点数。
NSDate计算时间相比格林威治时间2001年1月的第一刻的秒数。在这一刻之前的date用负数存储。之后的date用正数存储。
Creating Date Objects
如果你想要一个代表当前时间的date,你可以allocate一个NSDate对象。
NSDate *now=[[NSDate alloc]init];
或者使用NSDate的类方法date来制造date对象。如果你想要其它的时间,你可以使用NSDate的initWithTimeInterval或者dateWithTimeInterval方法。然而,你通常会使用日历和日期成分来创建日期。
initWithTimeInterval方法以相对某个特殊的时间初始化日期对象。你指定你的日期对象要是相比现在多少秒之前或者多少秒之后。
下面的例子一个是24小时之前,也就是昨天,另一个是明天即24小时之后。
NSTimeInterval secondsPerDay=24*60*60;
NSDate *tomorrow=[[NSDate alloc]initWithTimeInterval:secondsPerDay];
NSDate *yesterDay=[[NSDate alloc]initWithTimeInterval:-secondsPerDay];
[tomorrow release];
[yesterday release];
下面的例子展示了如何使用dateByAddingTimeInterval方法来得到新的日期对象
NSTimeInterval secondsPerDay=24*60*60;
NSDate *today=[[NSDate alloc]init];
NSDate *tomorrow,*yesterday;
tomorrow=[today dateByAddingTimeInterval:secondsPerDay];
yesterday=[today dateByAddingTimeInterval:-secondsPerDay];
[today release]
Basic Date Calculations
为了比较dates,你可以使用isEqualToDate:,compare:,laterDate:和earlierDate:方法。这些方法的比较精度在秒以下。你可能不需要在这么准确的精度做比较。例如,如果两个date差值在一分钟之内,你可能就认为两个date一样。如果这样,使用timeIntervalSinceDate:来比较两个dates。下面的代码片段演示了如何使用这个方法来比较两个dates的差值在一分钟之内。
if(fabs([date2 timeIntervalSinceDate:date1])<60)...
为了获得两个date对象的时间差值,使用timeIntervalSince…消息。例如,timeIntervalSinceNow返回给你date对象和当前时间的差值,秒为单位。
为了获得date的成分元素,使用NSDateComponents对象和NSCalendar对象。
Calendars,Date Components,and Calendar Units
日历对象封装了清算时间的系统信息,在这个系统中,定义了一年的长度,起始和分割。你使用日历对象来转换绝对时间和日期成分,例如年,月,日。
Calendar Basics
NSCalendar提供了不同日历的实现。它提供了几个不同日历的数据,包括佛教徒的,格列历,希伯来历,伊斯兰教历和日本历(提供的日历是有操作系统决定的)。NSCalendar和NSDateComponents类密切相关。
下面的例子演示了如何创建一个日本日历和当前用户的日历
NSCalendar *currentCalendar=[NSCalendar currentCalendar];
NSCalendar *japaneseCalendar=[[NSCalendar alloc]initWithCalendarIdentifier:NSJapaneseCalendar];
NSCalendar *usersCalendar=[[NSLocale currentLocale] objectForKey:NSLocaleCalendar];
这里currentCalendar和usersCalendar是一样的,虽然它们是不同的对象。
Date Components and Calendar Units
你可以使用NSDateComponents来代表一个date的成分,例如年,日和小时。下面的例子向你展示了如何创建一个date成分。
NSDateComponents *components=[[NSDateComponents alloc]init];
[components setDay:6];
[components setMonth:5];
[components setYear:2004];
Converting between Dates and Date Components
将一个date分解为一个date成分,你使用NSCalendar的components:fromDate:。除了这个date以外,你需要指定返回的NSDateComponents对象包括的成分。对此,这个方法需要一个由Calendar Units构成的位掩码。
NSDate *date=[NSDate date];
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents=[gregorian components:(NSDayCalendarUnit|NSWeekdayCalendarUnit) fromDate:today];
NSInteger day=[weekdayComponents day];
NSInteger weekday=[weekdayComponents weekday];
这给了你一个date的绝对成分。如果你想要知道这是一年的第几天,你可以使用ordinalityOfUnit:inUnit:forDate:。
从成分得到date也是可以的。你配置一个NSDateComponents来指定date的成分,然后使用NSCalendar的dateFromComponents:来生成相应的date对象。你可以提供你需要的成分。下面的例子显示了如何创建一个date对象。
NSDateComponents *components=[[NSDateComponents alloc]init];
[components setWeekDay:2];
[components setWeekdayOrdinal:1];
[components setMonth:5];
[components setYear:2008];
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date=[gregorian dateFromComponents:components];
你必须确保你提供的成分在对应的日历中是有意义的。例如在格列历中2月20日会生成不确定的行为。
Converting from One Calendar to Another
将一个date的成分从一个日历转换到另一个日历-例如从格列历转换到希伯来历-你首先使用第一个日历从成分中获取date对象,然后使用第二个日历将date对象分解为不同的成分。下面的例子掩饰了如何从一个日历转化另一个日历。
NSDateComponents *comps=[[NSDateComponents alloc]init];
[comps setDay:6];
[comps setMonth:5];
[comps setYear:2004];
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date=[gregorian dateFromComponents:comps];
[comps release];
[gregorian release];
NSCalendar *hebrew=[[NSCalendar alloc]initWithCalendarIdentifier:NSHebrewCalendar];
NSUInterger unitFlags=NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit
NSDate *components=[hebrew components:unitFlags fromDate:date];
NSInteger day=[components day];
NSInteger month=[components month];
NSInteger year=[components year];
Performing Calendar Calculations
NSDate提供了时间和日期的绝对值,可以被渲染到一个特定的日历中用于计算或者用户显示。为了进行日历计算,你通常需要得到date的成分元素,例如年,月和日。
Adding Components to a Date
你使用dateByAddingComponents:toDate:options:方法将components增加到某个date上。下面的例子显示了如何计算一个半小时之后的date。
NSDate *date=[[NSDate alloc]init];
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents=[[NSDateComponents alloc]init];
[offsetComponents setHour:1];
[offsetComponents setMinute:30];
NSDate *endOfWorldWar3=[gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
成分可以是负的,下面的例子显示了你如何得到当前周的Sunday
NSDate *today=[[NSDate alloc]init];
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents=[gregorian components:NSWeekdayCalendarUnit fromDate:today];
NSDateComponents *componentsToSubtract=[[NSDateComponents alloc]init];
componentsToSubtract setDay:0-([weekdayComponents weekday]-1);
NSDate *beginningOfWeek=[gregorian dateByAddingComponents:componentsToSubtract toDate:today options:];
在所有的地域中星期天不都是一个星期的第一天。
NSDate *today=[NSDate alloc]init];
NSDate *beginningOfWeek=nil;
BOOL ok=[gregorian rangeOfUnit:NSWeekCalendar startDate:&beginningOfWeek interval:NULL forDate:today];
Determining Temporal Differences
计算dates之间的时间有很多方法。你可以使用components:fromDate:toDate:options来计算两个date之间的差值,单位不是秒(timeIntervalSinceDate:)下面的例子说明了这点
NSDate *startDate=....;
NSDate *endDate=...;
NSCalendar *gregorian=[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags=NSMonthCalendarUnit|NSDayCalendarUnit;
NSDateComponents *components=[gregorian components:unitFlags fromDate:StartDate toDate:endDate options:0];
NSInteger months=[components month];
NSInteger days=[compnents day];
这个方法处理溢出。如果这个方法的参数间隔一年又三天,而你只询问间隔的日子,这个方法会返回NSDateComponents对象,对象的day成分为368或者369.然后这个方法也会对返回的结果作最小单位的截断,如果两个dates间隔8.5小时,而你询问间隔的日数,返回是0。下面的例子显示了你可以使用NSCalendar的一个category来询问实际间隔为小时以天数为返回结果的情况。
@implementation NSCalendar(MySpecialCalculations)
-(NSInteger)daysWithinEraFromDate:(NSDate *)startDate toDate:(NSDate *)endDate
{
NSInteger startDay=[self ordinalityOfUnit:NSDayCalendarUnit in Unit:NSEraCalendarUnit for Date:startDate];
NSInteger endDay=[self ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:endDate];
return endDay-startDay;
}
不要使用这个方法来计算以秒为单位的差距,因为在32bit的平台上会溢出。这个方法有效的前提还有一个,这两个date是同一个纪元,在格列历中意味着都是AC或者BC。
Checking When a Date Falls
如果你需要判断一个date是否落入当前这周(或者任意单位)你可以使用NSCalendar的rangeOfUnit:startDate:interval:forDate:
-(BOOL)isDateThisWeek:(NSDate *)date{
NSDate *start;
NSTimeInterval extends;
NSCalendar *cal=[NSCalendar autoupdatingCurrentCalendar];
NSDate *today=[NSDate date]'
BOOL success=[cal rangeOfUnit:NSWeekCalendarUnit startDate:&start interval:&extends forDate:today];
if(!success)return NO;
NSTimeInterval dateInSecs=[date timeIntervalSinceReferenceDate];
NSTimeInterval dayStartInSecs=[start timeIntervalSinceReferenceDate];
if(dateInSecs>dayStartInSecs**dateInSecs<(dayStartInsecs+extends)){
return YES;
}
else{
return NO;
}
}