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