#ios #swift #iphone #nsdate #utc
Вопрос:
Я получаю две даты от сервера. Текущее время и время разблокировки.
Unlock date: 2021-07-23 05:55:44 0000
Current date: 2021-07-23 05:54:44 0000
Итак, я должен вычесть из даты разблокировки текущую дату и оставшееся время, я должен запустить таймер для разблокировки.
let client = TrueTimeClient.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
let when = DispatchTime.now() 0.1
DispatchQueue.main.asyncAfter(deadline: when) {
self.countDownTimer = .scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.countDownTime()
}
}
}
@objc func countDownTime() {
let ntpTime = client.referenceTime?.now()
let unlockDuration = self.getUnlockCountDownTime(currentTime: unlocksTime ?? "" , unlockTime: unlocksTime ?? "", ntpDate: ntpTime ?? Date())
unlockHrsLabel.text = "(unlockDuration)"
if unlockDuration == "0d :0h : 0: 0" {
self.stopTimer()
//call some api
}
}
func getUnlockCountDownTime(currentTime: String, unlockTime: String, ntpDate: Date) -> String {
let dateFormatter = DateFormatter()
let loc = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = loc
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
// dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let unlockDate = dateFormatter.date(from: "(unlockTime)") ?? Date()
print("unlockDate (unlockDate)")
print("ntpDate (ntpDate)")
let currentDate = dateFormatter.date(from: "(currentTime)") ?? Date()
print("currentDate (currentDate)")
let calendar = Calendar.current
let diffDateComponents = calendar.dateComponents([.day, .hour, .minute, .second], from: unlockDate, to: ntpDate)
let countdown = "(String(describing:diffDateComponents.day!))d :(String(describing: diffDateComponents.hour!))h : (String(describing: diffDateComponents.minute!)): (String(describing: diffDateComponents.second!))"
// print(countdown)
return countdown
}
func stopTimer(){
guard self.countDownTimer != nil else {
fatalError("No timer active, start the timer before you stop it.")
}
self.countDownTimer?.invalidate()
}
Здесь я использовал pod «TrueTime» для получения времени ntp, но если мы изменим время устройства, продолжительность таймера автоматически увеличится.
Предположим, я получаю оставшееся время 1:50 секунд, если я изменю дату на 20 июня 2021 года, она покажет больше дней и часов для разблокировки.
Я должен показывать всегда одинаковую продолжительность таймера разблокировки, независимо от изменений времени и часовых поясов.
Это должно быть как на скриншоте выше. Но, если я изменю дату, она появится на экране ниже, что неправильно
Как это исправить? Есть какие-нибудь предложения?
Комментарии:
1. Отделите логику разблокировки от логики пользовательского интерфейса, установите один таймер на срабатывание один раз после общей продолжительности, а затем используйте другой таймер (или другое решение), который ведет обратный отсчет и обновляет пользовательский интерфейс
2. Я бы начал с отказа от любого использования
Date()
; вы не можете доверять времени локального устройства. Если вы не можете проанализировать входящие даты, выдайте ошибку или что-то в этом роде, не отступайтеDate()
. Как только ваш код не зависит от времени работы устройства, не имеет значения, что происходит на устройстве. Также, почему вы преобразуете строки вDate
несколько раз. Конечно, вы могли бы сделать это один раз. Тогда вам просто нужно отследить прошедшее время.3. Спасибо @JoakimDanielson за ваши ценные предложения
4. Спасибо @Paulw11 за ваши ценные предложения
Ответ №1:
Я нашел решение. Я просто удалил модуль «TrueTime» и вычел текущее время, чтобы разблокировать время с помощью timeinterval, затем я запустил таймер с оставшимися секундами. Затем я запускаю таймер с уменьшением остатка.
@objc func countDownTime() {
self.remainingTime -= 1
seunlockHrsLabel.text = "(self.convertIntegerToFormat(remainingTime: self.remainingTime))"
if remainingTime == 0 {
self.stopTimer()
}
}
func convertIntegerToFormat(remainingTime: Int) -> String {
let days = remainingTime / (24 * 3600)
let hours = remainingTime / 3600
let seconds = remainingTime % 60
let minutes = (remainingTime / 60) % 60
return "(days): (hours): (minutes): (seconds)"
}
Теперь он работает независимо от времени и часовых поясов устройства.