【问题标题】:Forcing NSDate to return 24-hour time regardless of locale无论语言环境如何,都强制 NSDate 返回 24 小时制
【发布时间】:2010-11-25 20:39:45
【问题描述】:

我正在尝试将今天的日期以 24 小时时间格式的字符串形式存储在 sqlite 表中,而不管用户的区域设置如何。因为 NSDate 尊重用户的区域设置,所以此代码根据用户的位置返回不同的结果:

NSLog(@"The date is %@", [NSDate date]);

如果他们的语言环境设置为英国(默认为 24​​ 小时制),则返回上述内容 '日期是 2009-09-05 11:17:35',而如果他们在美国,默认 12 小时时间,它返回'日期是 2009-09-05 11:17:凌晨 35 点。

有没有办法在提交到数据库之前自动检测 12 小时制并将其转换为 24 小时制?我正在使用 SQLite 持久对象,因此我需要将日期提供为 NSDate 而不是 NSString。

【问题讨论】:

    标签: iphone


    【解决方案1】:

    更新:最后我选择在使用 NSLocale 操作和存储日期之前覆盖用户的语言环境。所以,而不是这个:

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSSS"];  
    NSString *formattedDateString = [dateFormatter stringFromDate:self];

    我这样做了:

    NSLocale *POSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setLocale:POSIXLocale];  
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSSS"];  
    
    NSString *formattedDateString = [dateFormatter stringFromDate:self];
    

    这具有在存储之前标准化日期格式的效果。对于使用 sqlitepo 的人遇到同样的问题,可以在 NSDate-SQLitePersistence.m 的第 33 和 46 行找到相关的修改代码。

    感谢所有参与的人。

    【讨论】:

    【解决方案2】:

    在我之前的回答中,我认为您在使用 SQLite 持久对象时遇到了问题,但事实并非如此。我认为您只是误解了以下代码实际上在做什么:

    NSLog(@"The date is %@", [NSDate date]);
    

    您在不同语言环境下获得不同日志输出的原因不是因为 NSDate,这是因为 NSDateFormatter 在后台使用将[NSDate date] 的字符串表示形式插入到您的使用%@ 记录字符串。事实上,NSDate 没有“12 小时”或“24 小时”语言环境的概念——它只是一个时间点的表示。

    当您将 NSDate 转换为字符串时,例如在 NSLog 语句中或作为 SQL 查询字符串的一部分时,语言环境就会发挥作用。当你想这样做时,你应该指定自己的显式格式化程序,如下所示:

    NSDateFormatter *formatter = [[NSDateFormatter alloc] initWithDateFormat:@"yyyy-MM-dd HH:mm:ss" allowNaturalLanguage:NO];
    NSLog(@"The date is %s", [formatter stringFromDate:[NSDate date]]);
    [formatter release];
    

    使用上述方法,无论用户的区域设置如何,您都应该得到相同的字符串。

    至于您的 SQL 查询,我是否认为您也在使用 %@ 将日期插入查询字符串?如果是这样,你应该这样做:

    NSString* criteriaTemplate = @"WHERE date(due) BETWEEN date(%d) AND date('now', 'localtime')";
    NSString* criteria = [NSString stringWithFormat: criteriaTemplate, [myNSDate timeIntervalSince1970]];
    NSArray* todayTasks = [Task findByCriteria:criteria];
    

    希望这会有所帮助。

    【讨论】:

    • 谢谢,内森——这帮助我更好地理解了它。它引导我了解 setDateFormat 的工作原理,这帮助我找到了我单独发布的 NSLocale 覆盖。非常感谢。
    【解决方案3】:

    您可以使用 sqlite DATETIME 类型,并实际存储日期而不是字符串。您可以使用NSDateFormatter 定义日期如何显示给用户。

    【讨论】:

    • 非常感谢您的回复,格雷厄姆。现在我致力于使用 SQLite Persistent Objects,它将日期存储为字符串,否则 datetime 将是一个不错的选择。
    【解决方案4】:

    您可以考虑使用swizzling [NSDate date] 调用来始终应用美国语言环境日期格式化程序。

    【讨论】:

    • 谢谢,亚历克斯。我不知道这一点 - 我会仔细看看。感谢您的回复。
    • 以上链接不再有效。有这方面的说明吗?
    【解决方案5】:

    这看起来像是 SQLite 持久对象中的一个错误。该库获取您的 NSDate 实例并将其序列化为格式为@"yyyy-MM-dd HH:mm:ss.SSSS" 的字符串,这意味着时区信息实际上被丢弃了。当日期字符串转换回 NSDate 时,时区被假定为本地时区。这仅适用于所有 NSDate 实例都在本地时区的情况。

    解决此问题的最简单方法是修补NSDate-SQLitePersistence.m 中SQLite 持久对象定义的NSDate(SqlPersistence) 类别,以在序列化和反序列化期间将时区包含在格式字符串中(例如@"yyyy-MM-dd HH:mm:ss.SSSS Z")。但是,正确的解决方法是使用 DATETIME 列而不是基于字符的列来序列化 NSDate。

    当您在 UI 中显示日期时,您可以使用自己的 NSDateFormatter 来定义自己的字符串日期格式。

    【讨论】:

    • 感谢 Nathan 的建议——我实际上是通过使用 sqlite 的 'localtime' 选项进行时间比较来解决时区问题,如下所示: todayTasks = [Task findByCriteria: @"WHERE date(到期) BETWEEN '1980-01-01' AND date('now','localtime') ORDER BY due"];当时间以 24 小时格式存储时(例如 2009-09-05 13:18:48.3970),这很有效,但是在使用 SQLitePO 并以 12 小时格式存储时间时它会中断(例如 2009-09-05 01: 19:23 PM.1400),这让我很难过。
    • SQLite Persistent Objects 将始终将您的 NSDate 属性存储为 24 小时格式的字符串(这就是 "yyyy-MM-dd HH:mm:ss.SSSS" 日期格式中的 "HH"使用——“hh”将是 12 小时时间)。要查询,您应该使用 datetime() 而不是 date() 来包含时间组件。 datetime() 方法理解纪元秒数,因此您应该在传递给 -findByCriteria: 的查询字符串中使用 [NSString stringWithFormat:@"datetime(%d)", [yourNSDate timeIntervalSince1970]]
    • 谢谢,内森。非常感谢您的意见。我使用 date() 因为我不需要比较时间本身 - 只是一天;无论如何,我认为这是最简单的方法。我认为您可能正确地说这是 sqlitepo 的一个错误——我已经从我的 iPhone 中获取了 db 文件,并且 12 小时时间没有转换为 24 小时时间。 12 小时时间语言环境存储为 2009-09-06 01:09:11 PM.8550,而 24 小时时间正确写入为 2009-09-06 13:09:11.8550。
    • 这些 cmets 为问题添加了更多上下文,并表明我可能误解了您的问题/问题。我发布了一个新的答案,应该会有所帮助。
    猜你喜欢
    • 2020-01-24
    • 1970-01-01
    • 2019-09-20
    • 2020-05-22
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多