一、基本約定及要素
現(xiàn)代系統(tǒng)對(duì)于日期時(shí)間的處理思想,是系統(tǒng)統(tǒng)一以 UTC 時(shí)間為準(zhǔn)。在需要時(shí),根據(jù)時(shí)區(qū)、日歷、國(guó)際化/本地化等設(shè)置,依據(jù) UTC 時(shí)間計(jì)算出所需要的時(shí)間,用于顯示等操作。所以,理論上,世界上任何一臺(tái)電腦,只要時(shí)鐘是準(zhǔn)的,獲取到的 UTC 時(shí)間是一致的。只是系統(tǒng)會(huì)根據(jù)我們?cè)陔娔X中設(shè)定的時(shí)區(qū)、日歷、國(guó)際化/本地化等信息,再進(jìn)行展示。
iOS 中,主要涉及到的類(lèi)如下:
-
NSDate
主要用于日期的獲取、存儲(chǔ)、計(jì)算 -
NSDateComponents
工具類(lèi),用于對(duì)于日期、時(shí)間的拆分、組裝 -
NSCalendar
日歷,通過(guò)指定不同日歷類(lèi)型,來(lái)獲取對(duì)應(yīng)的信息。如:獲取當(dāng)前時(shí)間的農(nóng)歷月、日信息。 -
NSLocale
區(qū)域化相關(guān)內(nèi)容。此類(lèi)不僅用于日期時(shí)間,本文只涉及日期時(shí)間的部分。
如:獲取當(dāng)前時(shí)間月份的名稱(chēng),區(qū)域?yàn)槊绹?guó)會(huì)顯示May
,區(qū)域?yàn)橹袊?guó)會(huì)顯示五月
-
NSTimeZone
時(shí)區(qū)。用于配合 UTC 時(shí)間計(jì)算指定的時(shí)區(qū)對(duì)應(yīng)的時(shí)間。 -
NSDateFormatter
日期、時(shí)間格式化工具。格式化時(shí),會(huì)根據(jù)用戶(hù)指定的格式、時(shí)區(qū)、地區(qū),進(jìn)行處理。
二、一些綜合應(yīng)用
1、從字符串轉(zhuǎn)化為時(shí)間
有些場(chǎng)景需要根據(jù)存儲(chǔ)的字符串轉(zhuǎn)換回時(shí)間。比如:HTTP 的 Response Header 的 Date 字段,格式為:Sun, 01 Apr 2018 01:18:07 GMT
,需要轉(zhuǎn)換回 NSDate
,才便于后續(xù)處理。
- (NSDate *)dateFromString:(NSString *)dateStr {
// 創(chuàng)建日期格式化工具
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
// 指定日期格式,如上所示:Sun, 01 Apr 2018 01:18:07 GMT
dateFormatter.dateFormat = @"EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss 'GMT'";
// 指定區(qū)域,這個(gè)很重要!EEE、MMM 會(huì)根據(jù)區(qū)域設(shè)置進(jìn)行處理。如果這里設(shè)置為中文,則只能處理 “四月”、“周日”,而不能處理 “Apr”、“Sun”
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en"];
// 指定所使用的是 UTC 時(shí)間
dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
return [dateFormatter dateFromString:dateStr];
}
根據(jù)當(dāng)前時(shí)間,格式化輸出,操作類(lèi)似。
2、獲取當(dāng)前時(shí)間的公歷、農(nóng)歷日期
- (void)showDate {
// 當(dāng)前日期
NSDate *date = [NSDate date];
// 創(chuàng)建公歷日歷,此為默認(rèn)值
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
// 獲取月、日
NSDateComponents *dateComponents = [calendar components:NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
NSLog(@"公歷日期:%ld-%ld", dateComponents.month, dateComponents.day);
// 創(chuàng)建中國(guó)農(nóng)歷日歷
calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
// 獲取月、日
dateComponents = [calendar components:NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
NSLog(@"農(nóng)歷日期:%ld-%ld", dateComponents.month, dateComponents.day);
}
3、計(jì)算時(shí)間間隔
測(cè)試代碼塊耗時(shí),單位:納秒
#import <mach/mach_time.h>
CGFloat BNRTimeBlock (void (^block)(void)) {
// 獲取計(jì)時(shí)基礎(chǔ)信息
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS) return -1.0;
// 開(kāi)始時(shí)間
uint64_t start = mach_absolute_time ();
// 執(zhí)行代碼塊
block ();
// 結(jié)束時(shí)間
uint64_t end = mach_absolute_time ();
// 計(jì)算時(shí)間差
uint64_t elapsed = end - start;
// 根據(jù)系統(tǒng)“心率”計(jì)算時(shí)間
uint64_t nanos = elapsed * info.numer / info.denom;
return (CGFloat)nanos / NSEC_PER_SEC;
} // BNRTimeBlock
除此方法外,可以采用更為方便的 CACurrentMediaTime()
,返回單位為秒。這個(gè)是對(duì) mach_absolute_time()
的封裝,使用起來(lái)更方便一些。
三、備查資料
1、NSTimeZone
初始化
使用 + timeZoneWithName:
獲取已知的有效時(shí)區(qū)名稱(chēng):NSTimeZone.knownTimeZoneNames
,返回?cái)?shù)組
注:北京時(shí)間在 iOS 的 TimeZone 對(duì)照表里面并沒(méi)有,使用上海時(shí)間代表中國(guó)標(biāo)準(zhǔn)時(shí)
采用如下方式初始化即可:
// 初始化時(shí)區(qū)為 上海時(shí)間
[NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
使用 + timeZoneWithAbbreviation:
獲取有效縮寫(xiě):[NSTimeZone abbreviationDictionary]
,返回字典
2、NSCalendar
初始化
// 公歷
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
// 中國(guó)農(nóng)歷
calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierChinese];
具體日歷類(lèi)型,參見(jiàn) NSCalendarIdentifier
類(lèi)型。
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”.
};
這里假設(shè)的是區(qū)域設(shè)置為美國(guó)的情況,具體的格式,還跟 locale
設(shè)置有關(guān)。
常見(jiàn) dateFormat
符號(hào) | 說(shuō)明 |
---|---|
a | AM/PM (上午/下午) |
c/cc | 1~7 (一周的第一天, 周日為1) |
ccc | Sun/Mon/Tue/Wed/Thu/Fri/Sat (星期幾簡(jiǎn)寫(xiě)) |
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 (星期幾簡(jiǎn)寫(xiě)) |
EEEE | Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday (星期幾全拼) |
F | 1~5 (每月的第幾周, 一周的第一天為周一) |
h | 1~12 (0 padded Hour (12hr)) 帶0的時(shí), 12小時(shí)制 |
H | 0~23 (0 padded Hour (24hr)) 帶0的時(shí), 24小時(shí)制 |
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) 秒數(shù) |
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) 一年的第幾周, 一周的開(kāi)始為周日,第一周從去年的最后一個(gè)周日起算 |
W | 1~5 (0 padded Week of Month, 1st day of week = Sunday) 一個(gè)月的第幾周 |
y/yyyy | (Full Year) 完整的年份 |
yy/yyy | (2 Digits Year) 2個(gè)數(shù)字的年份 |
Y/YYYY | (Full Year, starting from the Sunday of the 1st week of year) 這個(gè)年份未知干嘛用的 |
YY/YYY | (2 Digits Year, starting from the Sunday of the 1st week of year) 這個(gè)年份未知干嘛用的 |
z~zzz | (Specific GMT Timezone Abbreviation) 指定GMT時(shí)區(qū)的編寫(xiě) |
zzzz | (Specific GMT Timezone Name) Z: +0000 (RFC 822 Timezone) 指定GMT時(shí)區(qū)的名稱(chēng) |
詳見(jiàn)
Date Format Patterns
Date Field Symbol Table
4、時(shí)間進(jìn)制換算
1 秒(s) == 1000 毫秒(ms)
1 毫秒(ms) == 1000 微秒(μs)
1 微秒(μs) == 1000 納秒(ns)
四、參考資料
- mach_absolute_time 使用
- iOS關(guān)于時(shí)間的處理
- Benchmarking
- iOS 如何獲取一個(gè)更為靠譜的當(dāng)前時(shí)間
- NSDateFormatter格式詳細(xì)列表一覽
- ios時(shí)間那點(diǎn)事--NSCalendar NSDateComponents
- NSCalendar 日歷類(lèi)
- NSDate、NSTimeInterval、NSDateFormatter、NSLocale 、NSTimeZone、NSDateComponents詳解
- iOS-NSDate 相差 8 小時(shí)
(完)