NSDateFormatter not behaving properly when convert

2020-08-01 05:52发布

问题:

I'm making an app that supports conversion of dates from the Buddhist calendar to Gregorian (Note: The "General > International > Calendar" settings of the device I'm testing on is "Buddhist".). However, I can't figure out why the NSDateFormatter doesn't parse my dates properly. Here's my code:

NSDate *now = [NSDate date];

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.calendar = gregorianCalendar;
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";

NSString *formattedDate = [formatter stringFromDate:now];
NSDate *boomDate = [formatter dateFromString:formattedDate];

NSLog(@"now: %@, formattedDate (as string) > %@, boomDate (as date) > %@", now, formattedDate, boomDate);

Xcode's log says:

now: 2556-05-23 07:11:03 +0000, formattedDate (as string) > 2013-05-23 15:11:03 +0800, boomDate (as date) > 2556-05-23 07:11:03 +0000

When I'm converting the formattedDate (which is an NSString) to an NSDate, why does my NSDateFormatter parse it according to the Buddhist calendar format even if I set it's properties properly (especially the formatter.calendar). I need my formattedDate converted as an NSDate with the Gregorian calendar format. Based on its logic, I'm expecting the NSDateFormatter to give me a date with the Gregorian format but it doesn't.

Basically, I need an NSDate following the Gregorian format from a Buddhist NSDate.

Any ideas?

回答1:

NSDate is just an object wrapper for a double value indicating the offset from the reference date. It does not contain information about calendars or timezones. It's just a point in time.

What we as humans decide to call this point in time depends on our calendar and timezone. An NSDate object has no meaning without a calendar and timezone.

When you're printing a date object using NSLog, the -description method on your date object gets called, and the -description method formats the string using your device's locale. That's why the boomDate is shown with buddhist calendar properties; your buddhist locale uses a buddhist calendar.

The now and boomDate variables are equal (try calling [now isEqualToDate:boomDate]).

You can tell that the conversion to gregorian succeeded, because the formattedDate shows the date as it would be in the gregorian calendar.