在Swift中,我如何解析/创建格式为带有分数秒的UTC时区的日期时间戳(ISO 8601,RFC 3339)?

11 浏览
0 Comments

在Swift中,我如何解析/创建格式为带有分数秒的UTC时区的日期时间戳(ISO 8601,RFC 3339)?

如何生成日期时间戳,使用ISO 8601RFC 3339的格式标准?\n目标是一个类似于这样的字符串:\n

"2015-01-01T00:00:00.000Z"

\n格式:\n

    \n

  • 年、月、日,格式为\"XXXX-XX-XX\"
  • \n

  • 字母\"T\"作为分隔符
  • \n

  • 小时、分钟、秒、毫秒,格式为\"XX:XX:XX.XXX\"
  • \n

  • 字母\"Z\"作为零偏移区域指示器,即UTC、GMT、Zulu时间。
  • \n

\n最佳情况:\n

    \n

  • 简单、简洁、直接的Swift源代码。
  • \n

  • 不需要使用任何额外的框架、子项目、cocoapod、C代码等。
  • \n

\n我在StackOverflow、谷歌、苹果等地搜寻,并没有找到一个关于这个问题的Swift答案。\n看起来最有希望的类是NSDateNSDateFormatterNSTimeZone。\n相关问答:如何在iOS上获取ISO 8601日期?\n到目前为止,这是我找到的最好的解决方案:\nvar now = NSDate()\nvar formatter = NSDateFormatter()\nformatter.dateFormat = \"yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'\"\nformatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)\nprintln(formatter.stringFromDate(now))\n

0
0 Comments

问题的原因是,当使用ISO8601DateFormatter解析Rails 4+ JSON数据源中的日期时,需要对格式化程序设置一些选项,否则date(from: string)函数将返回nil。解决方法是使用以下选项:

extension Date {

init(dateString:String) {

self = Date.iso8601Formatter.date(from: dateString)!

}

static let iso8601Formatter: ISO8601DateFormatter = {

let formatter = ISO8601DateFormatter()

formatter.formatOptions = [.withFullDate,

.withTime,

.withDashSeparatorInDate,

.withColonSeparatorInTime]

return formatter

}()

}

这段代码将ISO8601DateFormatter扩展为Date对象的初始化函数,并设置了格式选项。通过使用这些选项,可以确保解析日期时不会出错。

在Swift 4中,这种方法运行良好。如果您遇到错误,请确保您的代码与示例代码完全一样,并检查您的Swift版本。

关于是否包含毫秒的问题,有人建议在保存/接收日期时使用双精度值(自参考日期以来的时间间隔),并在使用Codable协议时使用默认的日期解码策略.deferredToDate。这样可以保留带有所有小数秒的日期。

,解决这个问题的方法是使用ISO8601DateFormatter并设置适当的选项来解析日期。如果需要保留小数秒,则可以使用双精度值来保存日期。

0
0 Comments

问题的原因是,如果设备使用的是非公历日历,那么年份将不符合RFC3339/ISO8601,除非同时指定locale、timeZone和dateFormat字符串。解决方法是设置locale为en_US_POSIX,并设置timeZone为0秒,然后使用dateFormat字符串"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"来格式化日期时间戳。

另一种解决方法是使用ISO8601DateFormatter来避免手动设置locale和timeZone。只需创建ISO8601DateFormatter实例,然后将formatOptions设置为.withFractionalSeconds,即可获取带有毫秒的日期时间戳。

为什么要将locale设置为en_US_POSIX,即使我们不在美国?因为需要一个一致的locale,并且ISO 8601/RFC 3999标准的约定是使用en_US_POSIX提供的格式。这是在网络上交换日期的通用语言。如果在保存日期字符串时设备上使用了一种日历,而在以后读取字符串时使用了另一种日历,就不能对日期进行错误解释。此外,需要一个永远不会更改的格式(这就是为什么使用en_US_POSIX而不是en_US)。有关更多信息,请参阅Technical Q&A 1480或相关的RFC/ISO标准。

.withFractionalSeconds - 这是我需要的,以支持处理毫秒。谢谢!

0
0 Comments

问题的出现是因为需要在Swift中解析/创建带有小数秒的日期时间戳,并使用UTC时区的ISO 8601和RFC 3339格式。以下是解决该问题的方法:

1. 首先,我们定义了一个ISO8601DateFormatter的扩展,以便根据指定的格式选项创建一个实例。

extension ISO8601DateFormatter {

convenience init(_ formatOptions: Options) {

self.init()

self.formatOptions = formatOptions

}

}

2. 接下来,我们定义了Formatter的扩展,以创建一个ISO 8601格式的日期格式化器,包括小数秒。

extension Formatter {

static let iso8601withFractionalSeconds = ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds])

}

3. 然后,我们定义了Date的扩展,以便将日期格式化为ISO 8601格式的字符串。

extension Date {

var iso8601withFractionalSeconds: String { return Formatter.iso8601withFractionalSeconds.string(from: self) }

}

4. 接下来,我们定义了String的扩展,以便将ISO 8601格式的字符串解析为Date对象。

extension String {

var iso8601withFractionalSeconds: Date? { return Formatter.iso8601withFractionalSeconds.date(from: self) }

}

5. 最后,我们使用这些扩展的方法来使用和处理日期时间戳。

Date().description(with: .current) // Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"

let dateString = Date().iso8601withFractionalSeconds // "2019-02-06T00:35:01.746Z"

if let date = dateString.iso8601withFractionalSeconds {

date.description(with: .current) // "Tuesday, February 5, 2019 at 10:35:01 PM Brasilia Summer Time"

print(date.iso8601withFractionalSeconds) // "2019-02-06T00:35:01.746Z\n"

}

以上是在Swift 4和iOS 11.2.1及更高版本中解决该问题的方法。

此外,还提供了一个Swift 3或更高版本的解决方案:

extension Formatter {

static let iso8601withFractionalSeconds: DateFormatter = {

let formatter = DateFormatter()

formatter.calendar = Calendar(identifier: .iso8601)

formatter.locale = Locale(identifier: "en_US_POSIX")

formatter.timeZone = TimeZone(secondsFromGMT: 0)

formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"

return formatter

}()

}

还提供了使用Codable协议进行编码和解码的解决方案。为此,我们定义了自定义的日期编码和解码策略:

extension JSONDecoder.DateDecodingStrategy {

static let iso8601withFractionalSeconds = custom {

let container = try $0.singleValueContainer()

let string = try container.decode(String.self)

guard let date = Formatter.iso8601withFractionalSeconds.date(from: string) else {

throw DecodingError.dataCorruptedError(in: container,

debugDescription: "Invalid date: " + string)

}

return date

}

}

extension JSONEncoder.DateEncodingStrategy {

static let iso8601withFractionalSeconds = custom {

var container = $1.singleValueContainer()

try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))

}

}

最后,提供了用于测试的代码示例,包括对日期进行编码和解码的示例。

我们可以使用上述的扩展和方法来解析/创建带有小数秒的日期时间戳,并使用UTC时区的ISO 8601和RFC 3339格式。

0