2

I have an application that uses a CLGeocoder to forwardGeocode a placemark from an address string. The CLPlacemark response contains a CLLocation which gives me GPS coordinates.

The only way to create an NSTimeZone seems to be by using the correct Time Zone Name. It is important to point out that I am not using the current location of the device, so [NSTimeZone localTimeZone] will not work for me.

Is there a way to get the timezone name for the CLLocation so that I can create an NSTimeZone correctly?

NOTE: I have been using timeZoneForSecondsFromGMT but that never contains correct DST data, so it is not helpful for me.

Joshua
  • 709
  • 2
  • 10
  • 23

3 Answers3

3

You should use https://github.com/Alterplay/APTimeZones to get NSTimeZone from CLLocation. It also works with CLGeocoder.

Krivoblotsky
  • 1,492
  • 11
  • 17
  • 2
    APTimeZones showed a lot of promise, but unfortunately it has a design problem that could lead to incorrect results. You can [read about that here](https://github.com/Alterplay/APTimeZones/issues/2). – chris Feb 18 '15 at 07:07
1

since iOS9 it should be possible direclty using CLGeocoder as specified here: https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html

Search results for MapKit and CLGeocoder can provide a time zone for the result.

IgnazioC
  • 3,442
  • 2
  • 26
  • 43
0

I found an interesting approach using CLGeocoder, which I put into a category on CLLocation. The interesting part looks like this:

-(void)timeZoneWithBlock:(void (^)(NSTimeZone *timezone))block {        
    [[[CLGeocoder alloc] init] reverseGeocodeLocation:self completionHandler:^(NSArray *placemarks, NSError *error) {           
        NSTimeZone *timezone = nil;

        if (error == nil && [placemarks count] > 0) {               
            CLPlacemark *placeMark = [placemarks firstObject];
            NSString *desc = [placeMark description];

            NSRegularExpression  *regex  = [NSRegularExpression regularExpressionWithPattern:@"identifier = \"([a-z]*\\/[a-z]*_*[a-z]*)\"" options:NSRegularExpressionCaseInsensitive error:nil];
            NSTextCheckingResult *result = [regex firstMatchInString:desc options:0 range:NSMakeRange(0, [desc length])];

            NSString *timezoneString = [desc substringWithRange:[result rangeAtIndex:1]];

            timezone = [NSTimeZone timeZoneWithName:timezoneString];
        }
        block(timezone);            
    }];
}

Usage is like this:

CLLocation *myLocation = ...
[myLocation timeZoneWithBlock:^(NSTimeZone *timezone) {
    if (timezone != nil) {
        // do something with timezone
    } else {
        // error determining timezone
    }
}];

Despite requiring a network connection and working asynchronously, I have found this to be the most reliable way of getting the time zone for a location.

EDITED YEARS LATER

This answer hasn't aged well since the timeZone property was added to CLPlacemark in iOS9 (thank you Ortwin Genz). Here's an updated category method:

-(void)timeZoneWithBlock:(void (^)(NSTimeZone *timezone))block {

    [[[CLGeocoder alloc] init] reverseGeocodeLocation:self completionHandler:^(NSArray *placemarks, NSError *error) {

        NSTimeZone *timeZone = nil;

        if (error == nil && [placemarks count] > 0) {
            CLPlacemark *placeMark = [placemarks firstObject];
            timeZone = placeMark.timeZone;
        }

        block(timeZone);

    }];

}
chris
  • 15,435
  • 8
  • 34
  • 38