[FIXED] Ist es ein NSCalendar-Bug?

Ausgabe

Warum sind die letzten beiden Zeilen der Ausgabe gleich?

Verwenden Sie NSCalendar, um den Unterschied zwischen startTime und endTime zu berechnen, und stellen Sie fest, dass der Unterschied zwischen @”2008-02-28 00:00:00″ und @”2022-02-28 00:00:00″ und der Unterschied zwischen @”2008 -02-29 00:00:00″ und @”2022-02-28 00:00:00″ sind identisch. Es sieht aus wie ein Fehler von NSCalendar, vielleicht wegen des Sprungmonats?

Code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self printDiffBetweenStartTime:@"2008-02-27 00:00:00" endTime:@"2022-02-28 00:00:00"];
    [self printDiffBetweenStartTime:@"2008-02-28 00:00:00" endTime:@"2022-02-28 00:00:00"];
    [self printDiffBetweenStartTime:@"2008-02-29 00:00:00" endTime:@"2022-02-28 00:00:00"];
}

- (void)printDiffBetweenStartTime:(NSString *)startTime endTime:(NSString *)endTime
{
    static NSDateFormatter *dateFormatter;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
        dateFormatter.calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    });
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *startDate = [dateFormatter dateFromString:startTime];
    NSDate *endDate = [dateFormatter dateFromString:endTime];
    
    NSCalendarUnit unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *components = [calendar components:unitFlags fromDate:startDate toDate:endDate options:0];
    NSLog(@"\"%@\" to \"%@\" : %@ year %@ month %@ day %@ hour %@ minute %@ second", startTime, endTime, @(components.year), @(components.month), @(components.day), @(components.hour), @(components.minute), @(components.second));

}

Ausgang:

"2008-02-27 00:00:00" to "2022-02-28 00:00:00" : 14 year 0 month 1 day 0 hour 0 minute 0 second
"2008-02-28 00:00:00" to "2022-02-28 00:00:00" : 14 year 0 month 0 day 0 hour 0 minute 0 second
"2008-02-29 00:00:00" to "2022-02-28 00:00:00" : 14 year 0 month 0 day 0 hour 0 minute 0 second

Lösung

Dies wird erwartet. Es gibt viele Möglichkeiten, diese Periodenberechnungen durchzuführen, und die Methode, die NSCalendarverwendet wird, entpuppt sich als nicht die, die Sie erwartet haben.

Die Dokumentation beschreibt kurz, was es tut:

Einige Operationen können mehrdeutig sein, und das Verhalten der Berechnung ist kalenderspezifisch, aber im Allgemeinen werden größere Komponenten vor kleineren Komponenten berechnet; Beispielsweise könnte im gregorianischen Kalender ein Ergebnis 1 Monat und 5 Tage statt beispielsweise 0 Monate und 35 Tage sein.

Das bedeutet, dass zuerst berechnet wird, wie viele Jahre zwischen den beiden Daten liegen, dann Monate, dann Tage und so weiter. “Jahre” ist die größte Komponente, die Sie angefordert haben.

Und NSCalendarstellt fest, dass das Hinzufügen von 14 Jahren zum 28.02.2008 genau den 28.02.2022 ergibt. 2008-02-29 um 14 Jahre zu addieren ist auch genau 2022-02-28, weil 2022 kein Schaltjahr ist. Beachten Sie, dass „Hinzufügen eines Jahres“ nicht dasselbe bedeutet wie „Hinzufügen von 12 Monaten“ oder „Hinzufügen von 365 Tagen“.

Damit in diesem Fall eine Differenz angezeigt wird, müssen Sie zuerst die Tage berechnen. Eine Periode hat 5114 Tage, die andere 5113.

Noch ein paar Beispiele:

Wenn Sie stattdessen den Zeitraum für Jahr, Monat und Tag zwischen dem 28.02.2008 und dem 01.02.2022 und dem Zeitraum zwischen dem 29.02.2008 und dem 01.02.2022 berechnen. Sie würden keinen Unterschied sehen, beide sind 13 Jahre, 11 Monate und 4 Tage. Dies liegt daran, dass das Hinzufügen von 13 Jahren sowohl zum 29.02.2008 als auch zum 28.02.2008 Sie zum 28.02.2021 führt, und das Hinzufügen von 11 Monaten ergibt den 28.01.2022. 4 Tage danach ist 2022-02-01.

Wenn Sie jedoch nur Monate und Tage berechnen, sind der Zeitraum zwischen 2008-02-28 und 2022-02-01 und der Zeitraum zwischen 2008-02-29 und 2022-02-01 unterschiedlich.

Der Zeitraum zwischen 2008-02-28 und 2022-02-01 beträgt 167 Monate und 4 Tage. Wenn man zum 28.02.2008 167 Monate addiert, erhält man den 28.01.2022. 4 Tage danach ist 2022-02-01.

Der Zeitraum zwischen 2008-02-29 und 2022-02-01 beträgt 167 Monate und 3 Tage. Wenn man zum 29.02.2008 167 Monate addiert, erhält man den 29.01.2022. 3 Tage danach ist 2022-02-01.

Periodenberechnungen sind seltsam, nicht wahr? Aber sie sind auf einzigartige Weise konsistent.


Beantwortet von –
Kehrmaschine


Antwort geprüft von –
Katrina (FixError Volunteer)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like