Я пытаюсь, чтобы мое приложение отображало ViewControllers, когда оно достигает 9: 00 UTC каждый день

#ios #swift #firebase #server #nsdate

#iOS #swift #firebase #сервер #nsdate

Вопрос:

Я пытаюсь, чтобы мое приложение отображало ViewControllers, когда оно достигает 9: 00 UTC каждый день. Я не хочу, чтобы оно использовало местное время, поскольку оно может меняться в разных регионах и может быть изменено. Я думал об использовании серверного времени, но у меня возникли проблемы с получением этого решения для работы. Я получил временную метку эпохи и преобразовал ее в дату.

 let ref = FIRDatabase.database().reference()   
let timestamp = FIRServerValue.timestamp()
  ref.setValue(timestamp)

    ref.observe(.value, with: {
        snap in
        if let t = snap.value as? TimeInterval {
            // Cast the value to an NSTimeInterval
            // and divide by 1000 to get seconds.
            print("this is the time in seconds (t)")
            let date = Date(timeIntervalSince1970: t)
            print("this is the time (Date(timeIntervalSince1970: t/1000))")
  

Он распечатывается this is the time 2016-10-10 18:40:21 0000 .

Проблема заключается в том, чтобы выяснить, как извлечь из этого только часовые минуты и секунды, чтобы я мог сравнить даты времени.

Комментарии:

1. Вам нужна помощь, чтобы узнать время или с помощью функции, которая должна запускать функцию в 9 часов?

2. Немного и того, и другого в поиске целостного решения. Вероятно, есть много способов, которыми я могу это сделать, но некоторые из возможных решений, о которых я думал, довольно запутанны.

3. Не совсем понятно, как вы используете Firebase в этом контексте. Выполняется ли этот код только один раз? Оно должно запускаться периодически. Затем вы должны проверить часовой компонент с помощью класса NSCalendar и запускать все, что захотите, если оно достигнет 9:00 часов (или значения удаленной конфигурации Firebase).

4. Он запускается каждый раз, когда загружается просмотр. Я не совсем уверен, как проверить разницу между часовыми минутами и секундами, не глядя на день, месяц или год. Есть предложения?

Ответ №1:

Одним из вариантов может быть:

  • Запрашивать текущее время с сервера при запуске приложения.
  • Вычислите разницу между 9:00 UTC и текущим временем.
  • Установите таймер ( NSTimer ), который срабатывает, когда разница прошла.
  • И, наконец, обрабатывайте обратный вызов любым удобным вам способом: всплывающие экраны, отображение всплывающего окна и т. Д.

Комментарии:

1. Я подумал, что это будет хорошим вариантом, и попробовал то же самое. Поэтому я использовал firebase, чтобы получить текущее время в виде метки времени эпохи и преобразовать его. Я отредактирую свой вопрос, чтобы отразить то, что я пробовал.

Ответ №2:

Вы могли бы использовать что-то вроде этого:

 let calendar = Calendar.current
let components = NSDateComponents()
components.hour = 9

let nineOClock = calendar.nextDate(after: Date(), matching: components as DateComponents, matchingPolicy: .strict)

let timer = Timer(fireAt: nineOClock!, interval: 0, target: self, selector: #selector(doSomething), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)

func doSomething(){
    print("Doing something")
}
  

Комментарии:

1. Насколько я понял, время устройства не подходит.

2. Да, мне нравится этот вариант, но, к сожалению, если пользователь изменит время, я не думаю, что это сработает. Я ошибаюсь?

Ответ №3:

Метод, который вычисляет время (в секундах) до следующих 9 утра на основе текущего времени (секунд с 1970 года).

 func untilNineAmSeconds(now: Int) -> Int {

    let todaySeconds = now % 86400
    let hourSeconds = 3600
    let nineAmSeconds = 9 * hourSeconds
    let daySeconds = 24 * hourSeconds

    if todaySeconds < nineAmSeconds {
        return nineAmSeconds - todaySeconds
    } else {
        return (daySeconds - todaySeconds)   nineAmSeconds
    }
}
  

Теперь вы (1) запрашиваете текущее время у Firebase, (2) получаете интервал времени до 9 утра и (3) назначаете таймер.

 let ref = FIRDatabase.database().reference()   
let timestamp = FIRServerValue.timestamp()
ref.setValue(timestamp)

ref.observe(.value, with: { snap in
    guard let ts = snap.value as? TimeInterval else {
        return
    }

    let seconds = untilNineAmSeconds(now: Int(ts))

    let timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(seconds), repeats: false) { _ in
        // TODO: pop view controllers
    }

    // ...
}
  

Комментарии:

1. Мне нравится решение, но я получаю несколько ошибок. Я получаю сообщение об ошибке с инструкцией guard и с Int(timeInterval). Нет интервала времени, откуда вы его получаете? Еще раз спасибо за вашу помощь.

2. Поэтому я не уверен, работает ли функция так, как она должна. Когда я использую его и распечатываю секунды, я продолжаю получать очень случайные результаты. Я получу как 80887, затем я запущу приложение через 10 секунд и получу 72708. Прошлой ночью я попытался запустить функцию, и кажется, что вызывается оператор else «return (daySeconds — todaySeconds) nineAmSeconds». Таким образом, предполагается, что это займет 86400 секунд — временная эпоха 9 часов или любое другое время в секундах. Разве это не будет отрицательным числом? Но, несмотря на это, я не получаю желаемых результатов. Любые предложения. Спасибо.

3. Я также не уверен, что учитываются миллисекунды, поэтому я продолжаю получать разные результаты.

4. Я нашел решение. Я хочу проголосовать за ваш ответ за всю вашу помощь, но, в конце концов, у меня это не сработало. Извините, но еще раз спасибо. В своем ответе я упомяну всю вашу помощь.

Ответ №4:

Благодаря Артему и его помощи я был направлен на правильный путь. После долгого времени, потраченного на изучение преобразования даты, я понял это. Конечная цель — преобразовать два значения в целые числа, чтобы я мог сравнить их за секунды и использовать их в таймере, чтобы выяснить, сколько времени осталось.

   ref.observe(.value, with: {
        snap in
        if let t = snap.value as? TimeInterval {

     let FinalTimeInterval = self.convertStringToDateToIntStartTime() - self.convertEpochTimeStampToDateToStringToDateToIntEndTime(timeInterval: t)

            if FinalTimeInterval < 0 {
                print("less than zero")
            } else {

            let timer = Timer.scheduledTimer(withTimeInterval: TimeInterval(FinalTimeInterval), repeats: false) { _ in
                // TODO: pop view controllers
                print("i'm so happy this is working")
            }
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)

            }

        }
    })


  func convertEpochTimeStampToDateToStringToDateToIntEndTime(timeInterval: TimeInterval) -> Int {
    let date = Date(timeIntervalSince1970: timeInterval/1000)

    var dateFormater = DateFormatter()
    dateFormater.timeZone = TimeZone(identifier: "UTC")
    dateFormater.dateFormat = "HH:mm:ss"
    let dateString = dateFormater.string(from: date)

    let endTime = dateFormater.date(from: dateString)


        dateFormater.dateFormat = "HH"
        let endHours = Int(dateFormater.string(from: endTime!))
        dateFormater.dateFormat = "mm"
        let endMinutes = Int(dateFormater.string(from: endTime!))
        dateFormater.dateFormat = "ss"
        let endSeconds = Int(dateFormater.string(from: endTime!))



    return endSeconds!   endMinutes! * 60   endHours! * 3600


}
func convertStringToDateToIntStartTime() -> Int {

    var dateFormater = DateFormatter()
    dateFormater.timeZone = TimeZone(identifier: "UTC")
    dateFormater.dateFormat = "HH:mm:ss"

    let startTime = dateFormater.date(from: "09:00:00")
    dateFormater.dateFormat = "HH"

    let startHours = Int(dateFormater.string(from: startTime!))
    dateFormater.dateFormat = "mm"

    let startMinutes = Int(dateFormater.string(from: startTime!))
    dateFormater.dateFormat = "ss"

    let startSeconds = Int(dateFormater.string(from: startTime!))



    return startSeconds!   startMinutes! * 60   startHours! * 3600

}