2009-09-05 75 views
1

我试图将当天日期作为字符串以24小时时间格式存储在sqlite表中,而不管用户的区域设置如何。因为NSDate的荣誉用户的区域设置,此代码返回根据用户的位置不同的结果:强制NSDate返回24小时时间而不管区域设置

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

如果他们的区域设置为英国,在24小时的时间是默认的,上述回报 “的日期是2009-09-05 11:17:35',而如果他们在美国,其中12小时时间是默认时间,则返回'日期为2009-09-05 11:17:35 AM ”。

有没有一种方法可以在将数据提交到数据库之前自动检测并将12小时时间转换为24小时时间?我使用SQLite持久对象,所以我需要提供日期作为NSDate而不是NSString。

回答

1

在我以前的回答中,我认为你遇到了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]; 

希望这会有所帮助。

+0

谢谢,弥敦道 - 这帮助我更好地理解它。它引导我查看setDateFormat如何工作,这帮助我找到了我分别公布的NSLocale覆盖。非常感激。 – Nick 2009-09-06 12:32:46

0

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

+0

非常感谢您的答复,格雷厄姆。现在,我致力于使用SQLite持久对象,它将日期存储为字符串,否则日期时间将是一个不错的选择。 – Nick 2009-09-05 12:27:56

0

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

+0

谢谢,亚历克斯。我不知道这个 - 我会仔细看看。谢谢回复。 – Nick 2009-09-05 12:30:38

+0

上述链接不再有效。有没有这个描述? – 2017-01-13 20:13:25

0

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

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

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

+0

感谢您的建议,内森 - 我实际上通过使用sqlite的'localtime'选项进行时间比较来解决时区问题,如下所示: todayTasks = [任务findByCriteria:@“WHERE date(due)BETWEEN'1980 -01-01'和日期('now','localtime')ORDER BY due“]; 当时间以24小时格式存储时(例如2009-09-05 13:18:48.3970),这很有用,但是在使用SQLitePO并以12小时格式存储时间时会中断(例如2009-09-05 01:19:23 PM.1400),这让我难倒了。 – Nick 2009-09-05 12:25:56

+0

SQLite持久对象将始终将您的NSDate属性存储为24小时格式的字符串(这就是“HH”所使用的“yyyy-MM-dd HH:mm:ss.SSSS”日期格式 - “hh”会12小时)。 要查询,您应该使用datetime()而不是date()来包含时间组件。 datetime()方法理解纪元秒,所以你应该在查询字符串中使用'[NSString stringWithFormat:@“datetime(%d)”,[yourNSDate timeIntervalSince1970]]'传递给-findByCriteria :. – 2009-09-06 09:09:18

+0

谢谢,弥敦道。非常感谢您的意见。我使用date(),因为我不需要比较时间本身 - 仅仅是一天;无论如何,我认为这是最简单的方法。 我想你可能是正确的说明这是一个与sqlitepo的错误 - 我已经从我的iPhone抓取了数据库文件,并且12小时时间没有被转换为24小时时间。 12小时时间区域被存储为2009-09-06 01:09:11 PM.8550,而24小时时间正确写为2009-09-06 13:09:11.8550。 – Nick 2009-09-06 11:12:56

2

更新:最后,我选择在使用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

感谢所有谁插话。

+0

@NickD:原来的代码和你用*取代的代码应该*按照Unicode TR35-4标准生成相同的字符串。看起来你可能遇到了一个bug - http://stackoverflow.com/questions/143075/nsdateformatter-am-i-doing-something-wrong-or-is-this-a-bug – 2009-09-06 13:24:02

+0

好吧,发现了。我搜索了Apple的iPhone开发者论坛,发现有人已经将该问题提交为bug#7037950:https://devforums.apple.com/message/93981#93981 – Nick 2009-09-06 14:44:26

相关问题