问题
I'm having problems converting a time string to a different timeZone.
This is a string example as the one I retrieve from a server: @"5/14/2013 4:19am"
I know the timeZone is America/New_York and I want to convert it to my local timeZone: Europe/Rome.
Here is the code I wrote to test it:
-(void) convertTimeZone
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone=[NSTimeZone timeZoneWithAbbreviation:@"GMT"];
dateFormatter.dateFormat=@"MM/dd/yyyy HH:mma";
NSString *sourceDateString = @"5/14/2013 4:19am";
NSTimeZone *sourceTimeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];
NSTimeZone *destinationTimeZone = [NSTimeZone localTimeZone];
NSInteger sourceGMToffset = sourceTimeZone.secondsFromGMT;
NSInteger destinationGMToffset = destinationTimeZone.secondsFromGMT;
NSInteger interval = destinationGMToffset-sourceGMToffset;
NSLog(@"DateFormatter TimeZone: %@", dateFormatter.timeZone);
NSLog(@"Source TimeZone: %@", sourceTimeZone);
NSLog(@"Destination TimeZone: %@", destinationTimeZone);
NSLog(@"sourceOffset: %u destinationOffset: %u interval: %u", sourceGMToffset, destinationGMToffset, interval);
NSLog(@"----------------------------------------------------------------------------------------------------");
NSLog(@"sourceDateString : %@", sourceDateString);
//Convert from string to date
NSDate *dateObject = [dateFormatter dateFromString:sourceDateString];
NSLog(@"From string to date: %@", dateObject);
//Now back from date to string
NSLog(@"From date to string: %@", [dateFormatter stringFromDate:dateObject]);
//Convert from sourceTimeZone to destinationTimeZone
NSDate *newDate = [[NSDate alloc] initWithTimeInterval: interval sinceDate:dateObject];
NSLog(@"destinationDateString: %@", [dateFormatter stringFromDate: newDate]);
}
output:
DateFormatter TimeZone: GMT (GMT) offset 0
Source TimeZone: America/New_York (GMT-04:00) offset -14400 (Daylight)
Destination TimeZone: Local Time Zone (Europe/Rome (CEST) offset 7200 (Daylight))
sourceOffset: 4294952896 destinationOffset: 7200 interval: 21600
sourceDateString : 5/14/2013 4:19am
From string to date: 2013-05-14 00:19:00 +0000
From date to string: 05/14/2013 00:19AM
destinationDateString: 05/14/2013 06:19AM
I'm getting mad!!!!
If the original date is "5/14/2013 4:19am" WHY the date formatter changes it to "05/14/2013 00:19AM" ????????? If it had saved correctly it to "05/14/2013 04:19AM +0000" the conversion would be perfect (6 hours between the two TimeZones)!!!
Any hint?
Thanks
Nicola
EDIT
By setting these parameters as suggested by lithu-t-v:
dateFormatter.timeZone=[NSTimeZone timeZoneWithAbbreviation:@"GMT"];
NSString *sourceDateString = @"5/14/2013 4:19am -0400";
It seems to work but it doesn't.
I say "it seems" because:
sourceDateString: 5/14/2013 04:19am -0400
From string to date: 2013-05-13 04:19:00 +0000 (OK)
From date to string: 05/14/2013 04:19 (OK)
destinationDateString: 05/14/2013 10:19 (CORRECT)
is correct BUT if I try with a late pm hour:
sourceDateString: 5/14/2013 10:19pm -0400
From string to date: 2013-05-14 16:19:00 +0000 (WRONG)
From date to string: 05/14/2013 16:19
destinationDateString: 05/14/2013 22:19 (WRONG!)
The correct result should be: 05/15/2013 04:19AM
回答1:
The +0000 component defines the date with the time zone and provide with actual time .A NSDate object include this part also.since that part is missing the time difference comes,with respect to local time zone
Here you ceated the timezone but is not set to the datefromatter.Set timezone to the dateformatter and try it
Append +0000 to the string and do the remaining.It will work
回答2:
Thank you all for all your hints! After a lot of trials I ended writing a function that uses DateComponent:
-(NSString*) convertToLocalTimeZoneDate: (NSString*) sourceDate
Time: (NSString*) sourceTime
{
//Date and time parsing
//Expected: NSString *sourceDate = @"5/13/2013";
//Expected: NSString *sourceTime = @"04:19am";
NSArray *dateArray = [sourceDate componentsSeparatedByString:@"/"];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
dateComps.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
dateComps.year = [[dateArray objectAtIndex:2] integerValue];
dateComps.month = [[dateArray objectAtIndex:0] integerValue];
dateComps.day = [[dateArray objectAtIndex:1] integerValue];
NSString *timeInDay = [sourceTime substringFromIndex:5];
if ([[timeInDay uppercaseString] isEqualToString:@"PM"]){
dateComps.hour = 12 + [[sourceTime substringWithRange:NSMakeRange(0, 2)] integerValue];
} else {
dateComps.hour = [[sourceTime substringWithRange:NSMakeRange(0, 2)] integerValue];
}
dateComps.minute = [[sourceTime substringWithRange:NSMakeRange(3, 2)] integerValue];
dateComps.timeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];
NSLog(@"Original Date Time: %@ %@", sourceDate, sourceTime);
NSLog(@"GMT Date Time: %@", dateComps.date);
//Return a string with the local date and time
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [NSLocale currentLocale];
dateFormatter.dateStyle = NSDateFormatterShortStyle;
dateFormatter.timeStyle = NSDateFormatterLongStyle;
return[dateFormatter stringFromDate:dateComps.date];
}
It returns the right output:
Original Date Time: 5/13/2013 04:19am (I know it is America/New_York)
GMT Date Time: 2013-05-13 08:19:00 +0000 (OK)
Output: 13/05/13 10:19:00 CEST
回答3:
This is what you want:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat=@"dd/MM/yyyy h:mma"; // Note: lower case h
NSString *sourceDateString = @"14/5/2013 5:19am"; // in New Yourk
NSTimeZone *sourceTimeZone = [[NSTimeZone alloc] initWithName:@"America/New_York"];
NSTimeZone *destinationTimeZone = [NSTimeZone localTimeZone];
dateFormatter.timeZone = sourceTimeZone;
NSLog(@"DateFormatter TimeZone: %@", dateFormatter.timeZone);
NSLog(@"Source TimeZone: %@", sourceTimeZone);
NSLog(@"Destination TimeZone: %@", destinationTimeZone);
NSLog(@"---------------------------------------");
NSLog(@"sourceDateString : %@", sourceDateString);
//Convert from string to date
NSDate *dateObject = [dateFormatter dateFromString:sourceDateString];
NSLog(@"From string to date should be in GMT: %@", dateObject);
//Convert from sourceTimeZone to destinationTimeZone
dateFormatter.timeZone = destinationTimeZone;
NSLog(@"Hopefully works: %@", [dateFormatter stringFromDate: dateObject]);
Output:
Test Case '-[TestOrderedList testFoo]' started.
2013-05-15 11:44:04.263 LogicSim[43238:303] DateFormatter TimeZone: America/New_York (EDT) offset -14400 (Daylight)
2013-05-15 11:44:04.264 LogicSim[43238:303] Source TimeZone: America/New_York (EDT) offset -14400 (Daylight)
2013-05-15 11:44:04.264 LogicSim[43238:303] Destination TimeZone: Local Time Zone (Europe/London (BST) offset 3600 (Daylight))
2013-05-15 11:44:04.264 LogicSim[43238:303] ---------------------------------------
2013-05-15 11:44:04.264 LogicSim[43238:303] sourceDateString : 14/5/2013 5:19am
2013-05-15 11:44:04.265 LogicSim[43238:303] From string to date should be in GMT: 2013-05-14 09:19:00 +0000
2013-05-15 11:44:04.265 LogicSim[43238:303] Hopefully works: 14/05/2013 10:19AM
Test Case '-[TestOrderedList testFoo]' passed (0.002 seconds).
The first mistake you made was in the date format specification HH
is the time in 24 hour format. When used with the am/pm specifier, this seems to always parse the hour as 0. Your test data coincidentally had an hour of 4 which is the same as the offset between GMT and New York, leading you to assume it was just getting the offset wrong. I changed the hour specifier to h
to get 12 hour time. I also changed the test time, to make it less confusing.
The second mistake was to mess about with the NSDate object, that way lies insanity. NSDates are always in GMT. Do not add or subtract time intervals to correct for time zones, just set the time zone in the date formatter appropriately. So my code sets the time zone to New York and parses the date. It then sets the time zone to local time (I'm in the UK on BST) and stringifies the date. Job done.
来源:https://stackoverflow.com/questions/16539638/objective-c-conversion-between-timezones