【问题标题】:How do I break down an NSTimeInterval into year, months, days, hours, minutes and seconds on iPhone?如何在 iPhone 上将 NSTimeInterval 分解为年、月、日、小时、分钟和秒?
【发布时间】:2010-11-17 06:57:56
【问题描述】:

我有一个跨年的时间间隔,我想要从年到秒的所有时间组件。

我的第一个想法是将时间间隔除以一年中的秒数,从运行总秒数中减去,再除以一个月中的秒数,从运行总和中减去,等等。

这似乎令人费解,我读到,每当您做一些看起来令人费解的事情时,可能有一个内置方法。

有吗?

我将 Alex 的第二种方法集成到我的代码中。

它在我的界面中由 UIDatePicker 调用的方法中。

NSDate *now = [NSDate date];
NSDate *then = self.datePicker.date;
NSTimeInterval howLong = [now timeIntervalSinceDate:then];

NSDate *date = [NSDate dateWithTimeIntervalSince1970:howLong];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
int year, month, day, hour, minute, sec;

sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &sec);
year -= 1970;

NSLog(@"%d years\n%d months\n%d days\n%d hours\n%d minutes\n%d seconds", year, month, day, hour, minute, sec);

当我将日期选择器设置为过去 1 年零 1 天的日期时,我得到:

1 年 1 个月 1 天 16 小时 0 分 20 秒

这是 1 个月零 16 小时的休息时间。如果我将日期选择器设置为过去 1 天,我会减少相同的数量。

更新:我有一个应用程序可以根据您的生日(从 UIDatePicker 设置)计算您的年龄(以岁为单位),但它经常关闭。这证明有一个不准确的地方,但我不知道它来自哪里,你能吗?

【问题讨论】:

  • 如果您将日期选择器设置为一天前,您会延迟 1 个月零 16 小时吗?
  • 是的,休息 1 个月 16 小时。
  • 如果结果始终是 1 个月零 16 小时,无论您选择什么值,您要么从变量中减去该值,使用移位,要么您需要评估该错误的来源。我的猜测是,如果您的时间间隔总是不正确,那么您的时间间隔就有问题。

标签: iphone cocoa time nstimeinterval


【解决方案1】:

简要说明

  1. 只是另一种完成 JBRWilkinson 答案的方法,但添加了一些代码。它还可以为 Alex Reynolds 的评论提供解决方案。

  2. 使用 NSCalendar 方法:

    • (NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts

    • “作为使用指定组件的 NSDateComponents 对象返回两个提供日期之间的差异”。 (来自 API 文档)。

  3. 创建 2 个 NSDate,其区别在于您要分解的 NSTimeInterval。 (如果您的 NSTimeInterval 来自比较 2 个 NSDate,则无需执行此步骤,甚至不需要 NSTimeInterval,只需将日期应用于 NSCalendar 方法即可)。

  4. 从 NSDateComponents 获取您的报价

示例代码

// The time interval 
NSTimeInterval theTimeInterval = ...;

// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];

// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1]; 

// Get conversion to months, days, hours, minutes
NSCalendarUnit unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;

NSDateComponents *breakdownInfo = [sysCalendar components:unitFlags fromDate:date1  toDate:date2  options:0];
NSLog(@"Break down: %i min : %i hours : %i days : %i months", [breakdownInfo minute], [breakdownInfo hour], [breakdownInfo day], [breakdownInfo month]);

【讨论】:

  • 此方法存在跨越夏令时变化的问题,你会直接遇到1小时的问题。
  • NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit 在 IOS8 中已弃用,请改用 NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitDay | NSCalendarUnitMonth
【解决方案2】:

这个代码知道夏令时和其他可能的讨厌的事情。

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components: (NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit )
                                                    fromDate:startDate
                                                      toDate:[NSDate date]
                                                     options:0];


NSLog(@"%ld", [components year]);
NSLog(@"%ld", [components month]);
NSLog(@"%ld", [components day]);
NSLog(@"%ld", [components hour]);
NSLog(@"%ld", [components minute]);
NSLog(@"%ld", [components second]);

【讨论】:

    【解决方案3】:

    iOS8及以上可以使用NSDateComponentsFormatter

    它具有将时间差转换为用户友好格式字符串的方法。

    NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
    formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
    
    NSLog(@"%@", [formatter stringFromTimeInterval:1623452]);
    

    这给出了输出 - 2 周、4 天、18 小时、57 分钟、32 秒

    【讨论】:

      【解决方案4】:

      使用+dateWithIntervalSince1970 将您的时间间隔转换为NSDate,使用NSCalendar 的-componentsFromDate 方法从中取出日期组件。

      SDK Reference

      【讨论】:

      • +1。对 OP 来说更详细一点,您无法将时间间隔精确地转换为这些组件,您必须知道从哪里开始(因此是 dateWithIntervalFrom1970),因为例如,如果您在 2 月,则 29 天是一个月1 日(当然,双六岁除外),但如果你是 1 月 1 日,则不是……
      【解决方案5】:

      这对我有用:

          float *lenghInSeconds = 2345.234513;
          NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:lenghInSeconds];
          NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
      
      
          [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
      
          [formatter setDateFormat:@"HH:mm:ss"];
          NSLog(@"%@", [formatter stringFromDate:date]); 
          [formatter release];
      

      这里的主要区别是您需要调整时区。

      【讨论】:

        【解决方案6】:

        或者有我的类方法。它不能处理年份,但可以很容易地添加它,尽管它更适合像天、小时和分钟这样的小时间间隔。它考虑了复数形式,只显示需要的内容:

        +(NSString *)TimeRemainingUntilDate:(NSDate *)date {
        
            NSTimeInterval interval = [date timeIntervalSinceNow];
            NSString * timeRemaining = nil;
        
            if (interval > 0) {
        
                div_t d = div(interval, 86400);
                int day = d.quot;
                div_t h = div(d.rem, 3600);
                int hour = h.quot;
                div_t m = div(h.rem, 60);
                int min = m.quot;
        
                NSString * nbday = nil;
                if(day > 1)
                    nbday = @"days";
                else if(day == 1)
                    nbday = @"day";
                else
                    nbday = @"";
                NSString * nbhour = nil;
                if(hour > 1)
                    nbhour = @"hours";
                else if (hour == 1)
                    nbhour = @"hour";
                else
                    nbhour = @"";
                NSString * nbmin = nil;
                if(min > 1)
                    nbmin = @"mins";
                else
                    nbmin = @"min";
        
                timeRemaining = [NSString stringWithFormat:@"%@%@ %@%@ %@%@",day ? [NSNumber numberWithInt:day] : @"",nbday,hour ? [NSNumber numberWithInt:hour] : @"",nbhour,min ? [NSNumber numberWithInt:min] : @"00",nbmin];
            }
            else
                timeRemaining = @"Over";
        
            return timeRemaining;
        }
        

        【讨论】:

          【解决方案7】:
          NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
          
          // format: YYYY-MM-DD HH:MM:SS ±HHMM
          NSString *dateStr = [date description];
          NSRange range;
          
          // year
          range.location = 0;
          range.length = 4;
          NSString *yearStr = [dateStr substringWithRange:range];
          int year = [yearStr intValue] - 1970;
          
          // month
          range.location = 5;
          range.length = 2;
          NSString *monthStr = [dateStr substringWithRange:range];
          int month = [monthStr intValue];
          
          // day, etc.
          ...
          

          【讨论】:

            【解决方案8】:
            - (NSString *)convertTimeFromSeconds:(NSString *)seconds {
            
                // Return variable.
                NSString *result = @"";
            
                // Int variables for calculation.
                int secs = [seconds intValue];
                int tempHour    = 0;
                int tempMinute  = 0;
                int tempSecond  = 0;
            
                NSString *hour      = @"";
                NSString *minute    = @"";
                NSString *second    = @"";
            
                // Convert the seconds to hours, minutes and seconds.
                tempHour    = secs / 3600;
                tempMinute  = secs / 60 - tempHour * 60;
                tempSecond  = secs - (tempHour * 3600 + tempMinute * 60);
            
                hour    = [[NSNumber numberWithInt:tempHour] stringValue];
                minute  = [[NSNumber numberWithInt:tempMinute] stringValue];
                second  = [[NSNumber numberWithInt:tempSecond] stringValue];
            
                // Make time look like 00:00:00 and not 0:0:0
                if (tempHour < 10) {
                    hour = [@"0" stringByAppendingString:hour];
                } 
            
                if (tempMinute < 10) {
                    minute = [@"0" stringByAppendingString:minute];
                }
            
                if (tempSecond < 10) {
                    second = [@"0" stringByAppendingString:second];
                }
            
                if (tempHour == 0) {
            
                    NSLog(@"Result of Time Conversion: %@:%@", minute, second);
                    result = [NSString stringWithFormat:@"%@:%@", minute, second];
            
                } else {
            
                    NSLog(@"Result of Time Conversion: %@:%@:%@", hour, minute, second); 
                    result = [NSString stringWithFormat:@"%@:%@:%@",hour, minute, second];
            
                }
            
                return result;
            
            }
            

            【讨论】:

              【解决方案9】:

              这是另一种可能性,更简洁:

              NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
              NSString *dateStr = [date description];
              const char *dateStrPtr = [dateStr UTF8String];
              
              // format: YYYY-MM-DD HH:MM:SS ±HHMM
              int year, month, day, hour, minutes, seconds;
              sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minutes, &seconds);
              year -= 1970;
              

              【讨论】:

              • 对于 1 秒(前一秒)的时间间隔,返回“年 -1,月 12,日 31,小时 16,分钟 0,秒 1”。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-08-24
              • 2011-06-10
              • 2021-08-14
              • 1970-01-01
              • 1970-01-01
              • 2017-11-22
              • 2012-05-25
              相关资源
              最近更新 更多