NSDate 8小時問題-沒你想的那么簡單!

說在前面

公司項目出了問題之后,上網差了很多資料,最后就有一個還是比較靠譜,剩下的都是說8小時,太膚淺,今天將這些問題列出,順便給NSDate做個記錄,最后po出解決公司問題的方法

項目除了什么問題?
  • 1.返回的時間戳好像是差了8小時
  • 2.項目中的時間分類好多,不知道那個是有用的
  • 3.項目中選擇了datePicker,獲得了一個時間,然后顯示,最后傳給后臺,結果時間多了8小時?
基礎知識普及

1.什么是UTC?
世界標準時間,國際協調時間,簡稱UTC。不屬于任意時區
2.啥事時間戳?就是1970.1.1 00:00:00作為標準,某個時間和他的秒數,并且NSDate必須是0時區的,UTC格式的
3.時間戳應該是10位,如果不巧碰到了13位的,代表著他計算了毫秒,只要刪除剪切前十位就行了

詳細的講解NSDate,一定有你不知道的知識

一.獲取當前時間 (NSDate),(NSDate -> NSString)

現在是北京時間
   //1.打印當前時間
    NSDate *date = [NSDate date];
    NSLog(@"當前時間%@",date);

    //2.打印出2011-11-12 23:10:34這種格式
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateStr = [dateFormatter stringFromDate:date];
    NSLog(@"字符串表示1:%@",dateStr);
    
   //3.打印出2013年12月22日 12時34分56秒這個格式
    NSDateFormatter *dateFormaterA = [[NSDateFormatter alloc]init];
    [dateFormaterA setDateFormat:@"yyyy年MM年dd日 HH時mm分ss秒"];
    NSString *dateStrA = [dateFormaterA stringFromDate:date];
    NSLog(@"%@",dateStrA);

打印結果

當前時間   :2016-08-24 14:16:47 +0000
字符串表示1:2016-08-24 22:16:47
字符串表示2:2016年08年24日 22時16分47秒

解釋

  • 1.[NSDate date]獲取的數據為什么少了8小時?
    是因為他獲取的是零時區的時間顯示的是格林尼治的時間: 年-月-日 時:分:秒:+時區,我們在東八區,所以會有8小時的問題,系統是沒有毛病的
  • 2.第二個打印,和第三個打印有什么異同點?
    2.1 相同點:都是獲取的正確的北京時間,沒有8小時的問題(因為系統認為NSDate是0時區的,轉換成字符串應該是當前時區的,所以沒問題)
    2.2 相同點:都是NSDate -> NSString,而且轉成字符串的文字格式多樣,主要依賴DateFormat,但是可以隨意確定DateFormat格式,都能輸出。(但是NSString -> NSDate不可以隨便的轉換,必須要看NSString是什么格式的,然后再去寫dateFormat,否則無效)
    2.3 不同點:格式不同算嗎??

二.獲取北京時間,獲取昨天此刻,獲取明天此刻,昨天和今天的時間差 (NSDate -> NSDate)

10:36分,北京時間
- (void)test3{
    
    //1.獲取當前時間 零時區的時間
    NSDate *date = [NSDate date];
    NSLog(@"當前零時區時間 %@", date);
    
    //2.獲得本地時間 東八區 晚八個小時 以秒計時
    NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:8 * 60 * 60];
    NSLog(@"今天此時的時間 %@",date1);
    
    //3.昨天此時的時間
    NSDate *yesterdayDate = [NSDate dateWithTimeIntervalSinceNow:(-24 + 8) * 60 * 60];
    NSLog(@"昨天此時的時間 %@",yesterdayDate);
    
    //4.明天此刻
    NSDate *tomorrowDate = [NSDate dateWithTimeInterval:24 * 60 * 60 sinceDate:date1];
    NSLog(@"明天此刻的時間 %@",tomorrowDate);
    
    //5.NSTimeInterval 時間間隔(單位是秒),double 的 typedef
    
    //昨天此時與明天此刻的時間間隔
    NSTimeInterval timeInterval = [tomorrowDate timeIntervalSinceDate:yesterdayDate];
    NSLog(@"昨日和明天此刻的時間(秒) %.0f",timeInterval);
}

顯示的結果

當前零時區時間 2016-08-24 14:36:11 +0000
今天此時的時間 2016-08-24 22:36:11 +0000
昨天此時的時間 2016-08-23 22:36:11 +0000
明天此刻的時間 2016-08-25 22:36:11 +0000
昨日和明天此刻的時間(秒) 172800

講解
1.dateWithTimeIntervalSinceNow方法是當前時間開始,加上時間戳,然后的時間,因為通過[NSDate date]方法獲取少了8小時,所以現在給加上去,獲取的是NSDate類型的北京時間(注意,如果是獲取NSString類型的,直接通過dateFormate就能轉化好,不需要考慮8小時問題!!!)
2.[tomorrowDate timeIntervalSinceDate:yesterdayDate]方法是獲取兩個NSDate類型的時間差值的


三.如何獲取時間戳(NSDate -> TimeStamp)

說白了就是看看某個0時區的NSDate和1970.1.1的時間差秒數就好了

    NSDate *date = [NSDate date];
    NSTimeInterval timeIn = [date timeIntervalSince1970];
    NSLog(@"1970年1月1日0時0分0秒至今相差 %.0f 秒", timeIn);

注意,一定是要0時區的時間,如果你獲取的NSDate是東八區的時間,想去轉成時間戳,一定要先減去8小時才行,否則時間戳會多出8小時!!!

打印結果是

1970年1月1日0時0分0秒至今相差 1472050117 秒

四.通過NSDateFormatter 處理NSDate和字符串的相互轉換

剛剛開場就講了NSDate -> NSString的步驟,

  • 1.獲取零時區的時間
  • 2.通過給dateFormat設置任意字符串轉化
  • 3.就可以自動變成正確的北京時間字符串!
  • 4.原因,系統認為NSDate是0時區的,NSString是東八區的

下面看看將NSString -> NSDate的步驟

  • 1.先獲取一個時間的字符串
  • 2.嚴格按照字符串中的時間格式,給dateFormat設置樣式
  • 3.獲得的是一個少了8小時的NSDate
  • 4.手動給NSDate添加8小時,最后得到了一個北京時間的NSDate對象
  • 5.原因,系統默認字符串是東八區的,但是轉化NSDate,他要搞成0時區的!
- (void)test4{

        //系統會認為字符串是東八區的時間, 轉乘NSDate是零時區的
        NSString *dateStr = @"2016年8月24日 11時05分23秒";
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
        [dateFormatter setDateFormat:@"yyyy年MM月dd日 hh時mm分ss秒"];
        NSDate *date = [dateFormatter dateFromString:dateStr];
        //將轉換回來的對象手動加上8小時,回到北京時間
        NSDate *date2 = [date dateByAddingTimeInterval:8 * 60 * 60];
        NSLog(@"字符串轉date: %@",date2);

}

打印結果

字符串轉date: 2016-08-24 11:05:23 +0000

注意,
1.一定先看時間字符串的格式,然后給dateForamte設置樣式,不過不相符,會出問題
2.通過dateFormat獲取的NSDate是0時區的,所以少了八小時,但是轉時間戳是沒問題的
3.要想得到正確的北京的NSDate類型對象,要加上8小時


作者,你叨逼叨的說了半天,到底要說個啥?

總結
No.1 通過[NSDate date]獲取是零時區的時間
No.2 NSDate(零時區) <-> timeStamp
No.3 系統認為NSDate應該是0時區的,NSString是東八區的
No.4 dateFormat轉換,公式NSDate(0時區)<-> NSString(東八區)
No.5 項目中為什么總會出現8*60*60這樣的東西?因為他們不知道前兩個公式
No.6 如何盡量少使用8*60*60還能解決項目的問題?** 凡是用到了NSDate,全部使用0時區的,因為至少轉換成時間戳的時候,絕對正確(NSDate是為了內部比較,還有就是轉成時間戳,上傳數據,目的不是用來顯示到屏幕上),通過No.4的公式,直接通過dateFormat轉化成北京時間字符串,截取使用即可(NSString才是用來顯示的,比較就讓NSDate去做好了)這樣基本就看不到8小時了**
No.7 (接No.6)有一種例外,就是通過datePicker,然后獲取的應該是NSDate類型的對象,應該是北京當前的時間(東八區),如果要上傳服務器的話,我們要傳遞的是時間戳,必須轉成東八區的,所以要減去8小時才行!


最后是我們公司的問題分享,看不看都行
1.為毛時間戳轉化之后,獲取的NSDate少了八小時?參見No.2
2.分類中寫的方法好多,到底用哪個?看完文章,對號入座吧
3.為毛線用pickerDate轉成時間戳多了八小時,上傳后臺之后,說好的時間戳是少了8小時,怎么轉變成NSDate有尼瑪多了八小時?No7已經說完了,不過可以再說一遍,假設pickerDate獲取的是一個NSDate(系統認為這種對象是0時區的,但是你卻傻呵呵的認為這個是東八區的時間,其實真實的0時區時間應該是4:00)12:00,直接轉成時間戳,(時間戳足足多了8小時),然后上傳服務器,又回來了這個時間戳,(過去我們認為時間戳都是少了八小時,按照過去的老習慣,將 NSDate[0時區] + 8小時 -> NSDate[東八區],)結果一定是多了8小時啊,所以爭取的思路,看剛剛的總結,就是少用(NSDate -> NSdate這種方式!)


彩蛋放送

.h文件

/**
 *  將0時區的時間轉成0時區的時間戳(10位數)
 */
+ (NSString *)transformToTimestampWithDate:(NSDate *)date;

/**
 *  將0時區的時間戳(10位數)轉成0時區的時間
 */
+ (NSDate *)transformToDateWithTimestamp:(NSString *)timestamp;

/**
 *  將0時區的時間戳(10位數)轉成8時區的時間文本格式(“2015-12-13 13:34:45”)
 */
+ (NSString *)transformToStringWithTimestamp:(NSString *)timestamp;

/**
 *  將0時區的時間戳(10位數)轉成8時區的時間文本格式(“2012-12-12 12:12”),帶有只有時分的
 */
+ (NSString *)transformToHourMiniteFormatWithTimestamp:(NSString *)timestamp;

/**
 *  將8時區的時間文本格式(“2015-12-13 13:34:45”)轉成 0時區的時間戳(10位數)
 */
+ (NSString *)transformToTimestampWithString:(NSString *)string;

/**
 *  將8時區的時間文本格式(“2015-12-13 13:34:45”)轉成 0時區的NSDate
 */
+ (NSDate *)transformToDateWithString:(NSString *)string;

/**
 *  將0時區的NSDate轉成 8時區的時間文本格式(“2015-12-13 13:34:45”)
 */
+ (NSString *)transformToStringWithDate:(NSDate *)date;

.m文件

/**
 *  將0時區的時間轉成0時區的時間戳
 */
+ (NSString *)transformToTimestampWithDate:(NSDate *)date{
    NSTimeInterval inter = [date timeIntervalSince1970];
    return [NSString stringWithFormat:@"%ld", (long)inter];
}

/**
 *  將0時區的時間戳轉成0時區的時間
 */
+ (NSDate *)transformToDateWithTimestamp:(NSString *)timestamp{
    NSTimeInterval inter = [timestamp doubleValue];
    NSDate * date = [NSDate dateWithTimeIntervalSince1970:inter];
    return date;
}

/**
 *  將0時區的時間戳轉成8時區的時間文本格式(“2015-12-13 13:34:45”)
 */
+ (NSString *)transformToStringWithTimestamp:(NSString *)timestamp{
    //1.先將時間戳->NSDate
    NSDate *date = [self transformToDateWithTimestamp:timestamp];
    //2.將date->NSString
    return [[self transformToStringWithDate:date] substringToIndex:16];
}


/**
 *  將0時區的時間戳(10位數)轉成8時區的時間文本格式(“2012-12-12 12:12”),帶有只有時分的
 */
+ (NSString *)transformToHourMiniteFormatWithTimestamp:(NSString *)timestamp{
    //1.先將時間戳->NSDate
    NSDate *date = [self transformToDateWithTimestamp:timestamp];
    //2.將date->NSString
    return [[self transformToStringWithDate:date] substringToIndex:13];
}

/**
 *  將8時區的時間文本格式(“2015-12-13 13:34:45”)轉成 0時區的時間戳
 */
+ (NSString *)transformToTimestampWithString:(NSString *)string{
    //1.先將NSString->NSDate
    NSDate *date = [self transformToDateWithString:string];
    //2.將date->timestamp
    return [self transformToStringWithDate:date];
}

/**
 *  將8時區的時間文本格式(“2015-12-13 13:34:45”)轉成 0時區的NSDate
 */
+ (NSDate *)transformToDateWithString:(NSString *)string{
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    [df setLocale:[NSLocale currentLocale]];
    [df setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *date = [df dateFromString:string];
    return date;
}

/**
 *  將0時區的NSDate轉成 8時區的時間文本格式(“2015-12-13 13:34:45”)
 */
+ (NSString *)transformToStringWithDate:(NSDate *)date{
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    [df setLocale:[NSLocale currentLocale]];
    [df setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *string = [df stringFromDate:date];
    return string;
}


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容

  • iOS開發中,經常會遇到各種各樣的時間問題,8小時時差,時間戳,求時間間隔,農歷等等。解決辦法網上比比皆是,但大多...
    小李龍彪閱讀 6,367評論 1 6
  • 在iOS開發中,經常會遇到各種各樣的時間問題,8小時時差,時間戳,求時間間隔,農歷等等。解決辦法網上比比皆是,但大...
    真巧了_嘿閱讀 2,786評論 0 7
  • 在Python中,迭代是通過for ... in來完成的 默認情況下,dict迭代的是key。如果要迭代value...
    牛崽兒酷閱讀 103評論 0 0
  • 晚上去看了學校里的紅樓夢音樂會。說來慚愧,《紅樓夢》我還沒讀完,高中時候由于是推薦閱讀書目,我便買了回來,看了三四...
    咯子嘣閱讀 275評論 0 0