2016-12-15 2 views
-1

Я пытаюсь написать код для приложения для планирования, и эти расписания должны основываться на текущем времени пользователя. Например, что-то доступно с 17:00 до 21:00 в текущий день. Когда я получаю текущее время с помощью NSDate(), печать его приводит к utc: 2016-12-15 13:12:05 +0000. Я знаю, что это в utc, потому что, если я добавлю свое местное смещение в моей голове, это будет фактическое время на моем телефоне. Проблема, с которой я сталкиваюсь, заключается в попытке создать эти окна времени, иногда время окончания идет на следующий день, потому что нет никакого смещения. Пример: смещение часового пояса пользователя -5, а в настоящее время - в 21:00 по местному времени. Это покажет 2 утра на следующий день, который не сработает, потому что мне нужно, чтобы он был в тот же день. Как вы управляете этим делом? Я не уверен, что функция print() даже печатает правильную дату. Подходит ли он к часовому поясу моей машины? Мне нужно увидеть фактические даты, потому что мне приходится иметь дело с часовыми поясами по всему миру. Я попытался сменить зону +5 раз, и весь мой код планирования ломается. Как я могу гарантировать, что мой планировщик всегда будет работать с местным временем пользователя?Swift NSDate, показывающий UTC при печати в отладчике. Как узнать, является ли это местным временем или utc при сравнении даты/времени?

Если кто-то сделал это, было бы полезно, если бы вы могли показать, как создать дату начала, дату окончания, а затем, как сравнить с текущей датой, чтобы увидеть, действительно ли она или не попадает в окно. Это необходимо для работы во всех часовых поясах.

Редактировать: Вот что я не понимаю. Как обрабатывать даты, которые находятся в форме такой строки: «2016-12-15T22: 16: 11 + 05: 00», где дата и время находятся в «местном времени»? Я знаю, что дата находится в местном времени, потому что это то, что было отображено на моем телефоне, когда я сгенерировал его (15 декабря 10 вечера). Теперь, когда у меня есть эта дата, я хочу знать, попадает ли она между окном 8 вечера и 11 вечера 15 декабря. Как мне это сделать? Когда я конвертирую эту строку в NSDate, она скрывает ее до UTC (это то, что я вижу в отладчике), и теперь дата составляет +5 часов с местного времени (что происходит на следующий день). Проблема в том, что я сравниваю дату на следующий день с текущей датой, например, текущая дата/время - 15 декабря 9 вечера. Но мне нужно знать, что дата указана 15 декабря 10 вечера.

+1

Опубликуйте свой текущий код, который не работает – dan

+2

FYI - когда вы видите '2016-12-15 13:12:05 + 0000', вы знаете, что это UTC, потому что это означает' + 0000'. Это часовой пояс. UTC - часовой пояс '+ 0000'. – rmaddy

ответ

2

Первое, ключевое, что нужно понять, это то, что NSDate не представляет собой «дату» каким-либо образом, о чем вы, вероятно, думаете. Он представляет собой единичный момент времени (без учета релятивистских эффектов или чего-то еще, чего вы интуитивно считаете «мгновением во времени»).

Это значит, что у NSDate нет часовой пояс. У него нет места. Он сам не знает ничего о «днях» или «часах» или «месяцах». Это только количество секунд, прошедших с определенного момента времени.

Почему я продолжаю и продолжаю об этом? Потому что NSDate почти никогда не то, что вы хотите для приложения для планирования. Когда вы говорите «2: 00p 15 марта 2017 года», вы имеете в виду номинальное значение времени, основанного на каком-то календаре. Поскольку календари могут меняться со временем (правила DST на самом деле do меняются со временем непредсказуемыми способами), вы не можете точно знать, что представляет собой момент, который представляет любое будущее номинальное время. Вы можете догадаться, но вы не можете знать, потому что правила, которые сопоставляют имена с моментами, могут измениться до этого. И, конечно, даже зная правила, это номинальное время будет представлять разные моменты времени, в зависимости от того, к какой часовой зоне он должен применяться. Возможно даже, что номинальное время вообще не существует (так как DST может пропустить его) или для его отображения на несколько мгновений (так как DST может пропустить назад).

Если вы планируете работу, вы хотите работать с NSCalendar и NSDateComponents. Эти инструменты позволяют вам кодировать номинальное время, применять часовые пояса и, в противном случае, разбираться с беспорядочностью календарных систем. Их необходимо преобразовать только в NSDate, понимая, что если это будущая дата, преобразование будет неопределенным.

NSDateComponents также позволяет вам отслеживать то, что вы действительно знаете о дате, а что нет, поскольку большая часть из них не является обязательной. Например, можно создать NSDateComponents с часовым поясом nil и без времени. Это позволяет вам выражать такие вещи, как «Хэллоуин - это все 31 октября, независимо от того, в каком часовом поясе вы находитесь». Но также выражаем: «Эта встреча проходит в 2:00 вечера по восточному стандартному времени, которая составляет 1: 00p КНТ». Преобразование этих вещей в NSDate преждевременно неизменно ведет к Хэллоуину, начинающемуся с 10 вечера 30 октября, и другой такой вздор.


Что касается вашего редактирования, я думаю, что все ваши путаницы над тем, что "2016-12-15T22: 16: 11 + 05: 00" означает. Это абсолютный момент времени. Это не местное время. Это не UTC. Это конкретный момент времени, когда все согласятся с тем, что это такое. Любой человек в мире согласится, что это 1481822171 секунд после Unix Epoch. Люди на Луне или на Марсе тоже согласились бы. Это абсолютный момент времени. Причина, по которой это правда, - «+05: 00». Это компенсирует номинальное время («15 декабря 2016 в 22:16:11») в абсолютное время (1481822171 секунд после Эпохи).

Когда вы превращаете это в NSDate, единственная информация, хранящаяся, - 1481822171. Нет ничего другого. Это не «в часовом поясе». Это не «местный». Это 1481822171. Когда вы печатаете описание даты, которое просто для удобства, оно печатает «15 декабря 2016 года, 12:16 вечера» для меня. Но это печатается по местному времени только для удобства. Это не означает, что NSDate является «по местному времени». Если вы хотите распечатать это, вы должны всегда использовать NSDateFormatter и применять часовой пояс, который вы хотите применить. Никогда не полагайтесь на description.

Я знаю, что повторяю одно и то же снова и снова, но людям кажется очень трудным «получить». Абсолютное время не имеет часового пояса. Часовые пояса существуют чисто для номинальных времен, потому что это делает людей счастливыми. Номинальные времена связаны с тем, как люди думают о календаре. Они имеют ограниченное отношение к тому, как работает (что не заботится о том, где вы находитесь на планете, или в какой политической системе вы находитесь и в каком календаре они предпочитают).

Если вы хотите узнать, существует ли это между некоторыми номинальными временами, вам нужно выяснить, когда это действительно на самом деле. Так что вы могли бы сделать что-то вроде этого:

// 8pm and 11pm on the 15th of December (in the +05:00 timezone). 
var startComp = DateComponents() 
startComp.year = 2016 
startComp.month = 12 
startComp.day = 15 
startComp.hour = 20 
startComp.timeZone = TimeZone(secondsFromGMT: 5*60*60)! // +05:00 

var endComp = startComp 
endComp.hour = 23 

let calendar = Calendar(identifier: .gregorian) 
let startDate = calendar.date(from: startComp)! 
let endDate = calendar.date(from: endComp)! 

let targetDate = ISO8601DateFormatter().date(from: "2016-12-15T22:16:11+05:00")! 

startDate < targetDate && targetDate < endDate // true 
+0

Так есть ли предпочтительный «правильный путь» для создания даты/времени для сравнения с использованием календаря и компонентов? Например, если я хочу создать текущую дату/время на телефоне пользователя и/или если я хочу создать дату/время из строки в utc или строку по местному времени? Я смотрю ТАК, и все делают по-другому. Это для быстрого 2.3. Я не смог обновить до версии 3 для этого проекта. – u84six

+0

Я не уверен, что вы имеете в виду здесь «правильно». 'NSDateComponents' имеет различные свойства, которые вы можете назначить для создания даты/времени. Чтобы преобразовать «сейчас» (что лучше всего достигается с помощью 'NSDate()') для компонентов, вам нужен календарь: 'calendar.components (in: from:)'. Преобразование в строки и из них осуществляется с помощью 'NSDateFormatter'. –

+0

Что я подразумеваю под «правильным способом», так это то, что если у меня есть строка даты, когда произошел какой-то случай, и он был сохранен в UTC, как я могу использовать календарь/компоненты для преобразования этой строки, которая будет использоваться в функции сравнения против текущей локальной даты/времени пользователя? Пример: пользователь сделал что-то, что вызвало событие, у которого есть дата, сохраненная в UTC. Они путешествуют и меняют свой часовой пояс. Когда я прочитал эту дату, чтобы сравнить ее текущее время, что мне нужно делать с компонентами, чтобы убедиться, что я делаю правильное сравнение? – u84six

0

NSDate (или дата, в Swift 3) объекты сохранить двойник, который записывает в момент времени, в любом месте на планете, независимо от часового пояса. Под обложками это двойное число - это количество секунд с полуночи 1 января 2001 года в Greenwich UK («дата эпохи»), но это произвольная «нулевая точка» и не привязывает объект NSDate к определенному часовому поясу.

Для отображения даты в вашем местном часовом поясе необходимо использовать формат даты.

Вы можете использовать код:

print(NSDateFormatter.localizedStringFromDate(date, 
    dateStyle: .MediumStyle, 
    timeStyle: .MediumStyle)) 

Это будет отображать дату date в локальном часовом поясе пользователя и используя свои региональные настройки.

Что касается выполнения математики по датам, существует ряд методов, которые позволяют добавлять единицы времени к датам. Взгляните на документы для класса NSCalendar.Например, посмотрите на метод nextDateAfterDate(_:matchingComponents:options:)

Это позволит вам создать NSDate на 5 часов вечера сегодня, например.

+0

Первый абзац очень вводит в заблуждение. Объекты NSDate ничего не знают о UTC, а количество секунд, с тех пор, как эпоха не связана с часовым поясом (ее невозможно сохранить в UTC), это скалярная разница между двумя удвоениями. Свойство 'description' преобразуется в номинальное время в UTC; это единственная вещь UTC в NSDate. –

+1

@RobNapier, я отредактировал первую часть своего ответа, чтобы попытаться устранить путаницу. Улучшено ли редактирование? –

Смежные вопросы