0

I've searched and haven't found an exact question like mine, so here goes nothing:

I have a NSString containing a key that I pull from an XML feed. The key is a time in 24-hour format (e.g. 13:30 or 15:00.) I'd like to convert the NSString to an NSDate and have it converted to the appropriate timezone based on the device's set timezone. The key is Unicode HH:mm (24:00), so I'm curious why this does not work as it should.

I've already gotten a basic outline that should work, but alas does not. The 2nd NSLog (Got NS Date) returns null and the final log returns a strange number (1969-12--2147483629 -596:-31:-23 +0000 to be precise.) What am I doing wrong here?

Thanks in advance,

    NSString *dateString = [dict objectForKey:@"24hrdate"];
    NSLog(@"NSString Date: %@", dateString);

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    
    [formatter setDateFormat:@"HH:mm"];
    NSDate *sourceDate = [formatter dateFromString:dateString]; 
    NSLog(@"Got NS Date: %@", sourceDate);

    NSTimeZone *sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    NSTimeZone *destinationTimeZone = [NSTimeZone systemTimeZone];

    NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
    NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
    NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;

    NSDate* destinationDate = [[[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate] autorelease];
    NSLog(@"Final Date: %@", destinationDate);

3 Answers3

0

First of all understand that the date component will be 01-01-1970 because it isn't provided. I am assuming that you want the time to be 04:00 GMT if the input string is @"04:00". That you can achieve by setting the time zone of the formatter.

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];    
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
[formatter setDateFormat:@"HH:mm"];
NSDate *sourceDate = [formatter dateFromString:dateString]; 
Deepak Danduprolu
  • 44,595
  • 12
  • 101
  • 105
  • Fortunately, I have full control over the time key from the XML, so if I want it to just say, 04:00, I can do that manually in my site's code. With this knowledge, is there anyway that I can achieve what I'm after? Maybe if I use a "complete" date format like, say "dd MMM yyyy HH:mm:ss ZZZZ", can I filter out the stuff I don't need, convert to the device's timezone, and just display what I want/need? Thanks for the help! –  Jun 29 '11 at 07:05
  • From what I understand from your comment, your `dateString` isn't of the format `04:00` right now. If that is the case, you must provide the correct date format to the `NSDateFormatter` instance for it to parse the string properly. This seems to explain why you are getting `(null)` in the second log statement. – Deepak Danduprolu Jun 29 '11 at 07:34
  • Additionally, given an `NSDate` instance you can print it in any time zone and any format using an `NSDateFormatter` instance. Set the date format like you do when parsing a date from the string and set the appropriate time zone using `setTimeZone:` and use `stringFromDate:` method to get the string you want. – Deepak Danduprolu Jun 29 '11 at 07:36
0

NSDate is used to represent a date and time. While you can represent just a date by sticking with midnight, you can't really represent just a time of day with it. You can sort of fake this on the Mac (it defaults to some reasonable day), but on iOS you'll get wildly inaccurate times instead. (At least, you do on certain versions. This may have been fixed.)

There's two approaches here:

  1. You can build a NSDateComponents from your time of day and using dateByAddingComponents to add that to midnight on the date you want the time to appear on. This will fail to return the time you expect on a day where daylight savings begins or ends.

  2. You can build a date/time string using the date you want (NSDate) and the time (likely, as a NSString).

- (NSDate *)timeInHours: (NSInteger)hours
                minutes: (NSInteger)minutes
                seconds: (NSInteger)seconds
                 onDate: (NSDate *)inDate;
{
    id timeStr = [[NSMutableString alloc] initWithFormat: @"%02d:%02d:%02d", hours, minutes, seconds];
    id dateStr = [dateWithoutTimeFormatter stringFromDate: inDate];
    id dateTimeStr = [[NSString alloc] initWithFormat: @"%@ %@", dateStr, timeStr];
    [timeStr release];
    id dateTime = [dateWithTimeFormatter dateFromString: dateTimeStr];
    [dateTimeStr release];
    return dateTime;
}

If you really want just the time of day, just keep it around as a string.

Steven Fisher
  • 44,462
  • 20
  • 138
  • 192
  • If I keep it as a string, can I format using the device's timezone? If so, how? Eg if I just leave it be, is there a way to achieve the same idea and have the GMT time automatically change up based on the device's timezone? I thought NSDate was the only way to achieve that. I'd be glad to know that isn't the case. –  Jun 29 '11 at 07:00
  • Also, forgot to mention this (can't believe that lack of thought) but I have complete control over the output of the key (eg I can edit it to whatever format I like, including a "proper" date format like "dd MMM yyyy HH:mm:ss ZZZZ." If I do this, will it fix this issue and allow me to simply filter out what I don't need? If so, how would I go about filtering all of the unneeded information out and just retaining the GMT time? The first option I discussed above would be ideal, but if it simply isn't possible, then this would seem the way to go. Thanks! –  Jun 29 '11 at 07:10
  • Local time zone: Yes. I believe that's how my code works, actually, because it was more concerned with time of day. What I wanted to handle was events that started at 10AM local, clock-face time on a day regardless of time zone, daylight savings time, etc. – Steven Fisher Jun 29 '11 at 17:41
  • Longer format: No, that won't really fix your problem. You're still going to have problems with time zones and daylight savings changes. – Steven Fisher Jun 29 '11 at 17:41
  • This really comes down to one thing, Marc: What do you care about? If you care about the clock-face time, track that and avoid using NSDate and family until you're ready to pin that clock-face time to a specific date. Otherwise, you're going to have to figure out exactly what your needs are. :) – Steven Fisher Jun 29 '11 at 17:42
  • Hey Steven, thanks for the help and different angle. I spent some more of today thoroughly analyzing the problem, and finally came up with a proper solution that isn't too convoluted. I posted what I did as an answer if you or anyone else is curious. Thanks again! –  Jun 30 '11 at 07:33
0

Just wanted to post back that I did manage to achieve what I initially set out to do without any issues. Basically, I had to convert the string to NSDate, run that NSDate through a NSDateFormatter (set to the time's original timezone--NSDateFormatter's setTimeZone was helpful), pull an NSDate out of that, and then run that through another NSDateFormatter for the device's timezone. I then converted the resulting NSDate back to NSString, and stuck it on a UILabel.

This solution seems to have worked quite well, as I've set my devices to various timezones, and the timezone change is still correct.

EDIT: this was important to included, too:

NSString *date…….
date = [date stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  • You should make sure to thoroughly test this. I suggest writing a quick command line tool to apply a few times to every day in a year and check the results. Hopefully, everything will be fine. :) – Steven Fisher Jun 30 '11 at 16:57
  • I just finished examining everything, and it works as it should. I have the source date formatter set to the source's timezone, and that works when combined with the date itself. Although different parts of the world begin/end DST on different dates, this solution (appending the time of day to the date itself) manages to avoid any possible problems that might arise if you're looking at a date/time in the future when another country might be off or on DST, and the source isn't (resulting in the time being an hour off either way). Thanks again, Steven. –  Jul 01 '11 at 01:47