【问题标题】:Swift Correct calculation of time as a proportion of day迅速正确计算时间占一天的比例
【发布时间】:2020-05-23 17:44:05
【问题描述】:

我正在尝试计算特定时间相当于一天的比例。例如,06:00 是 0.25,18:00 是 0.75 等等。

我正在评估一系列 Date 类型的日期,这些日期是在 timeZone = "GMT" 中创建的。下面的例程工作正常。但是,当我为 DST 中的日期评估 23:00 之后的时间时,计算会出错,因为时间被评估为第二天(例如 23:08 被评估为 00:08)

我有什么方法可以识别从 GMT 到 DST 的日期何时进入第二天?然后我可以相应地调整计算。

我的判断输入时间代表比例的函数是:

func getTimeAsProportionOfDay(time: Date) -> Double {
    //calculates the amount of day, between 0 and 1 given the input date

    let calendar =  Calendar.current
    let hours = calendar.component(.hour, from: time)
    let minutes = calendar.component(.minute, from: time)
    let seconds = calendar.component(.second, from: time)
    let totalSeconds = Double(hours * 60 * 60 + minutes * 60 + seconds)

    return Double(totalSeconds) / Double(secondsInDay)
}

另外,我知道我的 secondsInDay (= 24*60*60) 常数在技术上可能不正确,但我不确定用什么系统常数替换它。

谢谢。

【问题讨论】:

  • 有些日子只有 23 小时。你对这些有什么计划?
  • 我想确定的是,你是追求字面的真实还是数字的简单。
  • 马特,23 小时的日子(幸运的是)自己解决了。关于你的第二点,我认为,就像在任何一天一样,如果我要评估的时间超出了那一天,那么它应该被忽略,因为比例 > 1。但是,我找不到办法排除这些天或评估为 > 1 然后忽略。

标签: swift date swift5


【解决方案1】:

您只需要获取原始日期之后的第二天并减去一秒。然后使用日历方法计算该日期的秒数

func ordinality(of smaller: Calendar.Component, in larger: Calendar.Component, for date: Date) -> Int?

你可以通过一些助手让你的生活更轻松

extension Date {
    var dayAfter: Date { Calendar.current.date(byAdding: .day, value: 1, to: noon)!}
    var noon: Date { Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)! }
    var startOfDay: Date { Calendar.current.startOfDay(for: self) }
    var endOfDay: Date { Calendar.current.date(byAdding: .init(second: -1), to: dayAfter.startOfDay)! }
}

测试 endOfDay

Date().endOfDay  // "Feb 7, 2020 at 11:59 PM"

还有你的方法:

func getTimeAsProportionOfDay(time: Date) -> Double {
    // discarding the fractional seconds
    let time = Calendar.current.date(bySetting: .nanosecond, value: 0, of: time)!
    return Double(Calendar.current.ordinality(of: .second, in: .day, for: time)!-1) /
        Double(Calendar.current.ordinality(of: .second, in: .day, for: time.endOfDay)!-1)
}

游乐场测试:

let date = DateComponents(calendar: .current, year: 2020, month: 2, day: 7, hour: 23, minute: 08).date!
date.endOfDay
let result = getTimeAsProportionOfDay(time: date)  // 0.9639000451394113

【讨论】:

  • 谢谢,这很有帮助,但在我的功能中,我实际上想忽略 DST 已移至第二天的时间。因此,例如,2020 年 3 月 25 日的 23:08(在英国,这仍然是 GMT)被评估为 0.9639000...但是 2020 年 4 月 26 日的 23:08 GMT(在 DST 中是 2020 年 4 月 27 日的 00:08)被识别为在第二天,我可以返回一个值 1。
  • 如果你愿意,我可以使用 UTC 时间发布
  • 对于上下文,我使用一天的比例来创建一个渐变,代表给定一天中不同质量的光。我正在评估的时间是当天的各种天文状态。因此,如果天文事件发生在夏令时生效日期的英国夏令时 23:08,那么从技术上讲,该事件属于第二天,可以忽略梯度计算。
  • 所以 23:08 将是一天的结束,应该返回 1?所以你要为你的方法提供一天的结束吗?
  • 从格林威治标准时间 23:00 到格林威治标准时间 23:59 的任何时间都应返回 1,但仅在 DST 期间,据我所知,任何表达式中的日期计算为 00:00 DST第二天 00:59 DST。即我想忽略由于 DST 而转移到第二天的时间(或给他们一个默认输出 1),但我无法找到识别它们的方法。日期对我来说有点新,很棒但很新!
【解决方案2】:

一般来说,我会这样做:

let date = Date()

var dayStart = Date()
var dayDuration: TimeInterval = 0

Calendar.current.dateInterval(of: .day, start: &dayStart, interval: &dayDuration, for: date)

let timeInterval = date.timeIntervalSince(dayStart)
let percentage = timeInterval / dayDuration

print(percentage)

【讨论】:

  • 我在操场上试过这个,它给出了相同的结果 - 它评估 GMT 23:08 作为 8 分钟的比例(即 0.0055555....)。
  • 我真正想做的是确定时间何时显示为第二天。例如当我处理 2020 年 4 月 25 日格林威治标准时间 23:08 的时间并通过我的代码将其评估为 2020 年 4 月 26 日 00:08 的 DST 日期时,这是一个特殊情况,我想处理它。跨度>
  • 你应该解释真正的目标,因为规范不清楚。或者改进规格!
【解决方案3】:

所有,感谢您的帮助。我想我已经找到了解决这个问题的方法,方法是使用固定的一天开始进行比较。

func getTimeAsProportionOfDay(time: Date) -> Double {
    //calculates the amount of day, between 0 and 1 given the input date


    if Int(time.timeIntervalSince(tides.tideDate)) > secondsInDay { //time has been moved to next day by BST change) so return 1 for gradient
        return 1.0
    } else {/// this was my original code
        let calendar =  Calendar.current
        let hours = calendar.component(.hour, from: time)
        let minutes = calendar.component(.minute, from: time)
        let seconds = calendar.component(.second, from: time)
        let totalSeconds = Double(hours * 60 * 60 + minutes * 60 + seconds)

        return Double(totalSeconds) / Double(secondsInDay)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 2021-03-23
    • 1970-01-01
    相关资源
    最近更新 更多