說在前面
公司項目出了問題之后,上網差了很多資料,最后就有一個還是比較靠譜,剩下的都是說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)
- (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.4dateFormat
轉換,公式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;
}