一、基本约定及要素
现代系统对于日期时间的处理思想,是系统统一以 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 小时
(完)