代码之家  ›  专栏  ›  技术社区  ›  Jon

NSDateFormatter doesRelativeDateFormatting返回意外的相对日值

  •  1
  • Jon  · 技术社区  · 7 年前

    使用 NSDateFormatter 在macOS 10.13.3上,使用 doesRelativeDateFormatting 设置为 YES . 我发现在格式化程序上使用自定义格式时可能会出现相对日期问题,但我使用的是标准格式 dateStyle & timeStyle 设置。

    例如,使用适当配置的日期格式化程序将纽约市的当前日期与澳大利亚悉尼的日期进行比较,而不使用 doesRelativeDateFormatting ,从日期格式化程序输出的字符串正确显示悉尼的日期为纽约市日期的+1。当我启用时 doesRelativeDateFormatting 在相同的格式化程序上,悉尼的相对日期返回的日期与当天(“今天”)不正确。演示这些结果的代码:

    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NSDate *now = [NSDate date];
            NSDateFormatter *localDateFormatter = [NSDateFormatter new];
            localDateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"America/New_York"];
            localDateFormatter.dateStyle = NSDateFormatterFullStyle;
            localDateFormatter.timeStyle = NSDateFormatterFullStyle;
    
            NSDateFormatter *remoteDateFormatter = [NSDateFormatter new];
            remoteDateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Australia/Sydney"];
            remoteDateFormatter.dateStyle = NSDateFormatterFullStyle;
            remoteDateFormatter.timeStyle = NSDateFormatterFullStyle;
    
            NSLog(@"            Now in NYC: %@", [localDateFormatter stringFromDate:now]);
            NSLog(@"         Now in Sydney: %@", [remoteDateFormatter stringFromDate:now]);
    
            localDateFormatter.doesRelativeDateFormatting = YES;
            remoteDateFormatter.doesRelativeDateFormatting = YES;
    
            NSLog(@"   Relative now in NYC: %@", [localDateFormatter stringFromDate:now]);
            NSLog(@"Relative now in Sydney: %@", [remoteDateFormatter stringFromDate:now]);
        }
    }
    

    输出:

    2018-01-26 14:42:28.478 Untitled[40694:1821879]             Now in NYC: Friday, January 26, 2018 at 2:42:28 PM Eastern Standard Time
    2018-01-26 14:42:28.479 Untitled[40694:1821879]          Now in Sydney: Saturday, January 27, 2018 at 6:42:28 AM Australian Eastern Daylight Time
    2018-01-26 14:42:28.479 Untitled[40694:1821879]    Relative now in NYC: Today at 2:42:28 PM Eastern Standard Time
    2018-01-26 14:42:28.479 Untitled[40694:1821879] Relative now in Sydney: Today at 6:42:28 AM Australian Eastern Daylight Time
    

    这是一个bug吗 NSDateFormatter 还是我在格式化程序的配置中做错了什么?谢谢

    2 回复  |  直到 7 年前
        1
  •  4
  •   rmaddy    7 年前

    您的输出是正确的。给世界上任何地方的任何人打电话,问他们今天是几号,他们都会说“今天”。仅仅因为世界上两个地区一周中的一天不同,并不意味着世界各地都不是“今天”。

    比较两个不同时区的输出会让您感到困惑,这两个时区恰好在代码运行的两天内。

    “相对”日期格式的思想是,输出是给定时区中相对于“现在”的字符串。它与其他时区无关。以日期格式化程序上设置的为准。

        2
  •  1
  •   Jon    7 年前

    当然 @rmaddy 是正确的。有可能 doesRelativeDateFormatting 然后将日期与它自己的时区进行比较,就会报告“今天”,正如它应该报告的那样。

    因此,关键是获取远程时区中的日期,然后使用相对于首选(本地)时区的日期,并使用本地日期格式化程序的相对日期字符串。修改代码以说明两个时区之间的时差,我通过增量计算本地日期偏移量,并使用本地日期格式化程序获取日期字符串(仍然使用远程日期格式化程序获取时间字符串,因为它包含时区名称)。

    这并不完美,因为我没有正确地本地化字符串(“at”是在没有本地化的情况下手动插入的),但这段修改后的代码基本上得到了我想要的结果:

    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NSDate *now = [NSDate date];
    
            NSDateFormatter *localDateFormatter = [NSDateFormatter new];
            localDateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"America/New_York"];
            localDateFormatter.dateStyle = NSDateFormatterFullStyle;
            localDateFormatter.timeStyle = NSDateFormatterFullStyle;
    
            NSDateFormatter *remoteDateFormatter = [NSDateFormatter new];
            remoteDateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"Australia/Sydney"];
            remoteDateFormatter.dateStyle = NSDateFormatterFullStyle;
            remoteDateFormatter.timeStyle = NSDateFormatterFullStyle;
    
            NSLog(@"            Now in NYC: %@", [localDateFormatter stringFromDate:now]);
            NSLog(@"         Now in Sydney: %@", [remoteDateFormatter stringFromDate:now]);
    
            localDateFormatter.doesRelativeDateFormatting = YES;
    
            NSLog(@"   Relative now in NYC: %@", [localDateFormatter stringFromDate:now]);
    
            NSInteger localSecondsFromGMT = [localDateFormatter.timeZone secondsFromGMTForDate:now];
            NSInteger remoteSecondsFromGMT = [remoteDateFormatter.timeZone secondsFromGMTForDate:now];
            NSInteger remoteTimeZoneDelta = (remoteSecondsFromGMT - localSecondsFromGMT);
            NSDate *remoteDate = [now dateByAddingTimeInterval:(NSTimeInterval)remoteTimeZoneDelta];
            localDateFormatter.timeStyle = NSDateFormatterNoStyle;
            remoteDateFormatter.dateStyle = NSDateFormatterNoStyle;
            NSString *remoteRelativeDate = [localDateFormatter stringFromDate:remoteDate];
            NSString *remoteRelativeTime = [remoteDateFormatter stringFromDate:now];
    
            NSLog(@"Relative now in Sydney: %@ at %@", remoteRelativeDate, remoteRelativeTime);
        }
    }
    

    输出:

    2018-01-27 16:08:12.856 Untitled[95771:3146343]             Now in NYC: Saturday, January 27, 2018 at 4:08:12 PM Eastern Standard Time
    2018-01-27 16:08:12.857 Untitled[95771:3146343]          Now in Sydney: Sunday, January 28, 2018 at 8:08:12 AM Australian Eastern Daylight Time
    2018-01-27 16:08:12.857 Untitled[95771:3146343]    Relative now in NYC: Today at 4:08:12 PM Eastern Standard Time
    2018-01-27 16:08:12.857 Untitled[95771:3146343] Relative now in Sydney: Tomorrow at 8:08:12 AM Australian Eastern Daylight Time
    

    这有点不雅观,但它符合我当前的需要。