Приложение iOS Другой часовой пояс обрабатывает записи даты по-разному

Я выпустил свое первое приложение в App Store 2 месяца назад, и до сих пор успех был превосходным. Однако недавно я обнаружил проблему.

Предпосылка приложения состоит в том, чтобы иметь возможность отслеживать отправленные и полученные конверты с деньгами. Это простое приложение, которое позволяет вам добавлять записи, а затем на панели вкладок отображает хронологическую шкалу времени с последующей фильтрацией только по имени, событию и году на других вкладках. Он хорошо работает по всему миру, за исключением случаев, когда вы меняете часовой пояс.

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

Дата выбирается с помощью UIDatePicker для получения фактической даты.

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

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

NSCalendar *yearCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *yearComponent = [yearCal components:NSYearCalendarUnit fromDate:self.datePicker.date];
NSDate *selectedYear = [yearCal dateFromComponents:yearComponent];

Не слишком сильно меняя функциональность приложения (я хочу, чтобы оно работало таким же образом), как мне указать часовой пояс, скажем, по Гринвичу, но из-за перехода на летнее время и т. д. я бы хотел, чтобы это было чем-то например, 12 часов дня по Гринвичу в качестве стандарта, поэтому независимо от того, где вы находитесь в мире, он будет сосредоточен на 12 часов дня по Гринвичу в это время.

Я надеюсь, что это имеет смысл, но любая помощь будет оценена по достоинству.

Спасибо,


person amitsbajaj    schedule 16.02.2014    source источник
comment
обычно я использую dateFormatter с часовым поясом GMT для анализа строк даты и отправки/получения строки даты с нулевым часовым поясом (например, @01/01/2014 +000). NSDateFormatter * dateFormatter = [NSDateFormater new]; [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT: 0]]. Не уверен, что это правильное решение, но оно отлично работает для моих нужд.   -  person Mykola Denysyuk    schedule 16.02.2014
comment
Дорогой Николай - большое спасибо за ответ, и это имело смысл - я использовал ответ Мартина, чтобы заставить это работать, но я также понимаю ваш подход - ценю это!   -  person amitsbajaj    schedule 19.02.2014


Ответы (1)


С часовыми поясами довольно сложно иметь дело. Вам всегда нужно учитывать семантику вашего свойства даты (например, если значение, введенное в 2014 году в Австралии, должно отображаться как «в 2014 году» или «в 2013 году», потому что «домашний часовой пояс» находится в США, где это было в 2013 году и так далее)

NSCalendar по умолчанию использует текущий локальный часовой пояс, как и UIDatePicker (и NSTimeFormatter, который используется внутренне, когда вы выполняете po date в отладчике). Мой первый совет - хранить год как отдельное поле в БД, если вы хотите выполнять фильтрацию на его основе.

Но если вы хотите «нормализовать» значения даты для определенного часового пояса, вы можете установить часовой пояс UTC на NSDateComponents, чтобы получить первый момент года в UTC:

NSCalendar *yearCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *yearComponent = [yearCal components:NSYearCalendarUnit fromDate:self.datePicker.date];
[yearComponent setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]
NSDate *selectedYear = [yearCal dateFromComponents:yearComponent];

Это переопределяет собственное свойство timeZone NSCalendar (которое должно совпадать со свойством UIDatePicker).

person Martin Ullrich    schedule 16.02.2014
comment
Привет, Мартин! Большое спасибо за ответ и мои извинения за поздний ответ (было несколько сумасшедших дней), но ваш код действительно очень помог и обеспечил устранение этой ошибки. Это было действительно полезно, и это имеет смысл с использованием часового пояса UTC. Большое спасибо за это - очень признателен! - person amitsbajaj; 19.02.2014