如何在iOS上获得ISO 8601日期?

时间:2013-04-27 16:45:39

标签: ios nsdate nsdateformatter iso8601

通过2004-02-12T15:19:21+00:00在PHP中获取ISO 8601日期字符串(例如,date('c'))很容易,但是如何在Objective-C(iPhone)中获取它?是否有类似的简短方法呢?

这是我发现的 long 方式:

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

对于那些如此重要的事情来说,这似乎是一件非常艰难的事情。

10 个答案:

答案 0 :(得分:204)

使用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"];
[dateFormatter setsetCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];

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"
dateFormatter.calendar = Calendar(identifier: .gregorian)

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

答案 1 :(得分:47)

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

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

答案 2 :(得分:27)

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

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

答案 3 :(得分:11)

一个经常被忽视的问题是ISO 8601格式的字符串可能有毫秒而且可能没有。

换句话说,“2016-12-31T23:59:59.9999999”和“2016-12-01T00:00:00”都是合法的,但如果您使用静态类型的日期格式化程序,其中一个赢了解析。

iOS 10 开始,您应该使用ISO8601DateFormatter来处理ISO 8601日期字符串的所有变体。见下面的例子:

let date = Date()
var string: String

let formatter = ISO8601DateFormatter()
string = formatter.string(from: date)

let GMT = TimeZone(abbreviation: "GMT")
let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)

对于 iOS 9及更低版本,请对多个数据格式化程序使用以下方法。

我还没有找到涵盖这两种情况的答案,并摘录了这种微妙的差异。以下是解决它的解决方案:

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

答案 4 :(得分:8)

因此,在NSDate上使用Sam Soffee的类别here。将代码添加到项目中后,您可以在NSDate上使用单个方法:

- (NSString *)sam_ISO8601String

它不仅是一行,而且比NSDateFormatter方法快得多,因为它是用纯C语言编写的。

答案 5 :(得分:6)

来自IS8601,问题是表示和时区

  • ISO 8601 = year-month-day time timezone
  • 日期和时间有基本(YYYYMMDD,hhmmss,...)和扩展格式(YYYY-MM-DD,hh:mm:ss,...)
  • 时区可以是Zulu,偏移或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

所以这是我在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)

关于locale Formatting Data Using the Locale Settings

  

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

关于en_US_POSIX Technical Q&A QA1480 NSDateFormatter and Internet Dates

  

另一方面,如果您正在使用固定格式的日期,则应首先将日期格式化程序的区域设置设置为适合您的固定格式的区域设置。在大多数情况下,选择的最佳语言环境是&#34; en_US_POSIX&#34;,这是一个专门设计用于产生美国英语结果的语言环境,无论用户和系统偏好如何。 &#34; en_US_POSIX&#34;在时间上也是不变的(如果美国,在未来的某个时刻,它会改变日期的格式,&#34; en_US&#34;会改变以反映新的行为,但是&#34; en_US_POSIX&#34;将在机器之间(&#34; en_US_POSIX&#34;在iOS上和在OS X上的工作方式相同,就像在其他平台上一样)。

有趣的相关排队

答案 6 :(得分:3)

基于这个要点:https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift,可以使用以下方法将NSDate转换为ISO 8601日期字符串,格式为yyyy-MM-dd&lt; T&#39; 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"];
    }

答案 7 :(得分:3)

只需使用Foundation框架中的 NSISO8601DateFormatter

colour space

https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc

答案 8 :(得分: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()

答案 9 :(得分:-1)

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