CoreData и NSDate - дата хранится на 1 день позже в 2015 году

Я действительно озадачен тем, что должно быть чем-то действительно простым. Особенностью моего приложения является ежемесячно повторяющиеся события, поэтому мне нужно взять дату, добавить к ней месяц и сохранить ее. Каждый месяц я повторяю это.

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

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

Я использую MagicalRecord, чтобы помочь с CoreData, и я почти уверен, что это может иметь какое-то отношение к самому CoreData? Вот простой код, вызываемый для обновления даты:

// create date if we haven't already
    if (!_dateEntity.theDate) {
        NSDate *date = [NSDate date];
        _dateEntity.theDate = date;
    }

    NSLog(@"date before update - %@", _dateEntity.theDate);

    // add a month to it
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setMonth:1];
    _dateEntity.theDate = [calendar dateByAddingComponents:components toDate:_dateEntity.theDate options:0];

    NSLog(@"date after update - %@ \n ***** \n", _dateEntity.theDate);

    // save the context
    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
        if (success) {
            //NSLog(@"You successfully saved your context.");
        } else if (error) {
            //NSLog(@"Error saving context: %@", error.description);
        }
    }];

Это код наполовину sudo, выделенный из реального проекта в отдельный проект только для тестирования (чтобы убедиться, что я не сойду с ума!)

Вот (по запросу) логи из xCode:

2014-07-23 10:48:55.001 dateTest[52136:60b] date before update - 2014-07-23 09:48:54 +0000
2014-07-23 10:48:55.003 dateTest[52136:60b] date after update - 2014-08-23 09:48:54 +0000 
 ***** 
2014-07-23 10:48:59.994 dateTest[52136:60b] date before update - 2014-08-23 09:48:54 +0000
2014-07-23 10:48:59.995 dateTest[52136:60b] date after update - 2014-09-23 09:48:54 +0000 
 ***** 
2014-07-23 10:49:04.685 dateTest[52136:60b] date before update - 2014-09-23 09:48:54 +0000
2014-07-23 10:49:04.686 dateTest[52136:60b] date after update - 2014-10-23 09:48:54 +0000 
 ***** 
2014-07-23 10:49:08.127 dateTest[52136:60b] date before update - 2014-10-23 09:48:54 +0000
2014-07-23 10:49:08.128 dateTest[52136:60b] date after update - 2014-11-23 10:48:54 +0000 
 ***** 
2014-07-23 10:49:12.594 dateTest[52136:60b] date before update - 2014-11-23 10:48:54 +0000
2014-07-23 10:49:12.595 dateTest[52136:60b] date after update - 2014-12-23 10:48:54 +0000 
 ***** 
2014-07-23 10:49:16.014 dateTest[52136:60b] date before update - 2014-12-23 10:48:54 +0000
2014-07-23 10:49:16.015 dateTest[52136:60b] date after update - 2015-01-23 10:48:54 +0000 
 ***** 
2014-07-23 10:49:20.188 dateTest[52136:60b] date before update - 2015-01-23 10:48:54 +0000
2014-07-23 10:49:20.189 dateTest[52136:60b] date after update - 2015-02-23 10:48:54 +0000 
 ***** 
2014-07-23 10:49:32.956 dateTest[52136:60b] date before update - 2015-02-23 10:48:54 +0000
2014-07-23 10:49:32.957 dateTest[52136:60b] date after update - 2015-03-23 10:48:54 +0000 
 ***** 
2014-07-23 10:49:44.061 dateTest[52136:60b] date before update - 2015-03-23 10:48:54 +0000
2014-07-23 10:49:44.061 dateTest[52136:60b] date after update - 2015-04-23 09:48:54 +0000 
 ***** 

Судя по логам все нормально - еще 23 числа (сегодня). Однако, если я на самом деле смотрю в саму базу данных, последние две даты 2015-03-23 ​​и 2015-04-23 отображаются как 2015-03-22 и 2015-04-22 соответственно.

Последнее обновление в базе данных, как показано в браузере SQL: 2015/04/22 10:48:54

Они будут вести себя так до марта 2016 года, после чего они вернутся к правильному хранению. Это то, что я действительно не понимаю.

Кто-нибудь когда-нибудь испытывал что-то подобное? Я рву на себе волосы прямо сейчас


person Emile Bennett    schedule 23.07.2014    source источник
comment
Не могли бы вы зарегистрировать свои _dateEntity.theDate до и после добавления месяца, а затем добавить результаты в качестве обновления к сообщению?   -  person Lebyrt    schedule 23.07.2014
comment
Конечно, только что сделано для вас. Спасибо за вашу помощь!   -  person Emile Bennett    schedule 23.07.2014
comment
Не могли бы вы опубликовать эти две последние даты 2015-03-23 ​​и 2015-04-23, как они появляются в базе данных, а также с указанием времени и часового пояса?   -  person Lebyrt    schedule 23.07.2014
comment
Хорошо, приятель, это сейчас в посте, но и здесь. Последнее обновление в базе данных, как показано в браузере SQL: 22/04/2015 10:48:54   -  person Emile Bennett    schedule 23.07.2014
comment
Хорошо спасибо. Но как насчет часового пояса? Вам удалось получить его из базы данных? На самом деле это может быть не проблема, просто дата журнала и базы данных может быть одной и той же датой, но с разными часовыми поясами.   -  person Lebyrt    schedule 23.07.2014
comment
хм, я нигде не могу найти часовой пояс в базе данных - он не регистрируется в самом объекте NSDate. Есть ли у базы данных в целом часовой пояс? Если это так, и вы думаете, что это поможет выяснить, что происходит, не могли бы вы помочь мне найти его?   -  person Emile Bennett    schedule 23.07.2014
comment
Даты неверны, когда вы смотрите в SQLite самостоятельно или когда используете SQL Browser. Как они выглядят, если вы используете Core Data? Вот что на самом деле важно здесь.   -  person Tom Harrington    schedule 23.07.2014


Ответы (1)


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

Попробуйте этот пример без Core Data:

    NSDate *dateNow = [NSDate date];

    // add a month to it
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setMonth:1];
    components.calendar = calendar;
    NSDate *dateNowPlusOneMonth = [calendar dateByAddingComponents:components toDate:dateNow options:0];

    NSLog(@"now %@", dateNow);
    NSLog(@"now plus one month %@", dateNowPlusOneMonth);

    NSDate *dateMarch01 = [NSDate dateWithTimeIntervalSince1970:1425206934];
    // add a month to it
    NSDate *dateMarch01PlusOneMonth = [calendar dateByAddingComponents:components toDate:dateMarch01 options:1];
    NSLog(@"Interval straddles ST/DST changeover date in USA");
    NSLog(@"March 01 %@", dateMarch01);
    NSLog(@"March 01 plus one month %@", dateMarch01PlusOneMonth);

    NSDate *dateMarch23 = [NSDate dateWithTimeIntervalSince1970:1427107734];
    // add a month to it
    NSDate *march23PlusOneMonth = [calendar dateByAddingComponents:components toDate:dateMarch23 options:0];
    NSLog(@"Interval is after ST/DST changeover date in USA");
    NSLog(@"March 23 %@", dateMarch23);
    NSLog(@"March 23 plus one month %@", march23PlusOneMonth);

Вот результат (с удаленными временными метками NSLog):

now 2014-07-23 18:03:22 +0000
now plus one month 2014-08-23 18:03:22 +0000

Interval straddles ST/DST changeover date in USA
March 01 2015-03-01 10:48:54 +0000
March 01 plus one month 2015-04-01 09:48:54 +0000

Interval is after ST/DST changeover date in   USA
March 23 2015-03-23 10:48:54 +0000
March 23 plus one month 2015-04-23 10:48:54 +0000

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

Листинг 10 Руководства по программированию даты и времени иллюстрирует «Получение воскресенья на текущей неделе». Я думаю, вам нужно будет адаптировать эту процедуру, что-то вроде «получение текущей даты и времени в следующем месяце».

person Hal Mueller    schedule 23.07.2014