在iOS開發中,經常會遇到各種各樣的時間問題,8小時時差,時間戳,求時間間隔,農曆等等。解決辦法網上比比皆是,但大多零零散散,很多資料並沒有說明其中問題。這裏集中總結一下,以便於以後查閱和供大家參考。有我自己的理解,錯漏之處請大家吐槽。
NSDate的8小時問題
NSDate轉字符串時間
初始化一個NSDate
時間[NSDate date]
,獲取的是零時區的時間(格林尼治的時間: 年-月-日 時:分:秒: +時區),而北京時間是東八區時間,因爲時區不同,所以打印的時間相差了8小時。此刻表示的時間是一樣的。
|
|
打印結果:
|
|
打印結果前面的時間是北京時間:2016-12-07 10:44:24.470
。而date
打印出來的時間顯示少了8小時,因爲它表示的是零時區(+0000)
時間02:44:24
。此刻對應東八區的北京時間就是10:44:24
。只是時區不同,表示的時間點是一樣的。好比1公斤和2斤,重量是一樣的。[NSDate date]
獲取的時間單位是零時區(+0000)
,我們所要的北京時間的單位是東八區(+0800)
。
系統會默認[NSDate date]
獲取的時間爲零時區時間,而經過NSDateFormatter
轉化爲字符串時間就是當前所在時區的準確時間,並沒有8小時誤差。
轉字符串時間的時區設定
上文中NSDate時間轉爲字符串時間並沒有設置NSDateFormatter
的timeZone
。不設置會默認使用當前所在的時區,與設置系統時區formatter.timeZone = [NSTimeZone systemTimeZone]
的效果是一樣的。
也可以設置時區,獲取指定時區的字符串時間
|
|
這時獲取的時間就是東八區時間,哪怕手機拿到零時區的格林尼治,獲取的也是東八區的時間,因爲這裏指定時區了。也有如下時區指定:
|
|
通過下面方法可得到系統支持的時區對應的字符串常量:
|
|
字符串時間轉NSDate
字符串時間轉爲NSDate時間也會有時區問題。也會遇到有所謂的8小時誤差,其實就是時區不同。比如下面的例子:
|
|
打印結果:
|
|
NSDateFormatter
的指定格式是:@"yyyy-MM-dd HH:mm:ss Z"
。這裏面的Z
指的是時區。要轉化的字符串時間格式必須和這個格式匹配,上面給定的字符串時間是:@"2016-12-07 14:06:24 +0800"
,是一個東八區時間,轉化爲NSDate後是零區時間2016-12-07 06:06:24 +0000
,字面顯示上少了8小時,其實時間一樣。
其實如果上面給定的字符串時間爲@"2016-12-07 14:06:24 +0000"
,轉化出來的NSDate時間會完全一樣,因爲字符串時間爲零時區時間,不存在時區誤差。大家可以試一下。
當不指定字符串時間的時區時,即沒有後面的+0800
,同時要把NSDateFormatter
時間格式裏的Z
去掉,保證格式匹配。系統會認爲字符串時間是系統所在時區的時間,轉化爲NSDate時間是零時區時間。
同樣,也可以使用formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
這種方式指定字符串時間的時區,和用Z
對應+0000
是一樣的。
NSDate轉當前時區的NSDate時間
因爲[NSDate date]
得出的時間是零時區時間,當我們要獲取當前所在時區的NSDate時間時,通常會用以下方法:
|
|
打印結果:
|
|
上面代碼中zone
是當前時區,interval
是當前時區和零時區時間的差值,最後結果localDate
是零時區時間date
加上這個差值interval
,得到當前時區的NSDate時間。更有甚者,在開發中直接加8*60*60
或28800
這樣的值,因爲相差8小時嘛。這樣在東八區沒問題,在其他時區時間就錯了。
其實這種做法是不科學的,因爲得到的最終時間還是零時區時間,時間後面明顯是+0000
,在使用中一般不顯示時區,所以認爲當做當前時區的時間使用也未嘗不可。此爲大坑!
坑1:這時如果轉爲字符串時間,又會增加8小時。因爲做時間轉換的時候,系統會認爲這個NSDate是零時區,得到的字符串時間是東八區的。
解決辦法是:將錯就錯,字符串時間也設置爲零時區的字符串時間。從深坑跌入更深的坑!
|
|
這裏的@"UTC"
是指世界標準時間,也是現在用的時間標準,東八區比這個時間也是快8小時,這裏填@"GMT"
也是可以的。
坑2:在與後臺交互時,有時需要+0000
時區,這時只能手動拼接字符串更改這個時區字段,改爲正確的時區。
所以,在開發中儘量不要這麼做,當時間要求顯示、存儲或與後臺交互的時候,使用字符串時間!不要使用轉化的NSDate。
時間換算,時間戳的概念
當前時間轉時間戳
時間戳是指1970年1月1日0時0分0秒到當前時間的秒數。注意:這裏的當前時間是指零時區的NSDate時間。
|
|
打印結果:
|
|
時間戳轉當前時間
|
|
打印結果:
|
|
注意時間戳使用的NSDate時間是當前零時區的時間!當前零時區時間!當前零時區時間!重要的事情說三遍!不要進行NSDate轉當前時區的NSDate時間,再轉時間戳。下面是驗證:
|
|
打印結果:
|
|
問題解釋詳見上文的NSDate轉當前時區的NSDate時間
。
時間操作與比較
時間初始化和比較方法
幾個時間初始化方法:
|
|
幾個時間比較方法:
|
|
幾個計算時間間隔的方法:
|
|
獲取年月日時分秒周時區
oc裏的時間坑太多,根本沒辦法像其他語言那樣直接time.year就能獲取年份。要想獲取NSDate的年月日需要使用日曆對象NSCalendar
。
|
|
打印結果:
|
|
NSDateComponents
創建方法中添加的枚舉NSCalendarUnit
,是後面要獲取的年月日時分秒必須對應添加的。比如要獲取年dateComps.year
,就需要添加枚舉NSCalendarUnitYear
。
可以看到,[NSDate date]
時間可以使用NSCalendar
直接獲取當前時區的時分秒,打印的時
和時區
即可看出。這是[NSCalendar currentCalendar]
日曆對象初始化的原因,也可以用[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]
指定Identifier的方式初始化陽曆日曆。可以試試指定Identifier爲NSCalendarIdentifierChinese
,打印的是中國農曆。
dateComps.weekOfMonth
是今天屬於本月的第幾周。
dateComps.weekOfYear
是今天屬於本年的第幾周。
dateComps.weekday
是星期,這個和日常使用有些不同。上述程序打印的是周=4
,但2016-12-07是週三
。這裏weekday
的對應關係是:週日-1,週一-2,週二-3,週三-4,週四-5,週五-6,週六-7。畢竟國外慣例週日是每週的第一天。
農曆
獲取農曆的工具方法,可根據需求添加農曆節日和二十四節氣
|
|
轉自:http://markmiao.com/2016/12/08/iOS%E6%97%B6%E9%97%B4%E9%97%AE%E9%A2%98/#NSDate轉當前時區的NSDate時間