objective c - Calculate the next event from now given an NSDate in the past and a repeat interval -
how can calculate first date later date in past repeating interval? example:
// date in past nsdate *pastdate = [nsdate my_datewithstring:@"11/09/2001"]; // time interval nstimeinterval repeatinterval = 14 * 24 * 60 * 60; // 2 weeks // current date nsdate *now = [nsdate date]; // 23/07/2015 // start calculating next date -> nsdate *nextdate = /* interval added past date */ // result later now? // no? calculate again // abracadabra nslog(@"nexdate = %@",nextdate); // 28/07/2015
i don't want use iterations. i'm concerned calculating case start date 1 year in past , repeat interval of day.
here solution, has iterations.
nsdatecomponents *twoweeksdatecomponents = [nsdatecomponents new]; twoweeksdatecomponents.weekofmonth = 2; nsdate *date = self.picker.date; nscalendar *calendar = [nscalendar currentcalendar]; nsdate *now = [nsdate date]; nsdate *nextdate = date; nscomparisonresult result = [nextdate compare:now]; while (result == nsorderedascending) { nextdate = [calendar datebyaddingcomponents:ktwoweeksdatecomponents todate:nextdate options:nscalendarmatchnexttime]; result = [nextdate compare:now]; } nslog(@"nexdate = %@",nextdate); // 28/07/2015
you can indeed without iteration, using little arithmetic instead. you're looking nearest multiple of factor f strictly greater value n. it's bit more complicated being calendrical calculation, still arithmetic (and nscalendar
of course heavy lifting -- e.g., leap years).
nsdate * pastdate = ...; nsdate * = [nsdate date];
get repeat interval user , construct nsdatecomponents
representing it:
nscalendarunit repeatunit = nscalendarunitweekofyear; nsuinteger repeatinterval = 2; nsdatecomponents * repeatcomps = [nsdatecomponents new]; [repeatcomps setvalue:repeatinterval forcomponent:repeatunit];
given repeat unit, find amount of unit occurs between 2 dates, date components object:
nscalendar * cal = [nscalendar currentcalendar]; nsdatecomponents * deltacomps = [cal components:repeatunit fromdate:pastdate todate:now options:0]; nsinteger deltaval = [deltacomps valueforcomponent:repeatunit];
now comes arithmetical bit. round delta down nearest multiple of repeat interval. adding rounded value (using appropriate unit) produce date equal or earlier now.
now, jawboxer has pointed out, repeatunit
of nscalendarunitmonth
, unexpected results if calculate date using value , afterwards add 1 more repeat interval (as original version of answer did). instead, add 1 number of repeats immediately; calendar correctly handles month increments.
nsinteger repeatsjustpastnow = 1 + deltaval - (deltaval % repeatinterval); nsdatecomponents * tonowcomps = [nsdatecomponents new]; [tonowcomps setvalue:repeatsjustpastnow forcomponent:repeatunit]; nsdate * nextdate; nextdate = [cal datebyaddingcomponents:tonowcomps todate:pastdate options:0];
jawboxer's swift version of corrected code on github.
Comments
Post a Comment