2010-11-02 2 views
3

Я работаю с расписанием, которое указывает время суток, например 10:30. Однако я не знаю даты. Я собираюсь хранить их как значения в NSDictionary и хотел бы иметь дело с ними прямолинейно.NSDate: Правильный способ работать со временем суток?

Я не могу использовать NSDate, так как у меня нет даты. По крайней мере, не в прямом смысле.

Другой способ, который кажется очевидным, - NSTimeInterval, но похоже, что это, вероятно, источник очень тонких ошибок. Я думаю, в частности, о летнем времени (на мой взгляд, на этой неделе почему-то!).

Помимо этого, единственное, что действительно весит, - держать его в форматированной строке или кодировать в NSNumber (например, hours * 60 + minutes). Разумеется, оба из них будут работать отлично, но, похоже, я изобретаю квадратное колесо, где я уверен, что где-то уже есть круглый.

Что является наименьшим против зернового способа борьбы с сырыми временами с использованием какао?

ответ

2

Короткий ответ заключается в том, что нет встроенного механизма для хранения времени суток, поэтому используйте только то, что наиболее удобно для вас. Я использовал строки в прошлом, используя свой собственный код кодирования и разбора (например, «22:00»), потому что их легко читать и отлаживать, но нет ничего плохого в том, что вы храните секунды или минуты за полночь, как вы предлагаете. Просто помните, что вам придется самому заниматься математикой.

Как вы это сделаете, вам понадобятся отдельные данные года, месяца, дня, часа, минуты и секунды, чтобы вы могли построить NSDate из NSDateComponents, используя метод NSCalendar -dateFromComponents:.

И как уже говорили другие, вы не можете установить время-день по добавления часов и минут к существующему NSDate, потому что если вы пересекаете границу перехода на летнее время, вы не получите значение, которое вы ожидаете. (Тем не менее, я предполагаю, что вы можете добавлять компоненты дня и месяца, не беспокоясь о DST)

0

Вы можете использовать NSDateComponents хранить только необходимые компоненты (час и минуты, например), а затем использовать NSCalendardateByAddingComponents:toDate:options: создать абсолютную ссылку на дату, когда нужно с помощью сериализованные компонентов и дату базы.

+0

К сожалению, это возвращает неправильный результат в дни, когда часы настроены. Добавление десяти часов в полночь возвращается 11:00 в 2010-03-14 и 9:00 в 2010-11-07. Возможно, я мог бы обмануть и сделать свое время относительно 4:00 утра или что-то еще, но тогда я буду делать глупое предположение о календаре. (Возможная причина ошибки тревоги iPhone?) –

+0

Арг, да, это похоже на возможный источник ошибки iPhone. Ну, хорошо, это стоило попробовать. :-) –

+0

Да. И это ужасно неудобно, когда действительно отличная идея не работает. Но спасибо за попытку. :) –

2

Итак, я думаю, что нет простого встроенного способа сделать это. Также похоже, что единственный способ заставить Cocoa построить время, которое я ожидаю на границах DST, - это строки.

Так что для потомков, похоже, я буду использовать что-то вроде этого.

Тест Жгут:

// 
// TimeTest.m 
// 

#import <Foundation/Foundation.h> 

#import "Utility.h" 

id utility; 

void testTime(NSTimeInterval time) { 
    id gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar] autorelease]; 

    id oneDay = [[[NSDateComponents alloc] init] autorelease]; 
    [oneDay setDay: 1]; 

    id thisDay = [gregorian dateFromComponents: [gregorian components: (NSEraCalendarUnit | NSYearCalendarUnit) 
                  fromDate: [NSDate date]]]; 
    for (NSInteger dayIdx = 0; dayIdx < 365; ++dayIdx) { 
     NSDate *dateTime = [utility timeInSeconds: time 
              onDate: thisDay]; 
     NSLog(@"%@", dateTime); 

     thisDay = [gregorian dateByAddingComponents: oneDay 
              toDate: thisDay 
              options: 0]; 
    } 
} 



int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    utility = [[[Utility alloc] init] autorelease]; 

    testTime(((10 * 60.0) + 0.0) * 60.0); 
    testTime(((9 * 60.0) + 30.0) * 60.0); 

    [pool drain]; 
    return 0; 
} 

Utility заголовок: реализация

// 
// Utility.h 
// 

#import <Foundation/Foundation.h> 


@interface Utility : NSObject { 
    NSCalendar *gregorian; 
    NSDateFormatter *dateWithoutTimeFormatter, *dateWithTimeFormatter; 
} 

- (NSDate *)timeInHours: (NSInteger)hours 
       minutes: (NSInteger)minutes 
       seconds: (NSInteger)seconds 
       onDate: (NSDate *)inDate; 

- (NSDate *)timeInSeconds: (NSTimeInterval)inTime 
        onDate: (NSDate *)inDate; 

@end 

Полезность:

// 
// Utility.m 
// 

#import "Utility.h" 


@interface Utility() 
@property (nonatomic, readwrite, retain) NSCalendar *gregorian; 
@property (nonatomic, readwrite, retain) NSDateFormatter *dateWithoutTimeFormatter, *dateWithTimeFormatter; 
@end 



@implementation Utility 



@synthesize gregorian, dateWithoutTimeFormatter, dateWithTimeFormatter; 



- (NSDate *)timeInHours: (NSInteger)hours 
       minutes: (NSInteger)minutes 
       seconds: (NSInteger)seconds 
       onDate: (NSDate *)inDate; 
{ 
    id timeStr = [[NSMutableString alloc] initWithFormat: @"%02d:%02d:%02d", hours, minutes, seconds]; 
    id dateStr = [dateWithoutTimeFormatter stringFromDate: inDate]; 
    id dateTimeStr = [[NSString alloc] initWithFormat: @"%@ %@", dateStr, timeStr]; 
    [timeStr release]; 
    id dateTime = [dateWithTimeFormatter dateFromString: dateTimeStr]; 
    [dateTimeStr release]; 
    return dateTime; 
} 



- (NSDate *)timeInSeconds: (NSTimeInterval)inTime 
        onDate: (NSDate *)inDate; 
{ 
    NSAssert1(inTime < 24.0 * 3600.0, @"Time %f must be less than 24hrs", inTime); 

    double temp = inTime; 
    int hours = rintf(floor(temp/3600.0)); 
    temp -= (hours * 3600); 
    int minutes = rintf(floorf(temp/60.0)); 
    temp -= (minutes * 60); 
    int seconds = rintf(temp); 

    return [self timeInHours: hours 
        minutes: minutes 
        seconds: seconds 
         onDate: inDate]; 
} 



- (id)init; 
{ 
    if ((self = [super init])) { 
     self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar] autorelease]; 
     self.dateWithoutTimeFormatter = [[[NSDateFormatter alloc] init] autorelease]; 
     [dateWithoutTimeFormatter setDateFormat: @"yyyy-MM-dd"]; 
     self.dateWithTimeFormatter = [[[NSDateFormatter alloc] init] autorelease]; 
     [dateWithTimeFormatter setDateFormat: @"yyyy-MM-dd HH:mm:ss"]; 
    } 
    return self; 
} 



- (void)dealloc; 
{ 
    self.gregorian = nil; 
    self.dateWithoutTimeFormatter = nil; 
    self.dateWithTimeFormatter = nil; 
    [super dealloc]; 
} 



@end 

Зачем с отдельным блоком для этого? Ну, я написал достаточно кода форматирования даты, чтобы знать, что построение NSCalendar и NSDateFormatter на лету полностью убивает производительность.