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

通过 date('c')在 PHP 中获得 ISO 8601日期字符串(例如,2004-02-12T15:19:21+00:00)很容易,但是如何在 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

对于如此重要的东西来说,似乎有太多的繁文缛节。

76225 次浏览

使用 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 setCalendar:[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())

作为对 Maddy 答案的补充,时区格式应该是 ISO 8601的“ ZZZZZ”(5乘以 Z) ,而不是单个“ Z”(RFC 822格式)。 至少在 iOS6上是这样的。

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

所以使用山姆 · 索菲的分类在 NSDate 上找到 给你。将这些代码添加到项目中后,您就可以在 NSDate 上使用单个方法:

- (NSString *)sam_ISO8601String

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

基于这个要点: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift,可以使用以下方法将 NSDate 转换为 yyyy-MM-dd‘ T’HH: mm: ss.SSSZ 格式的 ISO 8601日期字符串

-(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"];
}

更新

在 iOS10中,您可以只使用 Foundation 中的 日期格式化

原始答案

IS8601来看,问题在于表示和时区

  • ISO 8601 = year-month-day time timezone
  • 对于日期和时间,有基本的(YYYMMDD,hhmmss,...)和扩展格式(YYYY-MM-DD,hh: mm: ss,...)
  • 时区可以是祖鲁,偏移或格林尼治标准时间
  • Separator for date and time can be space, or T
  • 有星期格式的日期,但它很少使用
  • 时区之后可以有很多空间
  • 第二是可选的

Here are some valid strings

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

Solutions

NSDateFormatter

这是我在 在路上133 ISO8601中使用的格式

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

About the Z identifier 日期字段符号表

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

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

关于 en_US_POSIX

另一方面,如果使用的是固定格式的日期,则应该首先将日期格式化程序的区域设置为与固定格式相适应的内容。在大多数情况下,选择的最佳语言环境是“ en _ US _ POSIX”,这是一种专门设计用于产生美式英语结果的语言环境,不管用户和系统的偏好如何。“ en _ US _ POSIX”在时间和机器之间也是不变的(如果美国在未来某个时候改变了日期格式,“ en _ US”将会改变以反映新的行为,但是“ en _ US _ POSIX”不会)(“ en _ US _ POSIX”在 iOS 上和在 OS X 上以及在其他平台上的作用是一样的)。

有趣的相关问题

这有点简单,把日期放在 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()

iOS 10 introduces a new NSISO8601DateFormatter class to handle just this. If you're using Swift 3, your code would be something like this:

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

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

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

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

Starting from IOS10 you should use ISO8601DateFormatter that handles all variations of ISO 8601 date strings. See example below:

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)

对于 IOS9及以下版本,对多个数据格式化程序使用以下方法。

我还没有找到一个既包含案例又包含抽象的答案来消除这种微妙的差异。以下是解决这个问题的办法:

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

我还建议检查有关日期格式化程序的 苹果文章

只需从 Foundation 框架中使用 日期格式化

let isoDateFormatter = ISO8601DateFormatter()
print("ISO8601 string: \(isoDateFormatter.string(from: Date()))")
// ISO8601 string: 2018-03-21T19:11:46Z

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

在 iOS15中,你可以得到如下 ISO860:

let iso8601String = Date.now.ISO8601Format()

如果你来这里是因为一个相反的搜索结果,这里有一个最简单的解决方案:

let date = ISO8601DateFormatter().date(from: dateString)