NSDateFormatter doesRelativeDateFormatting returns 意外的相对日期值

NSDateFormatter doesRelativeDateFormatting returns unexpected relative day value

在 macOS 10.13.3 上使用 NSDateFormatter,将 doesRelativeDateFormatting 设置为 YES 时,我得到的值不正确。我发现在格式化程序上使用自定义格式时可能存在相对日期问题,但我使用的是标准 dateStyle & timeStyle 设置。

例如,在不使用 doesRelativeDateFormatting 的情况下使用适当配置的日期格式化程序将纽约市的当前日期与澳大利亚悉尼的日期进行比较,日期格式化程序的字符串输出正确显示了悉尼的日期从纽约市的那一天起就+1。当我在相同的格式化程序上启用 doesRelativeDateFormatting 时,悉尼的相对日期 returns 错误地为同一天 ('Today')。演示这些结果的代码:

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

这是 NSDateFormatter 中的错误还是我在格式化程序配置中做错了什么?谢谢。

你的输出是正确的。给世界上任何地方 phone 上的任何人打电话,问他们今天是几号,他们都会说 "today"。仅仅因为它在世界的两个地方是不同的星期几并不意味着它不是 "today" 在任何地方。

当代码为 运行.

时,比较恰好在两个不同日期的两个不同时区的输出,您会让自己感到困惑

"relative" 日期格式的想法是输出是相对于给定时区的 "now" 的字符串。它与任何其他时区无关。在日期格式器上设置哪个。

当然,@rmaddy是正确的。启用 doesRelativeDateFormatting 然后将日期与其自己的时区进行比较将报告 'Today',因为它应该。

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

这并不完美,因为我没有正确地本地化字符串(“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

这有点不雅,但可以满足我当前的需求。