我如何在iOS上获得ISO 8601的date?

通过date('c')在PHP中获取ISO 8601datestring(例如, 2004-02-12T15:19:21+00:00 )是很容易的,但是如何在Objective-C(iPhone )? 有没有类似的方法来做到这一点?

以下是我发现要做的很长一段路:

 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 

对于这么重要的东西来说,这看起来非常糟糕。

使用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]; 

而在Swift中:

 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()) 

作为maddy回答的补充,对于ISO 8601,时区格式应该是“ZZZZZ”(5倍Z),而不是单个“Z”(用于RFC 822格式)。 至less在iOS 6上。

(请参阅http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns

iOS 10引入了一个新的NSISO8601DateFormatter类来处理这个。 如果你使用的是Swift 3,你的代码应该是这样的:

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

所以在这里findNSDate使用Sam Soffee的类别。 随着代码添加到您的项目,您可以在NSDate上使用单一的方法:

 - (NSString *)sam_ISO8601String 

它不仅是一条线,它比NSDateFormatter方法快得多,因为它是用纯C编写的。

IS8601的问题在于代表性和时区

  • ISO 8601 = year-month-day time timezone
  • 对于date和时间,有基本的(YYYYMMDD,hhmmss,…)和扩展格式(YYYY-MM-DD,hh:mm:ss,…)
  • 时区可以是祖鲁,偏移或GMT
  • date和时间的分隔符可以是空格或T
  • 有星期格式的date,但很less使用
  • 时区之后可能会有很多空格
  • 其次是可选的

这里有一些有效的string

 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 

解决scheme

  • 一步一步parsing,像soffes ISO8601
  • 转换为基本格式,如onmyway133 ISO8601

NSDateFormatter

所以这里是我在onmyway133 ISO8601中使用的格式

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

关于Z标识符date字段符号表

 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) 

关于locale 使用 locale 格式化数据

语言环境表示特定用户的格式化选项,而不是用户的首选语言。 这些通常是相同的,但可以不同。 例如,居住在德国的母语为英语的人可能select英语作为语言,德国作为该地区

关于en_US_POSIX 技术问答QA1480 NSDateFormatter和Internetdate

另一方面,如果您使用的是固定格式date,则应首先将date格式化程序的语言环境设置为适合固定格式的语言。 在大多数情况下,最好的语言环境是“en_US_POSIX”,这个语言环境专门用来产生美式英语结果,而不pipe用户和系统的喜好。 “en_US_POSIX”在时间上也是不变的(如果美国在将来的某个时候改变date的格式,“en_US”将会改变以反映新的行为,但“en_US_POSIX”不会)和机器之间“en_US_POSIX”在iOS上的工作方式与在OS X上的工作方式相同,在其他平台上也如此)。

有趣的相关的排队

  • 将ISO 8601时间戳转换为NSDate:如何处理UTC时间偏移?
  • 为什么NSDateFormatter无法从ISO 8601格式parsingdate
  • 毫秒NSDateFormatterparsingISO8601毫秒和毫秒

基于这个要点: https : //github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift ,可以使用下面的方法将NSDate转换为格式为yyyy-MM的ISO 8601datestring-dd'T'HH: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"]; } 

一个经常被忽视的问题是ISO 8601格式的string可能有几毫秒,可能不会。

换句话说,“2016-12-31T23:59:59.9999999”和“2016-12-01T00:00:00”都是合法的,但是如果您使用的是静态typesdate格式化程序,则其中一个不会被parsing。

我还没有find涵盖这两个案例和摘要了这个微妙的差异的答案。 这是解决它的解决scheme:

 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(fromISO8601StringWithOptionalMilliseconds 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(fromISO8601StringWithOptionalMilliseconds: dateToString) // dateTo: 2016-12-31 23:59:59 +0000 let dateFromString = "2016-12-01T00:00:00" let dateFrom = DateFormatter.date(fromISO8601StringWithOptionalMilliseconds: dateFromString) // dateFrom: 2016-12-01 00:00:00 +0000 

我还build议检查有关date格式化程序的苹果文章 。

这有点简单,把date放到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() 

使用Swift 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 } } }