Изменение времени уменьшения таймера при изменении даты устройства в Swift

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

Теперь он работает независимо от времени и часовых поясов устройства.