NO IMAGE
說在前面

公司專案出了問題之後,上網差了很多資料,最後就有一個還是比較靠譜,剩下的都是說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這種方式!)

/**
*  將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;
}