2013-04-27 133 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关于日期的格式化。

相关问题