objective iphone cocoa nsdate nsdateformatter

iphone - objective - Opción Ordinal de Sufijo de Mes y Día para NSDateFormatter setDateFormat



dateformatter swift 4 (15)

¿Qué opción de setDateFormat para NSDateFormatter utilizo para obtener el sufijo ordinal de un mes-día?

por ejemplo, el fragmento siguiente produce actualmente:
3:11 PM Sábado 15 de agosto

¿Qué debo cambiar para obtener:
3:11 PM Sábado 15 de agosto

NSDate *date = [NSDate date]; NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [dateFormatter setDateFormat:@"h:mm a EEEE MMMM d"]; NSString *dateString = [dateFormatter stringFromDate:date]; NSLog(@"%@", dateString);

En PHP, usaría esto para el caso anterior:
<?php echo date(''h:m A l F jS'') ?>

¿Hay un NSDateFormatter equivalente a la opción S en la cadena de formateo de PHP?


Agregué estos dos métodos a NSDate con una categoría NSDate + Additions.

/- (NSString *)monthDayYear { NSDateFormatter * dateFormatter = NSDateFormatter.new; [dateFormatter setDateFormat:@"MMMM d*, YYYY"]; NSString *dateString = [dateFormatter stringFromDate:self]; return [dateString stringByReplacingOccurrencesOfString:@"*" withString:[self ordinalSuffixForDay]]; } /- (NSString *)ordinalSuffixForDay { NSDateFormatter * dateFormatter = NSDateFormatter.new; [dateFormatter setDateFormat:@"d"]; NSString *dateString = [dateFormatter stringFromDate:self]; NSString *suffix = @"th"; if ([dateString length] == 2 && [dateString characterAtIndex:0] == ''1'') { return suffix; } switch ([dateString characterAtIndex:[dateString length]-1]) { case ''1'': suffix = @"st"; break; case ''2'': suffix = @"nd"; break; case ''3'': suffix = @"rd"; break; } return suffix; }

Puede hacer que sean más eficientes al combinarlos e indexar el dígito del lugar del día dentro de la cadena de formato como punto de cambio. Opté por separar la funcionalidad para que los sufijos ordinales puedan llamarse por separado para diferentes formatos de fecha.


Aquí hay otra implementación de un método para generar el sufijo. Los sufijos que produce solo son válidos en inglés y pueden no ser correctos en otros idiomas:

- (NSString *)suffixForDayInDate:(NSDate *)date { NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day]; if (day >= 11 && day <= 13) { return @"th"; } else if (day % 10 == 1) { return @"st"; } else if (day % 10 == 2) { return @"nd"; } else if (day % 10 == 3) { return @"rd"; } else { return @"th"; } }


Esto dará cadena en formato "10:10 PM sábado, 2 de agosto"

-(NSString*) getTimeInString:(NSDate*)date { NSString* string=@""; NSDateComponents *components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay fromDate:date]; if(components.day == 1 || components.day == 21 || components.day == 31){ string = @"st"; }else if (components.day == 2 || components.day == 22){ string = @"nd"; }else if (components.day == 3 || components.day == 23){ string = @"rd"; }else{ string = @"th"; } NSDateFormatter *prefixDateFormatter = [[NSDateFormatter alloc] init]; [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:[NSString stringWithFormat:@"h:mm a EEEE, d''%@'' MMMM",string]]; NSString *dateString = [prefixDateFormatter stringFromDate:date]; return dateString; }


Esto hará el formateo en dos pasos: primero, crea una subcadena que sea el día con un sufijo apropiado, luego crea una cadena de formato para las partes restantes, conectando el día ya formateado.

func ordinalDate(date: Date) -> String { let ordinalFormatter = NumberFormatter() ordinalFormatter.numberStyle = .ordinal let day = Calendar.current.component(.day, from: date) let dayOrdinal = ordinalFormatter.string(from: NSNumber(value: day))! let dateFormatter = DateFormatter() dateFormatter.dateFormat = "h:mm a EEEE MMMM ''/(dayOrdinal)''" return dateFormatter.string(from: Date()) }

Como NumberFormatter construye el día ordinal, debería funcionar en todos los idiomas, no solo en inglés.

Puede obtener una cadena de formato ordenada para la configuración regional actual reemplazando la asignación a dateFormat con esto:

dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "h:mm a EEEE MMMM d", options: 0, locale: dateFormatter.locale)?.replacingOccurrences(of: "d", with: "''/(dayOrdinal)''")

Tenga en cuenta el consejo de varios otros de que la creación de formateadores es costosa, por lo que debe almacenar en caché y reutilizarlos en el código que se llama con frecuencia.


Esto se hace fácilmente a partir de iOS9

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; formatter.numberStyle = NSNumberFormatterOrdinalStyle; NSArray<NSNumber *> *numbers = @[@1, @2, @3, @4, @5]; for (NSNumber *number in numbers) { NSLog(@"%@", [formatter stringFromNumber:number]); } // "1st", "2nd", "3rd", "4th", "5th"

Tomado de NSHipster

Swift 2.2:

let numberFormatter = NSNumberFormatter() numberFormatter.numberStyle = .OrdinalStyle let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for number in numbers { print(numberFormatter.stringFromNumber(number)!) }


Esto ya está implementado en la Fundación.

let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .ordinal numberFormatter.locale = Locale.current numberFormatter.string(for: 1) //Should produce 1st numberFormatter.string(for: 2) //Should produce 2nd numberFormatter.string(for: 3) //Should produce 3rd numberFormatter.string(for: 4) //Should produce 4th


La documentación de NSDateFormatter dice que todas las opciones de formato que admite están enumeradas en TR35 .

¿Por qué quieres esto? Si está haciendo algo para que una máquina lo analice, debe usar el formato ISO 8601 , o el formato RFC 2822 si es necesario. Ninguno de esos requiere o permite un sufijo ordinal.

Si muestra fechas para el usuario, debe usar uno de los formatos de la configuración regional del usuario.


La respuesta de Matt Andersen es bastante elaborada, al igual que SDJMcHattie. Pero NSDateFormatter es bastante pesado en la CPU y si llama a esto 100x realmente ve el impacto, entonces aquí hay una solución combinada derivada de las respuestas anteriores. (Tenga en cuenta que lo anterior sigue siendo correcto)

NSDateFormatter es increíblemente costoso de crear. Cree una vez y vuelva a utilizarla , pero tenga cuidado: no es segura para subprocesos, por lo que una por subproceso.

Asumiendo self.date = [NSDate date];

- (NSString *)formattedDate{ static NSDateFormatter *_dateFormatter = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _dateFormatter = [[NSDateFormatter alloc] init]; _dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; _dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; }); _dateFormatter.dateFormat = [NSString stringWithFormat:@"h:mm a EEEE MMMM d''%@''", [self suffixForDayInDate:self.date]]; NSString *date = [_dateFormatter stringFromDate:self.date]; return date; }

/ * Código de SDJMcHattie, esto es más conveniente que usar una matriz * /

- (NSString *)suffixForDayInDate:(NSDate *)date{ NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day]; if (day >= 11 && day <= 13) { return @"th"; } else if (day % 10 == 1) { return @"st"; } else if (day % 10 == 2) { return @"nd"; } else if (day % 10 == 3) { return @"rd"; } else { return @"th"; } }

Salida: 3:11 PM Sábado 15 de agosto


Los formateadores de fecha en Mac OS 10.5 y iPhone usan TR35 como su especificador de formato estándar. Esta especificación no permite dicho sufijo en cualquier fecha; si quieres uno, tendrás que generarlo tú mismo.


Ninguna de estas respuestas fue tan estéticamente agradable como lo que estoy usando, así que pensé que podría compartir:

Swift 3:

func daySuffix(from date: Date) -> String { let calendar = Calendar.current let dayOfMonth = calendar.component(.day, from: date) switch dayOfMonth { case 1, 21, 31: return "st" case 2, 22: return "nd" case 3, 23: return "rd" default: return "th" } }

C objetivo:

- (NSString *)daySuffixForDate:(NSDate *)date { NSCalendar *calendar = [NSCalendar currentCalendar]; NSInteger dayOfMonth = [calendar component:NSCalendarUnitDay fromDate:date]; switch (dayOfMonth) { case 1: case 21: case 31: return @"st"; case 2: case 22: return @"nd"; case 3: case 23: return @"rd"; default: return @"th"; } }

Obviamente, esto solo funciona en inglés.


Ninguna de las respuestas utiliza el estilo de número ordinal que ya está presente en el formateador de números en swift.

var dateString: String { let calendar = Calendar.current let dateComponents = calendar.component(.day, from: date) let numberFormatter = NumberFormatter() numberFormatter.numberStyle = .ordinal let day = numberFormatter.string(from: dateComponents as NSNumber) let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MMM" return day! + dateFormatter.string(from: date) }


O si desea el sufijo para cualquier número:

extension Int { public func suffix() -> String { let absSelf = abs(self) switch (absSelf % 100) { case 11...13: return "th" default: switch (absSelf % 10) { case 1: return "st" case 2: return "nd" case 3: return "rd" default: return "th" } } } }

El pensamiento es que hay 5 posibilidades para números positivos. Su primer dígito del lugar es 1 que es "st". El segundo dígito del lugar es 2 siendo "2do". Es el tercer dígito del lugar donde 3 es "rd". Cualquier otro caso es "th", o si el segundo dígito es 1, entonces las reglas anteriores no se aplican y es "th".

El Módulo 100 nos da los últimos dos números del dígito, por lo que podemos verificar el 11 al 13. El Módulo 10 nos da el último número del dígito, por lo que podemos verificar 1, 2, 3 si no está atrapado por la primera condición.

Prueba esa extensión en patios de recreo:

let a = -1 a.suffix() // "st" let b = 1112 b.suffix() // "th" let c = 32 c.suffix() // "nd"

Me encantaría ver si hay una forma aún más corta de escribir esto usando operaciones binarias y / o una matriz.


- (void)viewDidLoad { NSDate *date = [NSDate date]; NSDateFormatter *prefixDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [prefixDateFormatter setDateFormat:@"yyy-dd-MM"]; date = [prefixDateFormatter dateFromString:@"2014-6-03"]; //enter yourdate [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:@"EEEE MMMM d"]; NSString *prefixDateString = [prefixDateFormatter stringFromDate:date]; NSDateFormatter *monthDayFormatter = [[[NSDateFormatter alloc] init] autorelease]; [monthDayFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [monthDayFormatter setDateFormat:@"d"]; int date_day = [[monthDayFormatter stringFromDate:date] intValue]; NSString *suffix_string = @"|st|nd|rd|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|st|nd|rd|th|th|th|th|th|th|th|st"; NSArray *suffixes = [suffix_string componentsSeparatedByString: @"|"]; NSString *suffix = [suffixes objectAtIndex:date_day]; NSString *dateString = [prefixDateString stringByAppendingString:suffix]; NSLog(@"%@", dateString); }


- (NSString *)dayWithSuffixForDate:(NSDate *)date { NSInteger day = [[[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:date] day]; NSString *dayOfMonthWithSuffix, *suffix = nil ; if(day>0 && day <=31) { switch (day) { case 1: case 21: case 31: suffix = @"st"; break; case 2: case 22: suffix = @"nd"; break; case 3: case 23: suffix = @"rd"; break; default: suffix = @"th"; break; } dayOfMonthWithSuffix = [NSString stringWithFormat:@"%ld%@", (long)day , suffix]; } return dayOfMonthWithSuffix; }


NSDate *date = [NSDate date]; NSDateFormatter *prefixDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [prefixDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [prefixDateFormatter setDateFormat:@"h:mm a EEEE MMMM d"]; NSString *prefixDateString = [prefixDateFormatter stringFromDate:date]; NSDateFormatter *monthDayFormatter = [[[NSDateFormatter alloc] init] autorelease]; [monthDayFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; [monthDayFormatter setDateFormat:@"d"]; int date_day = [[monthDayFormatter stringFromDate:date] intValue]; NSString *suffix_string = @"|st|nd|rd|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|st|nd|rd|th|th|th|th|th|th|th|st"; NSArray *suffixes = [suffix_string componentsSeparatedByString: @"|"]; NSString *suffix = [suffixes objectAtIndex:date_day]; NSString *dateString = [prefixDateString stringByAppendingString:suffix]; NSLog(@"%@", dateString);