一、基本約定及要素
現代系統對于日期時間的處理思想,是系統統一以 UTC 時間為準。在需要時,根據時區、日歷、國際化/本地化等設置,依據 UTC 時間計算出所需要的時間,用于顯示等操作。所以,理論上,世界上任何一臺電腦,只要時鐘是準的,獲取到的 UTC 時間是一致的。只是系統會根據我們在電腦中設定的時區、日歷、國際化/本地化等信息,再進行展示。
iOS 中,主要涉及到的類如下:
-
NSDate
主要用于日期的獲取、存儲、計算 -
NSDateComponents
工具類,用于對于日期、時間的拆分、組裝 -
NSCalendar
日歷,通過指定不同日歷類型,來獲取對應的信息。如:獲取當前時間的農歷月、日信息。 -
NSLocale
區域化相關內容。此類不僅用于日期時間,本文只涉及日期時間的部分。
如:獲取當前時間月份的名稱,區域為美國會顯示May
,區域為中國會顯示五月
-
NSTimeZone
時區。用于配合 UTC 時間計算指定的時區對應的時間。 -
NSDateFormatter
日期、時間格式化工具。格式化時,會根據用戶指定的格式、時區、地區,進行處理。
二、一些綜合應用
1、從字符串轉化為時間
有些場景需要根據存儲的字符串轉換回時間。比如:HTTP 的 Response Header 的 Date 字段,格式為:Sun, 01 Apr 2018 01:18:07 GMT
,需要轉換回 NSDate
,才便于后續處理。
- (NSDate *)dateFromString:(NSString *)dateStr {
// 創建日期格式化工具
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
// 指定日期格式,如上所示:Sun, 01 Apr 2018 01:18:07 GMT
dateFormatter.dateFormat = @"EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss 'GMT'";
// 指定區域,這個很重要!EEE、MMM 會根據區域設置進行處理。如果這里設置為中文,則只能處理 “四月”、“周日”,而不能處理 “Apr”、“Sun”
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en"];
// 指定所使用的是 UTC 時間
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
return [dateFormatter dateFromString:dateStr];
}
根據當前時間,格式化輸出,操作類似。
2、獲取當前時間的公歷、農歷日期
- (void)showDate {
// 當前日期
NSDate *date = [NSDate date];
// 創建公歷日歷,此為默認值
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
// 獲取月、日
NSDateComponents *dateComponents = [calendar components:NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
NSLog(@"公歷日期:%ld-%ld", dateComponents.month, dateComponents.day);
// 創建中國農歷日歷
calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
// 獲取月、日
dateComponents = [calendar components:NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
NSLog(@"農歷日期:%ld-%ld", dateComponents.month, dateComponents.day);
}
3、計算時間間隔
測試代碼塊耗時,單位:納秒
#import <mach/mach_time.h>
CGFloat BNRTimeBlock (void (^block)(void)) {
// 獲取計時基礎信息
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS) return -1.0;
// 開始時間
uint64_t start = mach_absolute_time ();
// 執行代碼塊
block ();
// 結束時間
uint64_t end = mach_absolute_time ();
// 計算時間差
uint64_t elapsed = end - start;
// 根據系統“心率”計算時間
uint64_t nanos = elapsed * info.numer / info.denom;
return (CGFloat)nanos / NSEC_PER_SEC;
} // BNRTimeBlock
除此方法外,可以采用更為方便的 CACurrentMediaTime()
,返回單位為秒。這個是對 mach_absolute_time()
的封裝,使用起來更方便一些。
三、備查資料
1、NSTimeZone
初始化
使用 + timeZoneWithName:
獲取已知的有效時區名稱:NSTimeZone.knownTimeZoneNames
,返回數組
注:北京時間在 iOS 的 TimeZone 對照表里面并沒有,使用上海時間代表中國標準時
采用如下方式初始化即可:
// 初始化時區為 上海時間
[NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
使用 + timeZoneWithAbbreviation:
獲取有效縮寫:[NSTimeZone abbreviationDictionary]
,返回字典
2、NSCalendar
初始化
// 公歷
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
// 中國農歷
calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
具體日歷類型,參見 NSCalendarIdentifier
類型。
3、NSDateFormatterStyle
typedef NS_ENUM(NSUInteger, NSDateFormatterStyle) { // date and time format styles
NSDateFormatterNoStyle = kCFDateFormatterNoStyle,
NSDateFormatterShortStyle = kCFDateFormatterShortStyle, // “11/23/37” or “3:30pm”.
NSDateFormatterMediumStyle = kCFDateFormatterMediumStyle, //“Nov 23, 1937”.or “3:30:32pm”.
NSDateFormatterLongStyle = kCFDateFormatterLongStyle, //“November 23, 1937” or “3:30:32pm”. GMT+08:00
NSDateFormatterFullStyle = kCFDateFormatterFullStyle //“Tuesday, April 12, 1952 AD” or “3:30:42pm PST”.
};
這里假設的是區域設置為美國的情況,具體的格式,還跟 locale
設置有關。
常見 dateFormat
符號 | 說明 |
---|---|
a | AM/PM (上午/下午) |
c/cc | 1~7 (一周的第一天, 周日為1) |
ccc | Sun/Mon/Tue/Wed/Thu/Fri/Sat (星期幾簡寫) |
cccc | Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday (星期幾全拼) |
d | 1~31 (月份的第幾天, 帶0) |
D | 1~366 (年份的第幾天,帶0) |
e | 1~7 (一周的第幾天, 帶0) |
E~EEE | Sun/Mon/Tue/Wed/Thu/Fri/Sat (星期幾簡寫) |
EEEE | Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday (星期幾全拼) |
F | 1~5 (每月的第幾周, 一周的第一天為周一) |
h | 1~12 (0 padded Hour (12hr)) 帶0的時, 12小時制 |
H | 0~23 (0 padded Hour (24hr)) 帶0的時, 24小時制 |
m | 0~59 (0 padded Minute) 分鐘 |
M/MM | 1~12 (0 padded Month) 第幾月 |
MMM | Jan/Feb/Mar/Apr/May/Jun/Jul/Aug/Sep/Oct/Nov/Dec |
MMMM | January/February/March/April/May/June/July/August/September/October/November/December |
s | 0~59 (0 padded Second) 秒數 |
SSS | (rounded Sub-Second) 毫秒 |
w | 1~53 (0 padded Week of Year, 1st day of week = Sunday, NB: 1st week of year starts from the last Sunday of last year) 一年的第幾周, 一周的開始為周日,第一周從去年的最后一個周日起算 |
W | 1~5 (0 padded Week of Month, 1st day of week = Sunday) 一個月的第幾周 |
y/yyyy | (Full Year) 完整的年份 |
yy/yyy | (2 Digits Year) 2個數字的年份 |
Y/YYYY | (Full Year, starting from the Sunday of the 1st week of year) 這個年份未知干嘛用的 |
YY/YYY | (2 Digits Year, starting from the Sunday of the 1st week of year) 這個年份未知干嘛用的 |
z~zzz | (Specific GMT Timezone Abbreviation) 指定GMT時區的編寫 |
zzzz | (Specific GMT Timezone Name) Z: +0000 (RFC 822 Timezone) 指定GMT時區的名稱 |
詳見
Date Format Patterns
Date Field Symbol Table
4、時間進制換算
1 秒(s) == 1000 毫秒(ms)
1 毫秒(ms) == 1000 微秒(μs)
1 微秒(μs) == 1000 納秒(ns)
四、參考資料
- mach_absolute_time 使用
- iOS關于時間的處理
- Benchmarking
- iOS 如何獲取一個更為靠譜的當前時間
- NSDateFormatter格式詳細列表一覽
- ios時間那點事--NSCalendar NSDateComponents
- NSCalendar 日歷類
- NSDate、NSTimeInterval、NSDateFormatter、NSLocale 、NSTimeZone、NSDateComponents詳解
- iOS-NSDate 相差 8 小時
(完)