ios - UIDatePicker and American/Canadian Timezone messing Up NSFetchRequest filter by Dates -
i have uitabbarcontroller
2 tabs (timeline , dates); both of uitableviewcontrollers
. user adds in information these table views tapping on uinavigationbar
button , filling in information name, event, amount , date. first 3 uitextfields
, date uidatepicker
. information saved core-data
, uitableviewcontroller
gets updated using nsfetchedresultscontrollers
.
the model of coredata transaction entity relationship years entity. have years entity checking dates elsewhere (but more years).
the second tab "dates" tab filters on years date, if user has 5 entries year 2014, show 2014 once , when user clicks on 2014 cell, they'll see entries year = 2014. same applies other years.
problem
i'm in united kingdom locale mac coded app on in locale , i've noticed massive issue.
if change timezone singapore, or asia (somewhere in front of uk in time) on devie, dates tab remains same left as. however, if change new york on phone, or mexico, or canada (basically anytime behind uk), dates tab gets messed each year going down one.
what mean is, if have 2014, 2013, 2012 in dates tab , you're in uk region, if go new york timezone , go app, shows 2013, 2012 , 2011.
what going on?
here's code in "save" method of add entry:
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 year category check whether exists. years *years = (years *)[years matchingyear:selectedyear inmanagedobjectcontext:context]; transaction.years = years;
this calls category on year entity
:
+ (years *)matchingyear:(nsdate *)enteredyear inmanagedobjectcontext:(nsmanagedobjectcontext *)context { years *years = nil; // creating fetch request check whether year exists, calling 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 handle } else if (![matchedyears count]) { // if year count 0 create years = [nsentitydescription insertnewobjectforentityforname:@"years" inmanagedobjectcontext:context]; years.yearofevent = enteredyear; } else { // if year exists, return it. years = [matchedyears lastobject]; } return years; }
my uidatepicker set current date, user cannot pick date in future.
here's fetchresultscontroller code date tab:
- (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; }
in save method, notice i'm setting timezone utc , reason did because if didn't, when went country , changed timezone, add "2014" each entry of 2014 in dates tab wrong. of course causing issues here.
requirement
i require ability keep dates tab same, regardless of timezone i'm in.
key points
there few reasons why format saved in years, etc , can't changed because impacts entire app. uidatepicker set uk locale in storyboard , there few reasons that. however, locale set "default", same issue occurs. timezones in america , canada remove year, 2014 becomes 2013, 2013 becomes 2012, 2012 becomes 2011 in dates tab. that's doesn't make sense me.
any guidance on appreciated!
what going on?
what's going on requirement of keeping dates consistent regardless of timezone not easy you'd like. it's this:
nsdate
has no concept of time zone. it's object wrappernstimeinterval
, measuring time since reference date in utc.- when convert
nsdate
human-readable, time zone applies conversion. has apply, because when ask date correspondingnsdate
, have answer question, the date, where, exactly?
your initial save code sets problem:
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];
if selected date today, final nsdate 410227200 seconds since reference date, in utc corresponds 00:00:00 on 1 january 2014. in time zones east of utc it's 1 or more hours later, still 2014. in time zones west of utc it's 1 or more hours earlier, still 2013. every other detail of problem stems fact.
if care year, best solution store year, not nsdate
. store 2014, 2013, 2012, etc integers rather values implied nsdate
.
incidentally part of question irrelevant:
i'm in united kingdom locale mac coded app on in locale , i've noticed massive issue.
what matters time zone on device running code, not zone on device used compile , link code.
Comments
Post a Comment