Най-добрата практика на NSDate при създаване на дата без времеви елемент

Пиша приложение, което използва основни данни, за да съхранява моите данни. В това е включено поле за дата, от което се интересувам само от датата, а не от часа. Трябва да избера записи въз основа на датата (не часа) и затова създадох категория в NSDate, за да върна дата, нормализирана до зададен час, както следва:

+ (NSDate *)dateWithNoTime:(NSDate *)dateTime {
if( dateTime == nil ) {
    dateTime = [NSDate date];
}
NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:dateTime];
NSDate *dateOnly = [[NSCalendar currentCalendar] dateFromComponents:comps];
[dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)];           // Push to Middle of day.
return dateOnly;

}

След това използвам това, когато добавям данни към основното хранилище на данни (имам сетер, който използва този метод, за да зададе примитивната стойност на датата) и след това използвам този метод, за да създам дата, която използвам за сравняване на датите, когато извършвам заявка за извличане. Така че на теория това винаги трябва да работи - т.е. избирам датите, които търся.

Въпреки това съм малко нервен, тъй като не съм напълно сигурен какъв ефект ще има промяната на часовата зона или локала. Ще работи ли все пак?

Какво се счита за най-добра практика при съхраняване и търсене на дата само когато не се интересувате от часа.

наздраве

РЕДАКТИРАНЕ

След като прочетох препоръчаната дискусия, мисля, че трябва да променя кода си, за да бъде както следва. Мисълта е, че ако се уверя, че го насочвам към конкретна календарна система и конкретна часова зона (UTC), тогава датите винаги трябва да са едни и същи, независимо къде се намирате, когато задавате датата и когато четете датата. Всички коментари относно този нов код се оценяват.

+ (NSDate *)dateWithNoTime:(NSDate *)dateTime {
if( dateTime == nil ) {
    dateTime = [NSDate date];
}

NSCalendar       *calendar   = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                         fromDate:dateTime];

NSDate *dateOnly = [calendar dateFromComponents:components];

[dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)];           // Push to Middle of day.
return dateOnly;

}


person SimonB    schedule 01.12.2010    source източник
comment
Благодаря за решението!! :D Само малка корекция: Редът: [dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)]; Трябва да бъде: dateOnly = [dateOnly dateByAddingTimeInterval:(60.0 * 60.0 * 12.0)];   -  person Leonardo Bortolotti    schedule 02.03.2016


Отговори (3)


Тук трябва да решите няколко проблема. Първо, както отбелязахте, часови зони. Трябва също да се тревожите за лятното часово време, което променя концепцията за „обед“.

Разгледайте тази дискусия на CocoaDev, където инженер на Apple дава някои отговори и обсъжда някои най-добри практики.

person Count Chocula    schedule 01.12.2010
comment
Благодаря за това. След като прочетох тази дискусия, изглежда, че трябва да се уверя, че винаги използвам една и съща календарна система и часова зона за съхранение и сравняване. Добавих нов код към моя въпрос въз основа на това ново мислене. - person SimonB; 01.12.2010

По-просто решение е да се използва предикат, който търси дати в определен диапазон.

Използвайте NSCalendarComponent, за да създадете начална дата и крайна дата за вашия "ден" и след това да ги включите в предиката.

NSPredicate *p=[NSPredicate predicateWithFormat:@"$@ <= date <= $@",startDate,endDate];

Това ще осигури максимална гъвкавост без много сложност. Програмирането на дата и час е измамно сложно. Бъдете готови да свършите малко работа.

person TechZen    schedule 01.12.2010

Освен това се озовах в сценарий, при който трябваше да имам NSDate, за да сравня дата, без да взема предвид времето.

Имах механизъм за филтриране и като част от потребителския интерфейс, ако потребителят избере днес минималната дата като начална дата и крайната дата като днес, щях да покажа „Всички периоди от време“ вместо низ във формата:

1/5/2006 - 24/12/2009

Така че трябваше да взема днешната дата, използвайки +date от NSDate, и да я сравня с крайната дата. Тази крайна дата дойде от UIDatePicker, зададено на без време, но +date върна датата и часа точно сега.

Така че написах този кратък удобен метод, той получава обект за дата, използва NSDateComponents и класа NSCalendar, за да извлече деня, месеца и годината.

След това тези 3 параметъра се използват за създаване на нов NSDate с помощта на NSDateFormatter's -dateFromString: метод, резултатът е NSDate, съответстващ на същата "дата" (в традиционната човешка концепция) като параметъра date, но без време.

- (NSDate *)strictDateFromDate:(NSDate *)date{
    NSUInteger flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
    NSDateComponents *components = [[NSCalendar currentCalendar] components:flags
                                                                   fromDate:[NSDate date]];
    NSString *stringDate = [NSString stringWithFormat:@"%d/%d/%d", components.day, components.month, components.year];

    NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
    formatter.dateFormat = @"dd/MM/yyyy";

    return [formatter dateFromString:stringDate];
}

Надявам се, че можете да използвате и да се наслаждавате на тази функция в бъдеще.

person Daniel    schedule 01.10.2012