Domanda

Saluti,

Recentemente ho affrontato un grosso problema (come sembra a me) con classe di NSCalendar.

Nel mio compito ho bisogno di lavorare con un grande periodi di tempo a partire dal 4000 aC al 2000AD (calendario gregoriano). In qualche luogo sono stato costretto a incrementare alcuni NSDate 100 intervallo anno. Quando incrementare gli anni in AD timeline. (0 -> ...) tutto ha funzionato bene, ma quando ho provato la stessa cosa con BC ero un po 'confuso

Il problema è che, quando si tenta di aggiungere 100 anni per 3000 aC [modifica] anno, si ottiene 3100BC [modificato] non importa cosa ... Personalmente l'ho trovato strano e illogico. Il risultato destra dovrebbe essere 2900BC.

Ecco il codice di esempio per voi di vedere questo "scorretto" il comportamento:

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

Che cosa si può dire di questo comportamento? È così che dovrebbe funzionare o si tratta di un bug? Sono confuso:. S

A proposito .: Il metodo [componenti NSCalendar: fromdate: TODATE: opzioni:] non consente di calcolare la differenza tra anni nell'era aC ... aggiuntiva 'PERCHE'?' in questo vaso di Pandora.

P.S .: stavo scavando attraverso la documentazione ufficiale e altre risorse ma non trovò nulla riguardo a questo problema (o forse è inteso per funzionare così e io sono un idiota?).

È stato utile?

Soluzione

Ho trovato una soluzione semplice per questo bug. Eccolo:

@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

Se vi chiedete perché ho invertito soli anni, la risposta è semplice, ogni altro componente, tranne anni di incremento e decremento nel modo giusto (io non li ho ancora testato, ma mesi e giorni sembrano funzionare bene).

Modifica :. Rimosso autorelease erroneamente aggiunto, grazie John

Altri suggerimenti

E 'un bug e o di una funzione. Il dottore di Apple non dice mai cosa intendono per l'aggiunta di componenti alla data del calendario . E 'perfettamente libero per loro di definire "l'aggiunta di un componente" alla data aC come solo l'aggiunta al componente anno.

Si sono d'accordo con te che è controintuitivo e penso che sia un bug.

È necessario convertire il vostro NSDate a uno

  • la seconda dall'epoca UNIX (1.1.1970) utilizzando -timeIntervalSince1970
  • la seconda dall'epoca OS X (1.1.2001) utilizzando -timeIntervalSinceReferenceDate

È quindi possibile eseguire il calcolo, e riconvertirlo in un NSDate. Penso che sia una cattiva idea di lavoro nel calendario gregoriano per tutto il tempo ... Sarebbe meglio per convertire il calendario gregoriano appena prima di mostrarlo sulla GUI.

Immaginate di avere appuntamento con la 1 ° momento della nostra era - AD 0001-01-01 00:00:00 Qual è stato il momento prima.? BC 0001-01-01 00:00:01 . Se gli sviluppatori di cacao utilizzato aritmetiche di base per questo compito, si otterrebbe AD 0000-12-31 23:59:59 . È che ragionevole per calendario gregoriano? Non credo. Quindi, mi sembra che il modo più conveniente per implementare il calendario è stato quello di usare la bandiera Era, e il cambiamento " direzione del tempo " quando si tratta di BC era di ottenere le date leggibili in ogni caso.

A proposito .: [NSCalendar dateByAddingComponents:toDate:options:] si comporta in modo davvero strano e non è in grado di contare intervallo di tempo tra le date BC, ho controllato anche. Così, per le date BC si può usare soluzione, per esempio traducendo risale al dC e poi trovare diff.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top