UITableView 部分中的 NSDates 不反映来自 UIDatePicker 的日期

Posted

技术标签:

【中文标题】UITableView 部分中的 NSDates 不反映来自 UIDatePicker 的日期【英文标题】:NSDates in a UITableView Section are not reflecting dates from a UIDatePicker 【发布时间】:2014-09-17 12:28:18 【问题描述】:

我有一个带有UITableViewController 的简单应用程序,它由用户填写a 并在不同的视图中从UIDatePicker 中选择一个日期。 UITableViewcells 填充有来自 UITextField 的词,而 UITableView section 标题表示来自 UIDatePicker 的选定日期。

当用户保存在Add Entry View Controller, 中时,它会保存到Core Data 并且NSFetchedResultsController 负责更新UITableView

在我的应用程序的早期版本(2.0 版)中,我遇到了一个错误,即美国时区总是将部分标题显示为UIDatePicker 中所选日期的前一天。对其他国家来说很好。 NSDate 与 UTC 时区一起存储。

我通过将UIDatePicker 设置为不使用版本 2.1.1 的任何时区来实施修复。我认为已经修复了它,但进一步的测试使我发现了其他错误。

我现在正在尝试解决这个问题。

我有一个Transient 属性,用于部分标题如下:

-(NSString *)sectionDateFormatter

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"d MMMM yyyy"];

    dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];

    NSDate *thisDate = self.dates.dateOfEvent;
    NSString *stringDate = [dateFormatter stringFromDate:self.dates.dateOfEvent];
    NSLog(@"[Transaction] The NSDate of self.dates.dateOfEvent = %@", thisDate);
    NSLog(@"[Transaction] The NSDate converted into a string = %@", stringDate);

    return [dateFormatter stringFromDate:self.dates.dateOfEvent];


我的模型是:Transaction EntityDates Entity 有关系,datesOfEventNSDate。我将其转换为字符串,以便以我想要的格式轻松显示为section 标题。

问题

如果我从新安装我的应用程序开始,这会非常有效,并且在 Add Entry View Controller 中,我已将 UIDatePicker 设置为也使用 GMT 时区。

但是,如果我从版本 2.1.1 更新,我的所有 EXISTING* 条目的日期都会在 UITableViewsection 标题中后移一位。我的意思是:

如果我在 2.1.1 版中有 1 个 9 月 17 日的条目、15 日的一个条目和 10 日的一个条目(只是日期的一个例子),当我更新到我正在开发的这个新版本时,所有章节标题都可以追溯到 9 月 16 日、9 月 14 日和 9 月 9 日。如果我单击该条目,UIDatePicker 将显示它应该是的日期(而不是 section 标题中显示的日期)。因此,如果我单击第一个条目,UIDatePicker 会显示第 17 个,但 section 标题会显示第 16 个。

这与时区无关。

我不确定我需要做些什么来确保更新的用户有相同的日期,并且新用户也没有问题。为什么一切都往前追溯?

当我在更新后运行应用程序时,NSLogs 输出显示: [交易] self.dates.dateOfEvent 的 NSDate = 2014-09-16 23:00:00 +0000 [Transaction] NSDate 转成字符串 = 16 September 2014

我不明白为什么dateOfEvent 在 23:00 是第 16 位,而字符串显示的是第 16 位。我不明白为什么日期会向后移动。

*EXISTING:我已经清楚地标记了这一点,因为更新版本中的新条目可以正常工作,但现有条目是它们的日期在章节标题中移回的条目。

请记住,在 2.1.1 版中,我没有在 Transient 属性中为 section 标题使用 GMT 的代码。由于时区的一些奇怪行为,这只是我现在在开发过程中介绍的内容。

更新:显示日期的存储方式

在添加条目的保存方法中,在 2.1.1 版本中,我这样做:

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
//cal.timeZone = [NSTimeZone localTimeZone];

NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                      fromDate:self.datePicker.date];
//[components setTimeZone:[NSTimeZone localTimeZone]];

NSDate *selectedDate = [cal dateFromComponents:components];

// Call the date category and check whether the value exists; if it does return, etc.
Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context];

所以,我已经为日历和 NSDateComponents 输入了 localTimeZone,但是我在发布的 2.1.1 版本中注释掉了代码。

在 2.0 版中,我有:

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                      fromDate:self.datePicker.date];
[components setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *selectedDate = [cal dateFromComponents:components];

// Call the date category and check whether the value exists; if it does return, etc.
Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context];

我将 NSDateComponents 的时区设置为 UTC。

在 2.2 版(我正在开发的版本)中,我正在设置:

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *components = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                                      fromDate:self.datePicker.date];

self.datePicker.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
components.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 

NSDate *selectedDate = [cal dateFromComponents:components];
// Call the date category and check whether the value exists; if it does return, etc.
Date *date = (Date *)[Date occasionWithDate:selectedDate inManagedObjectContext:context];

我将其设置为 GMT 时区。

对此的任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

NSDate 包含一个 UTC 时间点(大致是格林威治标准时间,没有夏令时)。它没有时区信息。如果我们同时看手表,我们可能会看到不同的时间,因为我们在不同的位置。但是,如果我们的应用程序同时调用 [NSDate date],我们会看到相同的结果。

您应该始终未修改地存储 NSDate,并使用 NSTimeZone 和 NSDateFormatter 方法向用户显示时间。如果 NSLog (@"%@", [NSDate date])) 显示出你意想不到的东西,这是绝对正常的,因为它以 UTC 显示时间。通过 NSDateFormatter 向用户显示的文本应该不同。

我想说你需要从你正在做的事情中退后一步,找出你为现有日期存储的确切内容。您是否存储了正确的 NSDate 或者您是否以某种方式针对时区进行了调整?如果您的新代码同时存储不同的 NSDates,那么显然有些事情是行不通的。

【讨论】:

非常感谢@gnasher729 的回复,您的解释非常有道理。我更新了我的问题以反映存储日期的代码。在 2.0 版中,我将其存储为 UTC。在 2.1.1 中,我根本没有设置时区(我有一些奇怪的问题,我认为没有设置时区有效.. 但它在这个问题中引起了这个问题)和 2.2 版(我目前正在工作的版本on),我将其设置为 GMT。问题是从 2.1.1 到 2.2(2.0 到 2.1.1 很好).. 所以没有设置时区,我搞砸了.. 所以看起来向用户显示的日期是什么搞砸了..它作为一个时区设置,并且在升级时与 UIDatePicker 有所不同。此外,重要的是要提到版本 2.1.1(和 2.0)没有在 sectionDateFormatter 瞬态属性中设置任何时区;这是我现在在 2.2 版中添加的代码。 我有一个可行的解决方案,就是回到代码工作的地方,然后在下一个版本中更新 Transaction.m。这有点像黑客,但它可以满足我的要求。感谢您对此的回复,它确实帮助我指明了正确的方向,我非常感谢!

以上是关于UITableView 部分中的 NSDates 不反映来自 UIDatePicker 的日期的主要内容,如果未能解决你的问题,请参考以下文章

快速排序NSDates数组[重复]

比较 NSDates 以检查今天是不是介于两者之间

使用排序函数按 NSDates 对数组进行排序[重复]

比较没有时间分量的 NSDates

UITableView 部分中的背景图像隐藏部分标题

在 UITableView 中的部分之间隐藏部分/空间