系統梳理 Objective-C 中 NSDate、NSDateComponents、NSCalendar、NSDateFormatter、NSTimer 的核心用法與常見陷阱。
NSDate:不可變時間點(參考日期:2001-01-01 00:00:00 UTC)NSDateComponents:日期構成要素(年月日時分秒、時區)NSCalendar:日曆運算邏輯(公曆/農曆、時區轉換、日期計算)NSDateFormatter:日期↔字符串格式化雙向轉換NSTimer:定時觸發機制NSDate *now = [NSDate date]; NSLog(@"%@", now); // 2024-01-15 08:30:45 +0000
NSDateComponents *comp = [[NSDateComponents alloc] init]; comp.year = 2007; comp.month = 6; comp.day = 29; comp.hour = 12; comp.minute = 1; comp.second = 31; comp.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"PDT"]; NSCalendar *cal = [NSCalendar currentCalendar]; NSDate *iPhoneRelease = [cal dateFromComponents:comp];
// 相等判斷
if ([date1 isEqualToDate:date2]) ...
// 早/晚
NSDate *earlier = [date1 earlierDate:date2];
NSDate *later = [date1 laterDate:date2];
// 秒數差
NSTimeInterval sec = [date1 timeIntervalSinceDate:date2];
// 日曆單位差(年/月/日)
NSDateComponents *diff = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay
fromDate:date1 toDate:date2 options:0];
NSInteger years = diff.year, months = diff.month, days = diff.day;
NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = @"MM/dd/yyyy"; // 解析格式 NSDate *date = [fmt dateFromString:@"02/14/2012"]; fmt.dateFormat = @"EEEE, MMMM d"; // 顯示格式 NSString *str = [fmt stringFromDate:date]; // "Tuesday, February 14"
NSDateComponents *offset = [[NSDateComponents alloc] init]; offset.week = -1; // 前一周 NSDate *shoppingDay = [cal dateByAddingComponents:offset toDate:valentinesDay options:0];
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:10]; // 10秒後首次觸發
NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate
interval:2 // 間隔2秒
target:self
selector:@selector(task:)
userInfo:@"custom data"
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// 停止
[timer invalidate];
NSDate 內部為 UTC,顯示/解析需明確設置 timeZoneYYYY(周曆年)與 yyyy(日曆年),跨年週邊易錯RunLoop,且強引用 timer 防止釋放NSCalendarUnit 在 iOS 8+ 改為 NSCalendarUnitYear 等枚舉常量iOS 10+ 推薦使用 Date、DateComponents、Calendar、DateFormatter、Timer (Swift 原生/Foundation 重構版),API 更符合 Swift 慣用語,線程安全性更好。