Question

Bonjour,

Récemment, je fait face à un gros problème (comme il me semble) avec classe NSCalendar.

Dans ma tâche que je dois travailler avec de longues périodes de temps à partir de 4000BC à 2000AD (calendrier grégorien). Dans un endroit que je suis obligé d'incrémenter un certain NSDate par intervalle de 100 ans. Lorsque incrémenter les années dans le scénario AD. (0 -> ...) tout a bien fonctionné, mais quand j'ai essayé la même chose avec la Colombie-Britannique i était un peu confus

Le problème est, lorsque vous essayez d'ajouter 100 ans à 3000 ans avant JC [édité] année, vous obtenez 3100BC [modifié], peu importe ce que ... Personnellement, je l'ai trouvé étrange et illogique. Le résultat correct doit être 2900BC.

Voici l'exemple de code pour vous de voir ce comportement « non droit »:

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]);

Que pouvez-vous dire au sujet de ce comportement? Est-ce la façon dont il devrait fonctionner ou est-ce un bug? Je suis confus. S

BTW .: la méthode [composants NSCalendar: FromDate: ToDate: Options:] ne nous permet pas de calculer la différence entre les années dans l'ère de la Colombie-Britannique ... plus «POURQUOI? dans la boîte de Pandore.

P.S .: Je fouillais dans les documents officiels et d'autres ressources, mais rien trouvé au sujet de ce problème (ou peut-être il est destiné à travailler si je suis un idiot?).

Était-ce utile?

La solution

J'ai trouvé une solution simple pour ce bogue. Ici, il 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 vous vous demandez pourquoi je inverti années seulement, la réponse est simple, tous les autres composants, sauf années est incrémenter et décrémenter la bonne manière (je ne les ai pas testé tous, mais des mois et des jours semble fonctionner très bien).

EDIT :. Enlevé autorelease ajouté par erreur, merci John

Autres conseils

Il est un bug et ou une fonction. Le doc Apple dit jamais ce qu'ils veulent dire par ajouter des composants à la date calendrical . Il est parfaitement libre pour eux pour définir « l'ajout d'un composant » à la date de BCE en tant que l'ajout du composant de l'année.

Oui je suis d'accord avec vous que c'est contre-intuitif et je pense que c'est un bug.

Vous devez convertir votre NSDate soit

  • la seconde à partir de l'époque UNIX (01/01/1970) en utilisant -timeIntervalSince1970
  • la seconde à partir de l'époque OS X (01.01.2001) en utilisant -timeIntervalSinceReferenceDate

Vous pouvez alors effectuer le calcul et la reconvertir en un NSDate. Je pense qu'il est une mauvaise idée de travailler dans le calendrier grégorien tout le temps ... Il serait préférable de convertir le calendrier grégorien juste avant que vous le montrer sur l'interface graphique.

Imaginez que vous avez rendez-vous avec le 1er moment de notre ère - AD 0001-01-01 00:00:00 Quel a été le moment avant.? BC 0001-01-01 00:00:01 . Si les développeurs Cocoa utilisé pour cette tâche de arithmétiques de base, vous obtiendrez AD 0000-12-31 23:59:59 . Est-ce raisonnable pour le calendrier grégorien? Je suppose que non. Donc, il me semble que la façon la plus pratique de mettre en œuvre le calendrier était d'utiliser le drapeau Era, et le changement « direction du temps » lorsqu'ils traitent avec l'époque en Colombie-Britannique pour obtenir des dates lisibles par l'homme dans tous les cas.

BTW .: [NSCalendar dateByAddingComponents:toDate:options:] se comporte vraiment étrange et ne peut pas compter l'intervalle de temps entre les dates Colombie-Britannique, j'ai vérifié aussi. Donc, pour les dates de la Colombie-Britannique, vous pouvez utiliser solution de contournement, par exemple en traduisant les dates à AD puis trouver diff.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top