NSDate: правильный способ работать со временем суток? - PullRequest
3 голосов
/ 02 ноября 2010

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

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 03 ноября 2010

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

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

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

2 голосов
/ 03 ноября 2010

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

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

Испытательный жгут:

//
//  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.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 на лету полностью снижает производительность.

0 голосов
/ 02 ноября 2010

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

...