2013-04-27 56 views
93

很容易通過date('c')在PHP中獲得ISO 8601日期字符串(例如,2004-02-12T15:19:21+00:00),但是如何在Objective-C(iPhone)中獲得它?有沒有類似的簡單方法來做到這一點?如何在iOS上獲得ISO 8601的日期?

這裏的辦法,我發現做到這一點:

NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; 
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ"; 

NSDate *now = [NSDate date]; 
NSString *formattedDateString = [dateFormatter stringFromDate:now]; 
NSLog(@"ISO-8601 date: %@", formattedDateString); 

// Output: ISO-8601 date: 2013-04-27T13:27:50-0700 

似乎一個可怕的很多繁瑣手續的東西如此重要。

+0

我猜短的是在旁觀者的眼中。三行代碼很短,不是嗎?有一個C NSDate子類,你可以添加一行代碼,我只是絆倒它:https://github.com/soffes/SAMCategories/tree/master/SAMCategories/Foundation。這就是說,真的,你有很好的答案(恕我直言),你應該獎勵艾蒂安或rmaddy的答案。它只是良好的做法和獎勵人們提供真正有用的信息(它幫助了我,我今天需要這個信息)。艾蒂安可以使用比rmaddy更多的分數。作爲一個很好的衡量標誌,我甚至會爲你的問題投票! – 2013-11-13 18:57:35

回答

184

使用NSDateFormatter

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; 
[dateFormatter setLocale:enUSPOSIXLocale]; 
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; 

NSDate *now = [NSDate date]; 
NSString *iso8601String = [dateFormatter stringFromDate:now]; 

而且在斯威夫特:

let dateFormatter = DateFormatter() 
let enUSPosixLocale = Locale(identifier: "en_US_POSIX") 
dateFormatter.locale = enUSPosixLocale 
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" 

let iso8601String = dateFormatter.string(from: Date()) 
+1

謝謝,Maddy。我發佈我的代碼後,我現在就看到了你的答案。 'setLocale'重要嗎? – JohnK 2013-04-27 17:32:25

+0

是的,特殊區域非常重要。沒有它,最終的字符串可能對某些用戶的設備是錯誤的。在解析或創建不適合用戶顯示的特定格式的日期/時間字符串時,應始終使用該區域設置。 – rmaddy 2013-04-27 17:35:51

+0

如果日期時間字符串*是*用於用戶顯示會怎麼樣? – JohnK 2013-04-27 18:20:26

25

爲補充馬迪的回答,時區的格式應爲 「ZZZZZ」(5次Z)爲ISO 8601,而不是的單個「Z」(用於RFC 822格式)。 至少在iOS 6

(見http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns

+0

很棒!任何對此感興趣的人都可以去鏈接,搜索8601你會看到它。 – 2013-11-13 15:27:46

+0

當日期的時區是UTC時,有沒有辦法讓它顯示00:00而不是Z(相當於)? – shim 2015-03-27 23:13:08

+0

非常感謝;)用dateformatter返回nil日期,我的頭撞到了牆上! :) – polo987 2016-01-21 16:12:15

8

因此,使用薩姆Soffee的類別上的NSDate發現here。與該代碼添加到你的項目,你可以從此使用上的NSDate一個方法:

- (NSString *)sam_ISO8601String 

它不僅是一條線,它比NSDateFormatter方法快得多,因爲它用純C.

+1

該類別的當前位置是[這裏](https://github.com/soffes/SAMCategories/blob/master/SAMCategories/NSDate+SAMAdditions.h) – Perry 2014-03-09 22:36:59

+1

我會建議反對它,它有內存異常問題這發生得非常隨機 – 2015-06-02 08:43:58

+1

@M_Waly你有沒有向他報告?我沒有警告地構建了他的代碼,並且通過了分析檢查。 – 2015-06-02 12:22:07

2

基於該要旨:https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift,下面的方法可用於的NSDate轉換爲ISO在YYYY-MM-dd'T'HH的格式8601的日期字符串:MM:ss.SSSZ

-(NSString *)getISO8601String 
    { 
     static NSDateFormatter *formatter = nil; 
     if (!formatter) 
     { 
      formatter = [[NSDateFormatter alloc] init]; 
      [formatter setLocale: [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; 
      formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: @"UTC"]; 
      [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS"]; 

     } 
     NSString *iso8601String = [formatter stringFromDate: self]; 
     return [iso8601String stringByAppendingString: @"Z"]; 
    } 
+0

關於亞秒鐘的'S'是關鍵在這裏 – 2016-07-11 02:51:14

+0

注意,如果你需要超過3秒鐘,那麼你不能使用日期格式化器必須手動解析它。 – malhal 2016-09-03 19:01:46

+0

不適用於'1991-01-21T05:07:58.000Z' – fnc12 2017-02-01 09:23:19

5

IS8601,問題是代表和時間zo NE

  • ISO 8601 = year-month-day time timezone
  • 對於日期和時間,也有基本的(年月日,HHMMSS,...)和擴展格式(YYYY-MM-DD,HH:MM:SS,...)
  • 時區可能是祖魯語,日期和時間可空間偏移或GMT
  • 分離,或T
  • 有日期星期格式,但它很少使用
  • 時區可不少後
  • 的第二空間是可選的

這裏有一些有效字符串

2016-04-08T10:25:30Z 
2016-04-08 11:25:30+0100 
2016-04-08 202530GMT+1000 
20160408 08:25:30-02:00 
2016-04-08 11:25:30  +0100 

解決方案

NSDateFormatter

因此,這裏是我的格式m使用onmyway133 ISO8601

let formatter = NSDateFormatter() 
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 
formatter.dateFormat = "yyyyMMdd HHmmssZ" 

關於Z標識符Date Field Symbol Table

Z: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent) 

關於localeFormatting Data Using the Locale Settings

語言環境表示爲特定的用戶,而不是用戶的偏好語言的格式選擇。這些通常是相同的,但可以不同。例如,以英語爲母語誰住在德國的可能,如果你與定點工作作爲語言和德國,成爲區域

關於en_US_POSIXTechnical Q&A QA1480 NSDateFormatter and Internet Dates

在另一方面,選擇英語格式日期,您應該首先將日期格式化程序的區域設置爲適合您固定格式的內容。在大多數情況下,要選擇的最佳語言環境是「en_US_POSIX」,該語言環境專門設計用於在不考慮用戶和系統偏好的情況下生成美國英語結果。 「en_US_POSIX」在時間上也是不變的(如果美國在將來的某個時間點改變格式日期的方式,「en_US」將改變以反映新的行爲,但「en_US_POSIX」不會)以及機器之間「en_US_POSIX」在iOS上的工作方式與在OS X上的工作方式相同,在其他平臺上也如此)。

有趣的相關quetions

+0

我剛剛嘗試過2016-07-23T07:24:23Z,它不起作用 – 2016-08-01 09:55:42

+0

@KamenDobrev你是什麼意思「不工作」?我只是將您的示例添加到測試中https://github.com/onmyway133/ISO8601/blob/master/ISO8601Tests/Tests.swift#L46,它的工作原理是 – onmyway133 2016-08-01 10:16:30

0

這是一個有點簡單,把日期爲UTC。

extension NSDate 
{ 
    func iso8601() -> String 
    { 
     let dateFormatter = NSDateFormatter() 
     dateFormatter.timeZone = NSTimeZone(name: "UTC") 
     let iso8601String = dateFormatter.stringFromDate(NSDate()) 
     return iso8601String 
    } 
} 

let date = NSDate().iso8601() 
29

iOS 10引入了一個新的NSISO8601DateFormatter類來處理這個。如果您使用的斯威夫特3,您的代碼將是這樣的:

let formatter = ISO8601DateFormatter() 
let date = formatter.date(from: "2016-08-26T12:39:00Z") 
let string = formatter.string(from: Date()) 
+0

,它給出了什麼格式?此外,如果能夠處理:2016-08-26T12:39:00-0000和2016-08-26T12:39:00-00:00和2016-08-26T12:39:00.374-0000 – malhal 2016-09-03 19:40:18

+0

前兩個正確解析;第三個不是。格式取決於您 - 它會創建一個Date對象,您可以根據需要操作。 – TwoStraws 2016-09-03 20:33:10

+0

感謝您的測試。對於格式的東西,我的意思是你可以告訴我們它的默認輸出是怎樣打印出來的?有興趣瞭解他們如何選擇輸出時區。乾杯 – malhal 2016-09-03 21:09:04

-1

使用雨燕3.0和iOS 9.0

extension Date { 
    private static let jsonDateFormatter: DateFormatter = { 
     let formatter = DateFormatter() 
     formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" 
     formatter.locale = Locale(identifier: "en_US_POSIX") 
     formatter.timeZone = TimeZone(identifier: "UTC")! 
     return formatter 
    }() 

    var IOS8601String: String { 
     get { 
      return Date.jsonDateFormatter.string(from: self) 
     } 
    } 

    init?(fromIOS8601 dateString: String) { 
     if let d = Date.jsonDateFormatter.date(from: dateString) { 
      self.init(timeInterval: 0, since:d) 
     } else { 
      return nil 
     } 
    } 
} 
3

經常忽略的一個問題是,在ISO 8601的字符串格式可能毫秒可能不會。

換句話說,「2016-12-31T23:59:59.9999999」和「2016-12-01T00:00:00」都是合法的,但是如果您使用的是靜態類型日期格式化程序,其中一個贏得了不會被解析。

我還沒有找到答案,涵蓋了這兩個案件和摘要了這種微妙的差異。下面是解決它的解決方案:

extension DateFormatter { 

    static let iso8601DateFormatter: DateFormatter = { 
     let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX") 
     let iso8601DateFormatter = DateFormatter() 
     iso8601DateFormatter.locale = enUSPOSIXLocale 
     iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" 
     iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0) 
     return iso8601DateFormatter 
    }() 

    static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = { 
     let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX") 
     let iso8601DateFormatter = DateFormatter() 
     iso8601DateFormatter.locale = enUSPOSIXLocale 
     iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'" 
     iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0) 
     return iso8601DateFormatter 
    }() 

    static func date(fromISO8601String string: String) -> Date? { 
     if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) { 
      return dateWithMilliseconds 
     } 

     if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) { 
      return dateWithoutMilliseconds 
     } 

     return nil 
    } 
} 

用法:

let dateToString = "2016-12-31T23:59:59.9999999" 
let dateTo = DateFormatter.date(fromISO8601String: dateToString) 
// dateTo: 2016-12-31 23:59:59 +0000 

let dateFromString = "2016-12-01T00:00:00" 
let dateFrom = DateFormatter.date(fromISO8601String: dateFromString) 
// dateFrom: 2016-12-01 00:00:00 +0000 

我也建議檢查Apple article關於日期的格式化。

相關問題