Swift:timeIntervalSince1970 的精度
Swift: Precision with timeIntervalSince1970
当我将 Unix 纪元时间转换为毫秒时,它会四舍五入。
代码:
import Foundation
extension Date {
public func getMilliSeconds()-> TimeInterval {
return TimeInterval(self.timeIntervalSince1970)
}
}
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time /// (notice the 8 is the last digit)")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(convertedTime) Time converted To Swift Date")
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:m:ss.SSSS"
let withMilli = df.string(from: convertedTime)
print("\(withMilli) Time with milliseconds using Date Formatter /// (notice 8 is missing and this was rounded to .9330")
if let convertedBackToEpochTime = df.date(from: withMilli) {
print("\(convertedBackToEpochTime.getMilliSeconds()) Time converted back to Unix epoch time")
}
日志:
1597269862.9328 Precise Epoch Time /// (notice the 8 is the last digit)
2020-08-12 22:04:22 +0000 Time converted To Swift Date
2020-08-12 15:4:22.9330 Time with milliseconds using Date Formatter /// (notice 8 is missing and this was rounded to .9330
1597269862.933 Time converted back to Unix epoch time
我以 1597269862.9328
开头,以 1597269862.933
结尾。
我怎样才能使日期准确地回到我开始时的日期:1597269862.9328
?
日期的所有组成部分(年、月、日、时、分、秒等)都是整数。毫秒,顾名思义,只精确到 one-thousandth 秒(即:3 位小数)。
你要得到的是nanosecond
属性。这是一个使用 Swift 5.0 中添加的自定义插值功能的示例:
import Foundation
extension String.StringInterpolation {
/// Our custom interpolator for Date
mutating func appendInterpolation(custom date: Date) {
let components: Set<Calendar.Component> = [
.year, .month, .day, .hour, .minute, .second, .nanosecond, .timeZone
]
let values = Calendar.current.dateComponents(components, from: date)
appendLiteral(values.description)
}
}
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time (notice the 8 is the last digit)")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(custom: convertedTime)")
结果:
1597269862.9328 Precise Epoch Time (notice the 8 is the last digit)
timeZone: America/Toronto (current) year: 2020 month: 8 day: 12 hour: 18 minute: 4 second: 22 nanosecond: 932800054 isLeapMonth: false
通知nanosecond: 932800054
。此值与原始输入的差异是由于浮点精度,这是不可避免的。
问题是 DateFormatter
限制在毫秒内。使用它无法显示超过 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.SSSSSSSSSXXXXX"
return formatter
}()
}
Formatter.iso8601withFractionalSeconds.string(from: Date()) // "2020-10-29T16:12:27.111000000Z"
如果您想取回初始值,您只需要从转换时间日期获取 timeIntervalSince1970:
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(convertedTime) Time converted To Swift Date")
print(convertedTime.timeIntervalSince1970) // "1597269862.9328\n"
请注意,Swift Date
存储为自参考日期以来的时间间隔。如果您想保持日期的准确性,您应该在存档时使用 timeIntervalSinceReferenceDate 而不是 timeIntervalSince1970。检查这个 .
当我将 Unix 纪元时间转换为毫秒时,它会四舍五入。
代码:
import Foundation
extension Date {
public func getMilliSeconds()-> TimeInterval {
return TimeInterval(self.timeIntervalSince1970)
}
}
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time /// (notice the 8 is the last digit)")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(convertedTime) Time converted To Swift Date")
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:m:ss.SSSS"
let withMilli = df.string(from: convertedTime)
print("\(withMilli) Time with milliseconds using Date Formatter /// (notice 8 is missing and this was rounded to .9330")
if let convertedBackToEpochTime = df.date(from: withMilli) {
print("\(convertedBackToEpochTime.getMilliSeconds()) Time converted back to Unix epoch time")
}
日志:
1597269862.9328 Precise Epoch Time /// (notice the 8 is the last digit)
2020-08-12 22:04:22 +0000 Time converted To Swift Date
2020-08-12 15:4:22.9330 Time with milliseconds using Date Formatter /// (notice 8 is missing and this was rounded to .9330
1597269862.933 Time converted back to Unix epoch time
我以 1597269862.9328
开头,以 1597269862.933
结尾。
我怎样才能使日期准确地回到我开始时的日期:1597269862.9328
?
日期的所有组成部分(年、月、日、时、分、秒等)都是整数。毫秒,顾名思义,只精确到 one-thousandth 秒(即:3 位小数)。
你要得到的是nanosecond
属性。这是一个使用 Swift 5.0 中添加的自定义插值功能的示例:
import Foundation
extension String.StringInterpolation {
/// Our custom interpolator for Date
mutating func appendInterpolation(custom date: Date) {
let components: Set<Calendar.Component> = [
.year, .month, .day, .hour, .minute, .second, .nanosecond, .timeZone
]
let values = Calendar.current.dateComponents(components, from: date)
appendLiteral(values.description)
}
}
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time (notice the 8 is the last digit)")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(custom: convertedTime)")
结果:
1597269862.9328 Precise Epoch Time (notice the 8 is the last digit)
timeZone: America/Toronto (current) year: 2020 month: 8 day: 12 hour: 18 minute: 4 second: 22 nanosecond: 932800054 isLeapMonth: false
通知nanosecond: 932800054
。此值与原始输入的差异是由于浮点精度,这是不可避免的。
问题是 DateFormatter
限制在毫秒内。使用它无法显示超过 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.SSSSSSSSSXXXXX"
return formatter
}()
}
Formatter.iso8601withFractionalSeconds.string(from: Date()) // "2020-10-29T16:12:27.111000000Z"
如果您想取回初始值,您只需要从转换时间日期获取 timeIntervalSince1970:
let epochTime: TimeInterval = 1597269862.9328
print("\(epochTime) Precise Epoch Time")
let convertedTime = Date(timeIntervalSince1970: epochTime)
print("\(convertedTime) Time converted To Swift Date")
print(convertedTime.timeIntervalSince1970) // "1597269862.9328\n"
请注意,Swift Date
存储为自参考日期以来的时间间隔。如果您想保持日期的准确性,您应该在存档时使用 timeIntervalSinceReferenceDate 而不是 timeIntervalSince1970。检查这个