NSDate 8小時問題

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:20160824221647

解釋

  • 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小時!!!

打印結果是

197011000秒至今相差 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章