我有一个UITabBarController
,有两个标签(时间轴和日期);两者都是UITableViewControllers
。用户通过点击UINavigationBar
按钮然后填写姓名,事件,金额和日期等信息,向这些表视图添加信息。前三个是UITextFields
,日期是UIDatePicker
。保存到Core-Data
的信息后,UITableViewController
会使用NSFetchedResultsControllers
进行更新。
CoreData模型是一个与年份实体有关系的交易实体。我还有一个年度实体来检查其他地方的日期(但不仅仅是几年)。
第二个标签是"日期"选项卡仅根据日期中的年份进行过滤,因此如果用户在2014年有5个条目,则仅显示2014年一次,然后当用户点击2014年单元格时,他们将看到所有条目年= 2014年。这同样适用于其他年份。
问题
我在英国的语言环境,但是我编写该应用程序的Mac是在美国的语言环境中,我刚刚发现了一个大问题。
如果您在devie上将时区更改为新加坡或亚洲(及时在英国前面的某个地方),则日期选项卡将与您保留的时区保持一致。但是,如果您通过电话,墨西哥或加拿大(通常在英国之后的任何时间)将其更改为纽约,那么“日期”选项卡会每年减少一次。
我的意思是,如果您在日期标签中有2014年,2013年,2012年,并且您在英国地区,如果您前往纽约时区并进入应用程序,它现在显示2013年,2012年和2011年。
发生了什么事?
这里有" Save"中的一些代码。添加条目的方法:
NSCalendar *yearCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *yearComponent = [yearCal components:NSYearCalendarUnit fromDate:self.datePicker.date];
[yearComponent setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *selectedYear = [yearCal dateFromComponents:yearComponent];
// Calling the year category to check whether it exists.
Years *years = (Years *)[Years matchingYear:selectedYear inManagedObjectContext:context];
transaction.years = years;
这会调用年份Entity
上的类别:
+ (Years *)matchingYear:(NSDate *)enteredYear inManagedObjectContext:(NSManagedObjectContext *)context
{
Years *years = nil;
// Creating a fetch request to check whether the year already exists, calling from the Add/DetailViewController.
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Years"];
request.predicate = [NSPredicate predicateWithFormat:@"yearOfEvent = %@", enteredYear];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"yearOfEvent" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *matchedYears = [context executeFetchRequest:request error:&error];
if (!matchedYears)
{
// No errors to handle
}
else if (![matchedYears count])
{
// If the year count is 0 then create it
years = [NSEntityDescription insertNewObjectForEntityForName:@"Years" inManagedObjectContext:context];
years.yearOfEvent = enteredYear;
}
else
{
// If the year exists, return it.
years = [matchedYears lastObject];
}
return years;
}
我的UIDatePicker设置为当前日期,因此用户将来无法选择日期。
这里是日期标签的fetchResultsController代码:
- (NSFetchedResultsController *)fetchedResultsController
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Years" inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
NSPredicate *d = [NSPredicate predicateWithFormat:@"transactions.years.@count !=0"];
[fetchRequest setPredicate:d];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"yearOfEvent" ascending:NO];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
fetchRequest.fetchBatchSize = 20;
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
在我的保存方法中,我注意到我将时区设置为UTC,我之所以这样做是因为如果我没有,当我去另一个国家并更改我的时区时,它会添加" 2014"对于日期选项卡中2014年的每个条目,这显然是错误的。但这当然会导致一些问题。
要求
我只需要能够保持日期标签相同,无论我在哪个时区。
要点
格式保存的原因有几个原因,因为它会影响整个应用程序。 UIDatePicker在Storyboard中设置为UK Locale,原因如下。但是,即使将语言环境设置为"默认",也会出现同样的问题。美国和加拿大的时区消除了一年,因此2014年成为2013年,2013年成为2012年,2012年成为2011年的日期标签。这对我来说没什么意义。
对此的任何指导都非常感谢!
答案 0 :(得分:2)
发生了什么事?
正在发生的事情是,无论时区如何,保持日期一致的要求并不像您所希望的那么容易。它是这样的:
NSDate
没有时区概念。它基本上是NSTimeInterval
的对象包装器,用于测量自UTC参考日期以来的时间。NSDate
转换为人类可读的内容时,时区适用于转化。必须申请,因为当您要求提供与NSDate
相对应的日期时,您必须回答问题,日期,地点,确切?您的初始保存代码可以解决此问题:
NSCalendar *yearCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *yearComponent = [yearCal components:NSYearCalendarUnit fromDate:self.datePicker.date];
[yearComponent setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
NSDate *selectedYear = [yearCal dateFromComponents:yearComponent];
如果所选日期为今天,则最终NSDate自参考日期起为410227200秒,其中UTC对应于2014年1月1日00:00:00。在UTC以东的时区中,它是一个或多个几个小时后,现在仍然是2014年。在UTC以西的时区早一个小时,这仍然是2013年。问题的每一个细节都源于这个事实。
如果你关心这一年,最好的解决方案是存储年度,而不是NSDate
。将2014,2013,2012等存储为整数,而不是NSDate
暗示的值。
顺便提一下,这部分问题完全不相关:
我在英国的区域设置,但是我编写应用程序的Mac是在美国的区域设置,我刚刚发现了一个大问题。
重要的是运行代码的设备上的时区,而不是用于编译和链接该代码的设备上的区域。