如何在 iOS 上获取 ISO 8601 日期?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16254575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get an ISO 8601 date on iOS?
提问by JohnK
It's easy enough to get the ISO 8601 date string (for example, 2004-02-12T15:19:21+00:00
) in PHP via date('c')
, but how does one get it in Objective-C (iPhone)? Is there a similarly short way to do it?
2004-02-12T15:19:21+00:00
在 PHP 中通过获取 ISO 8601 日期字符串(例如)很容易date('c')
,但是如何在 Objective-C (iPhone) 中获取它?有没有类似的简短方法来做到这一点?
Here's the longway I found to do it:
这是我发现的很长的路要走:
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
It seems an awful lot of rigmarole for something so central.
对于如此重要的事情来说,这似乎是非常繁琐的事情。
回答by rmaddy
Use NSDateFormatter
:
使用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];
And in Swift:
在 Swift 中:
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())
回答by TwoStraws
iOS 10 introduces a new NSISO8601DateFormatter
class to handle just this. If you're using Swift 3, your code would be something like this:
iOS 10 引入了一个新NSISO8601DateFormatter
类来处理这个问题。如果你使用 Swift 3,你的代码应该是这样的:
let formatter = ISO8601DateFormatter()
let date = formatter.date(from: "2016-08-26T12:39:00Z")
let string = formatter.string(from: Date())
回答by Etienne
As a complement to maddy's answer, the time zone format should be "ZZZZZ" (5 times Z) for ISO 8601 instead of a single "Z" (which is for RFC 822 format). At least on iOS 6.
作为对 maddy 回答的补充,ISO 8601 的时区格式应为“ZZZZZ”(Z 的 5 倍),而不是单个“Z”(用于 RFC 822 格式)。至少在 iOS 6 上。
(see http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
(见http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns)
回答by Vadim Bulavin
An often overlooked issue is that strings in ISO 8601 format might have milliseconds and might not.
一个经常被忽视的问题是 ISO 8601 格式的字符串可能有毫秒,也可能没有。
In other words, both "2016-12-31T23:59:59.9999999" and "2016-12-01T00:00:00" are legit, but if you are using static-typed date formatter, one of them won't be parsed.
换句话说,“2016-12-31T23:59:59.9999999”和“2016-12-01T00:00:00”都是合法的,但如果您使用的是静态类型的日期格式化程序,则不会解析其中之一.
Starting from iOS 10you should use ISO8601DateFormatter
that handles all variations of ISO 8601 date strings. See example below:
从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)
For iOS 9 and belowuse the following approach with multiple data formatters.
对于iOS 9 及以下版本,请使用以下方法与多个数据格式化程序。
I haven't found an answer that covers both cases and abstracts away this subtle difference. Here is the solution that addresses it:
我还没有找到涵盖这两种情况并抽象出这种微妙差异的答案。这是解决它的解决方案:
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
}
}
Usage:
用法:
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
I also recommend checking Apple articleabout date formatters.
我还建议查看有关日期格式化程序的Apple 文章。
回答by David H
So use Sam Soffee's category on NSDate found here. With that code added to your project, you can from then on use a single method on NSDate:
因此,请在此处找到 NSDate 上使用 Sam Soffee 的类别。将该代码添加到您的项目中后,您就可以在 NSDate 上使用单个方法:
- (NSString *)sam_ISO8601String
Not only is it one line, its much faster than the NSDateFormatter approach, since its written in pure C.
它不仅是一行,而且比 NSDateFormatter 方法快得多,因为它是用纯 C 编写的。
回答by onmyway133
From IS8601, the problems are the representation and time zone
从IS8601 开始,问题是表示法和时区
- ISO 8601 =
year-month-day time timezone
- For date and time, there are basic (YYYYMMDD, hhmmss, ...) and extended format (YYYY-MM-DD, hh:mm:ss, ...)
- Time zone can be Zulu, offset or GMT
- Separator for date and time can be space, or
T
- There are week format for date, but it is rarely used
- Timezone can be a lot of spaces after
- Second is optional
- ISO 8601 =
year-month-day time timezone
- 对于日期和时间,有基本的 (YYYYMMDD, hhmmss, ...) 和扩展格式 (YYYY-MM-DD, hh:mm:ss, ...)
- 时区可以是祖鲁语、偏移量或 GMT
- 日期和时间的分隔符可以是空格,或者
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
解决方案
- Parse step by step, like soffes ISO8601
- Convert to basic format, like onmyway133 ISO8601
- 一步一步解析,像soffes ISO8601
- 转换为基本格式,如onmyway133 ISO8601
NSDateFormatter
NSDateFormatter
So here is the format that I'm using in onmyway133 ISO8601
所以这是我在onmyway133 ISO8601 中使用的格式
let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyyMMdd HHmmssZ"
About the Z
identifier Date Field Symbol Table
关于Z
标识符日期字段符号表
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)
About locale
Formatting Data Using the Locale Settings
关于locale
使用区域设置格式化数据
Locales represent the formatting choices for a particular user, not the user's preferred language. These are often the same but can be different. For example, a native English speaker who lives in Germany might select English as the language and Germany as the region
区域设置代表特定用户的格式选择,而不是用户的首选语言。这些通常是相同的,但可以不同。例如,居住在德国的母语为英语的人可能会选择英语作为语言,选择德国作为地区
About en_US_POSIX
Technical Q&A QA1480 NSDateFormatter and Internet Dates
关于en_US_POSIX
技术问答 QA1480 NSDateFormatter 和 Internet 日期
On the other hand, if you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is "en_US_POSIX", a locale that's specifically designed to yield US English results regardless of both user and system preferences. "en_US_POSIX" is also invariant in time (if the US, at some point in the future, changes the way it formats dates, "en_US" will change to reflect the new behaviour, but "en_US_POSIX" will not), and between machines ("en_US_POSIX" works the same on iOS as it does on OS X, and as it it does on other platforms).
另一方面,如果您使用固定格式的日期,您应该首先将日期格式化程序的区域设置为适合您的固定格式的内容。在大多数情况下,要选择的最佳语言环境是“en_US_POSIX”,这是一种专门设计用于产生美国英语结果而不管用户和系统偏好的语言环境。“en_US_POSIX”在时间上也是不变的(如果美国在未来的某个时候改变了它格式化日期的方式,“en_US”将改变以反映新的行为,但“en_US_POSIX”不会),并且在机器之间( “en_US_POSIX”在 iOS 上的工作方式与在 OS X 上的工作方式相同,在其他平台上也一样)。
Interesting related quetions
有趣的相关问题
回答by LLIAJLbHOu
Just use NSISO8601DateFormatterfrom Foundation framework.
只需使用Foundation 框架中的NSISO8601DateFormatter。
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
https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc
回答by Zack Zhu
Based on this gist: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift, the following method can be used to convert NSDate to ISO 8601 date string in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ
基于这个要点:https: //github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift,可以使用以下方法将 NSDate 转换为 yyyy-MM 格式的 ISO 8601 日期字符串-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"];
}
回答by iphaaw
This is a little bit simpler and puts the date into UTC.
这有点简单,并将日期放入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()
回答by Denis Krivitski
Using Swift 3.0 and iOS 9.0
使用 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
}
}
}