iOS 日期時間那點兒事兒

一、基本約定及要素

現代系統對于日期時間的處理思想,是系統統一以 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)

四、參考資料

(完)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • iOS開發中,經常會遇到各種各樣的時間問題,8小時時差,時間戳,求時間間隔,農歷等等。解決辦法網上比比皆是,但大多...
    小李龍彪閱讀 6,382評論 1 6
  • 在iOS開發中,經常會遇到各種各樣的時間問題,8小時時差,時間戳,求時間間隔,農歷等等。解決辦法網上比比皆是,但大...
    真巧了_嘿閱讀 2,798評論 0 7
  • 今晚我用手機看(開學第一課),剛開始看的時候,是吳磊,撒貝寧,還有同學們猜字游戲,挺有意思的。在采訪許淵沖(許老)...
    街舞少女閱讀 193評論 0 0