NSDateFormatter - не учитывает системные настройки 12/24 часа (am/pm) при некоторых обстоятельствах
Я хочу вывести дату (имеющую относительные даты, например, сегодня, вчера и т.д.) и время (в соответствии с настройкой 12/24 часов на устройстве iOS).
- Сегодня 5:48 вечера (когда в 12-часовом режиме); и
- Сегодня 17:48 (в режиме 24 часа)
Настройка NSFormatter как это (и использование stringFromDate:) не работает:
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale: [NSLocale autoupdatingCurrentLocale]];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle]; // doesn't respect am/pm setting on iOS device (grrr!)
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setDoesRelativeDateFormatting:YES]; // but does get relative dates
Это дает относительные даты, но по умолчанию используется значение 12/24 для локали, например. 12 часов для США и 24 часа для Великобритании. (Почему Apple думает, что британские люди любят круглосуточные часы, я не знаю...)
Работа, которую я использовал, использует два NSDateFormatters, один для даты и один для времени. Похоже, что при настройке NSDateFormatter с DateStyle NSDateFormatterNoStyle и timeStyle из NSDateFormatterShortStyle, он соблюдает настройку 12/24 часа. (Так что только когда у вас установлены стили даты и времени, есть проблемы.)
Я включил свою работу ниже, если у кого-то другая проблема. Есть ли более простой способ сделать это? Работа вокруг кажется несколько неудобной, и неясно, насколько я уверен, что она будет продолжать работать в будущих версиях iOS.
Работайте
- (NSString*) humanRelativeDateAndTimeAlt: (NSDate*) date;
{
NSDateFormatter* relativeDateFormatter = [[NSDateFormatter alloc] init];
[relativeDateFormatter setLocale: [NSLocale autoupdatingCurrentLocale]];
[relativeDateFormatter setTimeStyle:NSDateFormatterNoStyle]; // no time for this formatter
[relativeDateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setDoesRelativeDateFormatting:YES]; // relative dates
NSString* datePart = [[self relativeDateFormatter] stringFromDate:date];
NSDateFormatter* timeDateFormatter = [[NSDateFormatter alloc] init];
[timeDateFormatter setLocale:[NSLocale autoupdatingCurrentLocale]];
[timeDateFormatter setDateStyle: NSDateFormatterNoStyle]; // no date for this formatter
[timeDateFormatter setTimeStyle: NSDateFormatterShortStyle]; // does respect 12/24 hour setting
NSString* timePart = [timeDateFormatter stringFromDate:date];
int skipZero = 0; // extra code to remove leading zero if present
if ([[timePart substringToIndex:1] isEqualToString:@"0"]) skipZero = 1;
[relativeDateFormater release];
[timeDateFormatter release];
return [NSString stringWithFormat:@"%@ %@", datePart, [timePart substringFromIndex:skipZero]];
}
Ответы
Ответ 1
Причиной такого поведения является Locale, установить правильный локаль, установить локальный NSDateFormatter на ru_US_POSIX, чтобы исправить это.
Он работает как для 24-часового, так и для 12-часового формата.
От Apple doc:
В iPhone OS пользователь может переопределить настройку по умолчанию AM/PM по сравнению с 24-часовым временем (через Настройки > Общие > Дата и время > 24-часовое время), что заставляет NSDateFormatter переписывать указанную строку формата.
Ссылка: Каков наилучший способ справиться с языковой функцией NSDateFormatter?
Ответ 2
Я столкнулся с той же проблемой. Я поднял его как ошибку с Apple и разместил ее на Open Radar:
http://openradar.appspot.com/9774877
Ответ 3
Я нашел это решение:
NSDate *now = [[NSDate alloc] init];
NSTimeZone *localTimeZone = [NSTimeZone systemTimeZone];
NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
[rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
[rfc3339DateFormatter setTimeZone:localTimeZone];
NSString *dateString = [rfc3339DateFormatter stringFromDate:now];
NSLog(@"RFC 3339 datetime: %@", dateString);
// 2013-06-27T10:27:08-0600
// 2013-07-22T15:09:30+0100
Это исправлено 2 из моих проблем:
- Когда пользователь настроен на 12-часовой режим отображения, вывод с этим форматированием отображается как 24h
- Когда вы вручную устанавливаете часовой пояс в Дублине, на выходе не отображается датаTime с Z, а +0000
Ответ 4
У меня была аналогичная проблема, что я в конечном итоге сделал, чтобы изменить дату dateFormat, а не указывать timeStyle.
NSDateFormatter *formatter = [[ NSDateFormatter alloc ] init];
if (self.datePickerMode == UIDatePickerModeDateAndTime){
[formatter setDateFormat:[NSString stringWithFormat:@"%@ %@", f.dateFormat, @"HH:mm:ss"]];
}
Хорошо работает для меня, надеюсь, что это поможет.
Ответ 5
Используйте этот формат
NSDateFormatter* relativeDateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd hh:mm a";
NSString *stringDate = [dateFormatter stringFromDate:[NSDate date]];
- Instad HH (Час в день (0-23)) использует hh (Час в am/pm (1-12))
- Добавить a (маркер Am/pm) в конце формата.
Например: [Дата NSDate] 2017-05-14 12:40:00
- В 24-часовом времени вы получите 2017-05-14 12:40
- В 12-часовой момент вы получите 2017-05-14 12:40 PM
Для Сегодня | Вчера Я использую NSDateComponents для расчета и возврата правильной даты.
NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute;
NSDateComponents *components = [[NSCalendar currentCalendar] components:units fromDate:yourDate toDate:[NSDate date] options:0];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
if (components.year > 0) {
dateFormatter.dateFormat = [NSString stringWithFormat:@"'%@' '%@' MMM d, YYYY", [@"last seen" localized], [@"at" localized]];
}
else if (components.day > 7) {
dateFormatter.dateFormat = [NSString stringWithFormat:@"'%@' MMM d '%@' hh:mm a", [@"last seen" localized], [@"at" localized]];
}
NSString *relativeDateString = [dateFormatter stringFromDate: yourDate];