简体   繁体   English

Swift:具有 timeIntervalSince1970 的精度

[英]Swift: Precision with timeIntervalSince1970

When I convert Unix epoch time to milliseconds, it's getting rounded.当我将 Unix 纪元时间转换为毫秒时,它变得四舍五入。

Code:代码:

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")
}

Log:日志:

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

I started with 1597269862.9328 and ended with 1597269862.933 .我开始与1597269862.9328和止带1597269862.933 How can I get the date back to exactly what I started with: 1597269862.9328 ?我怎样才能让日期回到我开始的时候: 1597269862.9328

All components (year, month, day, hour, minute, second, etc.) of a Date are integers. Date 的所有组件(年、月、日、小时、分钟、秒等)都是整数。 And millisecond, true to its name, is only accurate to one-thousandth of a second (ie: 3 decimal digits).毫秒,顾名思义,只能精确到千分之一秒(即:3 个十进制数字)。

What you want to get is the nanosecond property.您想要获得的是nanosecond属性。 Here's an example using custom interpolation feature added in Swift 5.0:这是使用 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)")

Result:结果:

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

Notice nanosecond: 932800054 .注意nanosecond: 932800054 The difference between this value and the original input is due to floating point precision, which is unavoidable.该值与原始输入的差异是由于浮点精度造成的,这是不可避免的。

The issue there is that DateFormatter is limited to milliseconds.问题在于DateFormatter仅限于毫秒。 There is no way to display more than 3 fraction digits using it.使用它无法显示超过 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"

If you would like to get the initial value back you just need top get the timeIntervalSince1970 from your convertedTime date:如果您想取回初始值,您只需要 top 从您的 ConvertTime 日期获取 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"

Note that Swift Date is stored as the time interval since reference date.请注意,Swift Date存储为自参考日期以来的时间间隔。 If you would like to preserve the date accuracy you should use timeIntervalSinceReferenceDate instead of timeIntervalSince1970 when archiving it.如果您想保留日期准确性,您应该在存档时使用 timeIntervalSinceReferenceDate 而不是 timeIntervalSince1970。 Check this post .检查这个帖子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM