iOS 日期時(shí)間那點(diǎn)兒事兒

一、基本約定及要素

現(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)

四、參考資料

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 像小強(qiáng)一樣活著閱讀 3,650評(píng)論 6 16
  • iOS開(kāi)發(fā)中,經(jīng)常會(huì)遇到各種各樣的時(shí)間問(wèn)題,8小時(shí)時(shí)差,時(shí)間戳,求時(shí)間間隔,農(nóng)歷等等。解決辦法網(wǎng)上比比皆是,但大多...
    小李龍彪閱讀 6,430評(píng)論 1 6
  • 在iOS開(kāi)發(fā)中,經(jīng)常會(huì)遇到各種各樣的時(shí)間問(wèn)題,8小時(shí)時(shí)差,時(shí)間戳,求時(shí)間間隔,農(nóng)歷等等。解決辦法網(wǎng)上比比皆是,但大...
    真巧了_嘿閱讀 2,818評(píng)論 0 7
  • 今晚我用手機(jī)看(開(kāi)學(xué)第一課),剛開(kāi)始看的時(shí)候,是吳磊,撒貝寧,還有同學(xué)們猜字游戲,挺有意思的。在采訪許淵沖(許老)...
    街舞少女閱讀 197評(píng)論 0 0