iPhone - NSDate、NSString 和 Timezones 的奇怪问题

Posted

技术标签:

【中文标题】iPhone - NSDate、NSString 和 Timezones 的奇怪问题【英文标题】:iPhone - Strange problem with NSDate, NSString, and Timezones 【发布时间】:2011-09-24 21:06:30 【问题描述】:

我已经搜索并没有找到像我这样的确切问题,所以这里什么都没有:

我有一个 NSString,其中包含我从 XML 提要中提取的密钥。关键是 24 小时格式的时间(例如 13:30 或 15:00。)我想将 NSString 转换为 NSDate 并根据设备设置的时区将其转换为适当的时区。关键是 Unicode HH:mm (24:00),所以我很好奇为什么这不能正常工作。

我已经得到了一个应该可以工作的基本大纲,但可惜没有。第二个 NSLog(得到 NS 日期)返回 null,最后一个日志返回一个奇怪的数字(准确地说是 1969-12--2147483629 -596:-31:-23 +0000。)我在这里做错了什么?

提前致谢,

    NSString *dateString = [dict objectForKey:@"24hrdate"];
    NSLog(@"NSString Date: %@", dateString);

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    
    [formatter setDateFormat:@"HH:mm"];
    NSDate *sourceDate = [formatter dateFromString:dateString]; 
    NSLog(@"Got NS Date: %@", sourceDate);

    NSTimeZone *sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    NSTimeZone *destinationTimeZone = [NSTimeZone systemTimeZone];

    NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
    NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
    NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;

    NSDate* destinationDate = [[[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate] autorelease];
    NSLog(@"Final Date: %@", destinationDate);

【问题讨论】:

【参考方案1】:

首先要了解日期组件将是01-01-1970,因为它没有提供。如果输入字符串为@"04:00",我假设您希望时间为04:00 GMT。您可以通过设置格式化程序的时区来实现。

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
[formatter setDateFormat:@"HH:mm"];
NSDate *sourceDate = [formatter dateFromString:dateString]; 

【讨论】:

幸运的是,我可以完全控制来自 XML 的时间键,所以如果我只想说 04:00,我可以在我的站点代码中手动执行此操作。有了这些知识,无论如何我可以实现我所追求的吗?也许如果我使用“完整”的日期格式,比如“dd MMM yyyy HH:mm:ss ZZZZ”,我可以过滤掉我不需要的东西,转换成设备的时区,然后只显示我想要的/需要?感谢您的帮助! 根据我从您的评论中了解到的情况,您的 dateString 现在不是 04:00 的格式。如果是这种情况,您必须为 NSDateFormatter 实例提供正确的日期格式,以便它正确解析字符串。这似乎解释了为什么您在第二条日志语句中得到 (null) 此外,给定NSDate 实例,您可以使用NSDateFormatter 实例以任何时区和任何格式打印它。像从字符串中解析日期时一样设置日期格式,并使用setTimeZone: 设置适当的时区,并使用stringFromDate: 方法获取所需的字符串。【参考方案2】:

NSDate 用于表示日期和时间。虽然你可以通过坚持午夜来代表一个日期,但你不能真正用它来代表一天中的某个时间。你可以在 Mac 上伪造这个(它默认为某个合理的日期),但在 ios 上你会得到非常不准确的时间。 (至少,您在某些版本上会这样做。这可能已被修复。)

这里有两种方法:

    您可以根据一天中的时间构建NSDateComponents,并使用dateByAddingComponents 将其添加到您希望时间出现的日期的午夜。这将无法返回您期望的夏令时开始或结束日期的时间。

    您可以使用所需的日期 (NSDate) 和时间(可能是 NSString)构建日期/时间字符串。

- (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;

如果您真的只想要一天中的某个时间,只需将其作为字符串保留即可。

【讨论】:

如果我将其保留为字符串,我可以使用设备的时区进行格式化吗?如果是这样,怎么做?例如,如果我不这样做,有没有办法实现相同的想法并让 GMT 时间根据设备的时区自动更改?我认为 NSDate 是实现这一目标的唯一方法。我很高兴知道情况并非如此。 另外,忘记提及这一点(不敢相信缺乏思想),但我可以完全控制密钥的输出(例如,我可以将其编辑为我喜欢的任何格式,包括“正确的”日期格式,例如“dd MMM yyyy HH:mm:ss ZZZZ。”如果我这样做,它会解决这个问题并允许我简单地过滤掉我不需要的东西吗?如果是这样,我将如何进行过滤把所有不需要的信息都去掉,只保留格林威治标准时间?我上面讨论的第一个选项是理想的,但如果根本不可能,那么这似乎是可行的方法。谢谢! 本地时区:是的。实际上,我相信这就是我的代码的工作方式,因为它更关心一天中的时间。我想要处理的是从当地时间上午 10 点开始的事件,无论时区、夏令时等,都是一天的钟面时间。 加长格式:不,这并不能真正解决您的问题。您仍然会遇到时区和夏令时变化的问题。 这真的归结为一件事,马克:你在乎什么?如果您关心钟面时间,请跟踪它并避免使用 NSDate 和家庭,直到您准备好将该钟面时间固定到特定日期。否则,您将不得不确切地弄清楚您的需求是什么。 :)【参考方案3】:

只是想回帖说我确实设法实现了我最初打算做的事情,没有任何问题。基本上,我必须将字符串转换为 NSDate,通过 NSDateFormatter 运行该 NSDate(设置为时间的原始时区——NSDateFormatter 的 setTimeZone 很有帮助),从中拉出一个 NSDate,然后通过另一个 NSDateFormatter 运行该设备的时区.然后我将生成的 NSDate 转换回 NSString,并将其粘贴在 UILabel 上。

这个解决方案似乎效果很好,因为我已经将我的设备设置为不同的时区,并且时区更改仍然正确。

编辑:这也很重要:

NSString *date…….
date = [date stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

【讨论】:

你应该确保彻底测试这个。我建议编写一个快速命令行工具,在一年中的每一天应用几次并检查结果。希望一切都会好起来的。 :) 我刚刚完成了所有的检查,它可以正常工作。我将源日期格式化程序设置为源的时区,并且与日期本身结合使用时有效。尽管世界不同地区在不同日期开始/结束 DST,但此解决方案(将一天中的时间附加到日期本身)设法避免在您查看未来日期/时间时可能出现的任何问题另一个国家/地区可能已关闭或在 DST 上,而来源不是(导致无论哪种方式都需要一个小时的时间)。再次感谢史蒂文。

以上是关于iPhone - NSDate、NSString 和 Timezones 的奇怪问题的主要内容,如果未能解决你的问题,请参考以下文章

将NSDate转换为NSString

NSDate与 NSString long long类型的相互转化

NSDate和NSString的转换及判定是昨天,今天,明天

将 NSDate 转换为 NSString

NSString 到 NSDate 的转换失败

将NSString转换为NSDate(并再次返回)