Search code examples
iosobjective-cnsdatenscalendarnstimezone

Capture current time but reset the minutes to zero without dealing with timezone


In my core database, when I update information from the server, I capture the current time and save that in a core database field. I know the server updates information at the top of the hour, so I want to rate limit the requests to the server to once an hour, but also grab the most recent data from the server.

For example, say on the hour the server updates its data.

On my app, I can refresh at any point in time. Say I grabbed data at 7:55am. While I want to limit the frequency of update requests from the app to once an hour, I also want to have the latest data as soon as its available. So instead of storing a timestamp of 7:55, I would want to store 7:00am, so if I refresh in 10 minutes, I would at least get the next update.

NSDate *oldDate = [NSDate date];
unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay;
NSCalendar *calendar = [NSCalendar currentCalendar];
//calendar.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
NSDateComponents *comps = [calendar components:unitFlags fromDate:oldDate];
comps.minute = 00;
comps.second = 00;
NSDate *newDate = [calendar dateFromComponents:comps];

return newDate;

The above code does not work because once I call NSCalendar, timezones are involved. Is there a way to do this without involving NSCalendar?


Solution

  • Truncating a date/time to the full hour necessarily requires the specification of a time zone. As an example, Indian Standard Time is GMT+05.30, so "7.55am GMT" is the same as "1.25pm IST".

    If the server updates its data at every full GMT hour, the next update would be at "8.00am GMT". But if the server resides in India and updates its data at every full IST hour, the next update would be "2.00pm IST" which is "7.30am GMT".

    So to compute the "full hour" you have to know which time zone the server uses. If the server update is done every full GMT hour, then adding

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

    would be the right thing.

    Btw., a slightly shorter way to compute the start of the current hour is using the rangeOfUnit:... method of NSCalendar:

    NSDate *oldDate = [NSDate date];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    calendar.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 
    NSDate *newDate;
    [calendar rangeOfUnit:NSHourCalendarUnit startDate:&newDate interval:NULL forDate:oldDate];
    return newDate;