【问题标题】:Convert Double (number of days since Dec 30, 1899) to Date in Swift?将 Double(自 1899 年 12 月 30 日以来的天数)转换为 Swift 中的日期?
【发布时间】:2020-02-01 12:09:26
【问题描述】:

我有一个 double 值,表示自 1899 年 12 月 30 日以来的天数(Delphi 中通常的 TDateTime 值)。例如:43854.4410269444

是否可以从这个双精度中创建一个有效的日期值?

【问题讨论】:

  • 查看question
  • 谢谢哈桑,但我拥有的双精度值不是 Unix 时间值,而是自 1899 年 12 月 30 日以来的天数。
  • 计算从 Delphi 纪元到 Unix 纪元的天数并减去该值。然后使用链接中的代码。工作完成。

标签: swift date delphi double


【解决方案1】:

一种方法是获取代表“1899-12-30”的Date,然后调用addingTimeInterval

// either parse a date string...
let formatter = DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd"

let epoch = formatter.date(from: "1899-12-30")!
// or calculate the time directly from 1970
//let epoch = Date(timeIntervalSince1970: -86400 * 25569)

// now we add the quality of the number of days times the number of seconds in a day
let numberOfDays = 43854.4410269444
let result = epoch.addingTimeInterval(86400 * numberOfDays)

【讨论】:

  • 我不熟悉TDateTime,所以我想知道:您是否必须考虑夏令时?一天不一定有 86400 秒。
  • @MartinR 我也不是。但是从它的表示(从一个纪元开始的某个时间单位)和它的名字来看,我猜想它的设计方式会更容易实现。即不考虑 DST。
  • @MartinR 同样,为了考虑 DST,我们还需要一个 OP 没有提供的时区,所以我只是假设 OP 知道他们在做什么。
【解决方案2】:

这是我解决问题的尝试(见下文我如何计算幻数):

extension Date {
    init(fromDelphiTDateTime delphiDate: Double) {
        //Number of seconds between 12/30/1899 12:00 AM and 1/1/1970 12:00 AM
        let tDateTimeUnixTimeOffset = 2209161600.0 

        //24 * 60 * 60
        let numberOfSecondsInDay = 86400.0 

        let delphiTDateTimeAsUnixTime = delphiDate * numberOfSecondsInDay - tDateTimeUnixTimeOffset
        self.init(timeIntervalSince1970: delphiTDateTimeAsUnixTime)
    }
}

我假设TDateTime 没有任何时区信息。 由于 Unix 时间 (timeIntervalSince1970) 采用 UTC,如果它位于不同的时区,您需要将 TDateTime 值转换为 UTC。

例子:

//Dec 30, 1899 at 12:00 AM
let date1 = Date(fromDelphiTDateTime: 0)

//Jan 24, 2020 at 11:04 AM
let date2 = Date(fromDelphiTDateTime: 43854.4410269444)

以下是我使用 Swift 计算幻数 2209161600.0 的方法:

let zeroTDateTimeComponents = DateComponents(calendar: Calendar.init(identifier: .gregorian), timeZone: TimeZone(secondsFromGMT: 0), year: 1899, month: 12, day: 30, hour: 0, minute: 0, second: 0)
let zeroTDateTime = zeroTDateTimeComponents.date
let tDateTimeUnixTimeOffset = zeroTDateTime?.timeIntervalSince1970 //the value is 2209161600.0

希望这会有所帮助,如果社区验证或进一步改进我的答案,我将不胜感激。使用现有已知的 TDateTime 对及其 double 值进行一些单元测试肯定会有所帮助。

【讨论】:

  • 感谢您的努力,但结果值错误。例如:43854.4410269444 = 2020 年 1 月 24 日上午 9:04,而不是 2020 年 1 月 24 日上午 11:35(正确值)。
  • 感谢您指出这一点,我想我发现了我的错误。我没有将时区传递给 DateComponents 初始化程序,它显然在我当前的时区(UTC+3)中创建了一个日期,因此相差大约 3 小时。当我在那里明确传递时区时,结果似乎与 Sweeper 的示例相匹配。我已经根据我的发现更正了我的答案,以防有人决定使用它,我很高兴看到你的问题得到了解决:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 2020-12-07
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多