Pregunta

Saludos,

Hace poco se enfrentó a un gran problema (como parece a mí) con la clase NSCalendar.

En mi tarea que tiene que trabajar con un gran períodos de tiempo a partir del año 4000 AC a 2000AD (calendario gregoriano). En algún lugar me vi obligado a incrementar algunos NSDate por intervalo de 100 años. Al incrementar los años en la línea de tiempo AD. (0 -> ...) todo funcionaba bien, pero cuando he intentado lo mismo con BC que estaba un poco confundido

El problema es que cuando intenta agregar 100 años a 3000 AC [editado] años, se obtiene 3100BC [editado] no importa qué ... En lo personal me pareció extraño e ilógico. El resultado correcto debe ser 2900BC.

Aquí está el ejemplo de código para que usted vea este comportamiento "no está bien":

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

// initing
NSDateComponents *comps = [[[NSDateComponents alloc] init] autorelease];
[comps setYear:-1000];
NSDate *date = [gregorian dateFromComponents:comps];

// math
NSDateComponents *deltaComps = [[[NSDateComponents alloc] init] autorelease];
[deltaComps setYear:100];

date = [gregorian dateByAddingComponents:deltaComps toDate:date options:0];

// output
NSString *dateFormat = @"yyyy GG";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSLog(@"%@", [formatter stringFromDate:date]);

¿Qué se puede decir acerca de este comportamiento? ¿Es esta la forma en que debería funcionar o se trata de un error? Estoy confundido:. S

BTW .: el método [NSCalendar componentes: fromdate: TODATE: Opciones:] no nos permiten calcular la diferencia entre años antes de Cristo en la era ... adicional ¿Por qué? en esta caja de Pandora.

P.S .: Yo estaba cavando a través de documentos oficiales y otros recursos, pero no encontró nada sobre este problema (o tal vez es la intención de trabajar de manera y yo soy un idiota?).

¿Fue útil?

Solución

He encontrado una solución simple para este error. Aquí está:

@interface NSCalendar (EraFixes)

- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts;

@end

@implementation NSCalendar (EraFixes)

- (NSDate *)dateByAddingComponentsRegardingEra:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts
{
    NSDateComponents *toDateComps = [self components:NSEraCalendarUnit fromDate:date];
    NSDateComponents *compsCopy = [[comps copy] autorelease];

    if ([toDateComps era] == 0) //B.C. era
    {
        if ([comps year] != NSUndefinedDateComponent) [compsCopy setYear:-[comps year]];
    }

    return [self dateByAddingComponents:compsCopy toDate:date options:opts];
}

@end

Si usted se pregunta por qué sólo invertido años, la respuesta es simple, todos los demás componentes, excepto años se incremento y decremento de la manera correcta (no los he probado, pero los meses y los días parece que funcionan bien).

Editar . Autorelease eliminado añadido por error, gracias John

Otros consejos

Es un error y o una función. El doc Apple nunca dice lo que entienden por añadir componentes a la fecha del calendario . Es perfectamente libre para que ellos definen "la adición de un componente" a la fecha BCE como se acaba la adición al componente año.

Sí estoy de acuerdo con usted en que es contrario a la intuición y yo creo que es un error.

Es necesario para convertir su NSDate en

  • la segunda desde la época UNIX (1.1.1970) usando -timeIntervalSince1970
  • el segundo de la época OS X (1.1.2001) usando -timeIntervalSinceReferenceDate

A continuación, se puede realizar el cálculo, y convertirlo de nuevo en un NSDate. Creo que es una mala idea para el trabajo en el calendario gregoriano todo el tiempo ... Sería mejor para convertir al calendario gregoriano justo antes de mostrarlo en la interfaz gráfica de usuario.

Imagine que tiene fecha con primero momento de nuestra era - AD 0001-01-01 00:00:00 ¿Cuál fue el momento antes.? BC 0001-01-01 00:00:01 . Si los desarrolladores de cacao utilizado aritméticas básicas para esta tarea, se llega a AD 0000-12-31 23:59:59 . Es que razonable para el calendario gregoriano? Supongo que no. Por lo tanto, me parece que la forma más conveniente para poner en práctica el calendario era utilizar la bandera de Época, y el cambio " dirección del tiempo " cuando se trata de la era aC al ver las fechas legible en todos los casos.

BTW .: [NSCalendar dateByAddingComponents:toDate:options:] realmente se comporta de manera extraña y es incapaz de contar intervalo de tiempo entre las fechas antes de Cristo, he comprobado también. Por lo tanto, para conocer las fechas BC puede usar solución, por ejemplo, mediante la traducción de las fechas a AD y luego encontrar dif.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top