【问题标题】:NSDate: Right way to work with time of day?NSDate:使用一天中的时间的正确方法?
【发布时间】:2010-11-02 19:55:30
【问题描述】:

我正在使用指定一天中的时间的时间表,例如上午 10:30。然而,我不知道日期。我会将这些值作为值存储在 NSDictionary 中,并希望以直接的方式处理它们。

我不能使用NSDate,因为我没有约会。至少,不是以直接的方式。

另一种似乎很明显的方式是NSTimeInterval,但这看起来可能是非常微妙的错误的来源。我特别想到了夏令时(出于某种原因,这周我想到了这一点!)。

除此之外,唯一真正想到的是将其保存在格式化的字符串中或将其编码为NSNumber(如hours * 60 + minutes)。当然,这两种方法都可以正常工作,但似乎我正在发明一个方形轮子,我确信某处已经有一个圆形轮子。

什么是最不反对使用 Cocoa 处理原始时间的粗略方式?

【问题讨论】:

    标签: cocoa cocoa-touch time nsdate


    【解决方案1】:

    简短的回答是没有用于存储时间的内置机制,因此只需使用对您来说最方便的方式。我过去曾使用自己的编码和解析代码(例如“22:00”)使用字符串,因为它们易于阅读和调试,但按照您的建议存储午夜过后的秒数或分钟数并没有错。请记住,您必须自己计算。

    无论你怎么做,你都需要单独的年、月、日、小时、分钟和秒值,以便你可以使用 NSCalendar 的 -dateFromComponents: 方法从 NSDateComponents 构造一个 NSDate。

    正如其他人所说,您不能通过添加小时和分钟到现有的NSDate 来设置时间,因为如果您越过 DST 边界,您将无法获得该值你期望。 (但是,我假设您仍然可以添加日期和月份组件而不必担心 DST)

    【讨论】:

      【解决方案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.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
      

      为什么要为此烦恼一个单独的单元?好吧,我已经编写了足够多的日期格式化代码,知道即时构建 NSCalendarNSDateFormatter 会完全影响性能。

      【讨论】:

        【解决方案3】:

        您可以使用NSDateComponents 仅存储您需要的组件(例如小时和分钟),然后使用NSCalendar dateByAddingComponents:toDate:options: 创建绝对日期引用,当您需要使用序列化组件和基日期。

        【讨论】:

        • 不幸的是,这会在调整时钟的日子返回错误的结果。将 10 小时添加到午夜将返回 2010 年 3 月 14 日上午 11:00 和 2010 年 11 月 7 日上午 9:00。我可能会作弊并将我的时间与凌晨 4:00 或其他时间相关,但那时我会对日历做出愚蠢的假设。 (iPhone 报警错误的可能原因?)
        • 啊,是的,这似乎是 iPhone 警报错误的可能来源。哦,好吧,虽然值得一试。 :-)
        • 是的。当一个非常好的想法不起作用时,这是非常不方便的。但是感谢您的尝试。 :)
        • 当然,没有办法从NSDate 得到NSTimeZone,因为这样可以很容易地处理这个问题......同时,NSCalendarDate,这似乎被绑定到一个时区,是“预定贬值”。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-14
        • 1970-01-01
        • 2017-04-18
        • 1970-01-01
        • 2016-06-10
        相关资源
        最近更新 更多