【问题标题】:reset date to next hour after top of hour is reached到达整点后将日期重置为下一小时
【发布时间】:2020-10-31 18:37:30
【问题描述】:

我希望我的 swift 代码倒计时到最近的时间点。因此,如果时间为 146,则用户代码应倒计时 14 分钟。现在我下面的代码倒计时到特定的日期和时间。我只是希望它在应用程序运行时倒计时到最近的小时。

import UIKit

class ViewController: UIViewController {
    @IBOutlet var timerLabel: UILabel!
    
    var timer: Timer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(UpdateTime), userInfo: nil, repeats: true)
    }
    
    @objc func UpdateTime() {
        let userCalendar = Calendar.current
        // Set Current Date
        let date = Date()
        let components = userCalendar.dateComponents([.hour, .minute, .month, .year, .day], from: date)
        let currentDate = userCalendar.date(from: components)!
        
        // Set Event Date
        var eventDateComponents = DateComponents()
        eventDateComponents.year = 2021
        eventDateComponents.month = 01
        eventDateComponents.day = 01
        eventDateComponents.hour = 01
        eventDateComponents.minute = 00

        eventDateComponents.timeZone = TimeZone(abbreviation: "GMT")
        

        let eventDate = userCalendar.date(from: eventDateComponents)!
        
        let timeLeft = userCalendar.dateComponents([.day, .hour, .minute, ], from: currentDate, to: eventDate)
    
        timerLabel.text = "\(timeLeft.day!)d \(timeLeft.hour!)h \(timeLeft.minute!)m "

        endEvent(currentdate: currentDate, eventdate: eventDate)
    }
    
    func endEvent(currentdate: Date, eventdate: Date) {
        if currentdate >= eventdate {
            timerLabel.text = "Happy New Year!"
            // Stop Timer
            timer.invalidate()
        }
    }
}

编辑/更新:

我在我的 swift 代码中的目标是到达时间的顶部。在尝试实现@Leo 的答案后,它会打印“Top of Hour”,但问题是它只执行一次。只要应用程序处于打开状态,我希望它每小时打印一次“Top of Hour”。所以我需要重置结束日期,这是我试图在

让日期 = Date() 结束 = date.nextHour

这不会让代码编译。所以我必须将 end var 重置为下一个小时。

【问题讨论】:

  • 您所要做的就是每秒钟而不是每分钟运行一次时钟,以查看当前日期并在分钟为 0 时按铃。
  • 我对原帖做了一些改动。立即尝试

标签: swift date calendar nsdateformatter nsdatecomponentsformatter


【解决方案1】:

无需每秒更新 10 次用户界面。因为它会比需要的速度更快地耗尽设备的电池,而它应该每分钟只运行一次。您可以将计时器 timeInterval 更改为 1 秒,并安排它在下一个偶数秒触发。要获取下一个偶数小时和下一个偶数分钟,您可以使用 Calendar 方法

func nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = .first, direction: Calendar.SearchDirection = .forward) -> Date?

只需创建两个扩展 Date 的计算属性,并为分钟或纳秒分量传递零:

extension Date {
    var nextHour: Date {
        Calendar.current.nextDate(after: self, matching: DateComponents(minute: 0), matchingPolicy: .strict)!
    }
    var nextSecond: Date {
        Calendar.current.nextDate(after: self, matching: DateComponents(nanosecond: 0), matchingPolicy: .strict)!
    }
    var minute: Int {
        Calendar.current.component(.minute, from: self)
    }
}

现在向视图控制器添加一个属性以保留结束日期的参考。请注意,无需将您的计时器声明为可选:

var end: Date?
var timer = Timer()

并创建一个 DateComponentsFormatter 来创建剩余时间的本地化描述:

extension Formatter {
    static let minutesRemaining: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.formattingContext = .standalone
        formatter.unitsStyle = .short
        formatter.allowedUnits = [.minute, .second]
        formatter.includesTimeRemainingPhrase = true
        return formatter
    }()
}

现在您只需设置结束日期并安排计时器在下一个偶数分钟触发:

override func viewDidLoad() {
    super.viewDidLoad()
    // get the current date
    let date = Date()
    // set the end date
    end = date.nextHour
    // schedule the timer to fire at the next even second and set its interval to 1 second
    timer = .init(fireAt: date.nextSecond, interval: 1, target: self, selector: #selector(updateUI), userInfo: nil, repeats: true)
    RunLoop.main.add(timer, forMode: .common)
    updateUI()
}
@objc func updateUI() {
    if Date().minute == 0 || Date() > end {
        end = Date().nextHour
        timerLabel.text = "beginning of hour"
        print("beginning of hour")
    } else {
        // update the remaining time (for a perfect sync we need to subtract a second from the current time)
        let text = Formatter.minutesRemaining.string(from: Date().addingTimeInterval(-1), to: end) ?? ""
        timerLabel.text = text
        print(text)
    }
}

【讨论】:

  • 我在类型 'Formatter' has no member 'minutesRemaining' 时收到错误
  • @FloydGertez 抱歉,这是扩展格式化程序。检查我上次的编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
相关资源
最近更新 更多