I conducted a quick test with the Cocoa Touch to see how NSHebrewCalendar works. I'm particularly interested in the month numbers. I used a date picker to easily change dates, and I passed it in to a method which logs the hebrew date, the hebrew month number, the hebrew year, and if the year is leap year. That looks like this:

BOOL isHebrewLeapYear = [self.calendar isHebrewLeapYear:[calendar hebrewYearForDate:[self.calendar workingDate]]];

NSLog(@"Hebrew Date:%@, Month Number: %i, %i is Leap Year: %i", [self.calendar stringFromHebrewDate:[self.calendar workingDate]], [self.calendar hebrewMonthNumberFromDate:[self.calendar workingDate]], [calendar hebrewYearForDate:[self.calendar workingDate]], isHebrewLeapYear);    

The self.calendar object is a custom class. The workingDate property is an NSDate instance. Here are the relevant method declarations.

//  Check if a given year is a leap year
- (BOOL) isHebrewLeapYear:(NSInteger)year{
    return ((7 * year + 1) % 19) < 7;
}

//Get the hebrew year for a given date
- (NSInteger) hebrewYearForDate:(NSDate *)date{
   NSCalendar *hebrewCalendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSHebrewCalendar] autorelease];
   return [[hebrewCalendar components:NSYearCalendarUnit fromDate:date] year];
}

- (NSInteger) hebrewMonthNumberFromDate:(NSDate *)date{
    NSCalendar *hebrewCalendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSHebrewCalendar] autorelease];
    return [[hebrewCalendar components:NSMonthCalendarUnit fromDate:date] month];
}

Apparently hebrew leap years are handled as follows:

  • Month numbering starts at 1, with that month being "Tishri".
  • In a nonleap year, Adar is month number 7, not 6.
  • In a leap year, Adar I is number 6 and Adar II is 7.
  • "Nisan" is always 8 and so on until "Elul", which is always 13.

Does it sound like my experiment is producing accurate results? Is this behavior documented anywhere?

有帮助吗?

解决方案

Month numbering starts at 1, with that month being "Tishri".

Correct.

In a nonleap year, Adar is month number 7, not 6.

Technically incorrect. (More on this below)

In a leap year, Adar I is number 6 and Adar II is 7.

Correct.

"Nisan" is always 8 and so on until "Elul", which is always 13.

Correct.

So what's up with Adar in non-leap years? I ran this code to find out:

@autoreleasepool {

    NSDate *today = [NSDate date];
    NSCalendar *hebrew = [[NSCalendar alloc] initWithCalendarIdentifier:NSHebrewCalendar];
    NSDateComponents *diff = [[NSDateComponents alloc] init];
    NSDateFormatter *f = [[NSDateFormatter alloc] init];
    [f setDateFormat:@"d MMMM y"];
    [f setCalendar:hebrew];

    for (NSInteger i = 0; i < 19; ++i) {
        NSDateComponents *comp = [[NSDateComponents alloc] init];
        [comp setYear:5772 + i];
        [comp setDay:1];

        NSLog(@"============= %d ============", [comp year]);

        for (NSInteger i = 1; i <= 13; ++i) {
            [comp setMonth:i];

            NSDate *d = [hebrew dateFromComponents:comp];
            NSLog(@"%d: %@ (%@)", i, [f stringFromDate:d], d);
        }
    }

}

In a leap year, this will log what you would expect:

============= 5790 ============
1: 1 Tishri 5790 (2029-09-10 07:00:00 +0000)
2: 1 Heshvan 5790 (2029-10-10 07:00:00 +0000)
3: 1 Kislev 5790 (2029-11-08 08:00:00 +0000)
4: 1 Tevet 5790 (2029-12-07 08:00:00 +0000)
5: 1 Shevat 5790 (2030-01-05 08:00:00 +0000)
6: 1 Adar I 5790 (2030-02-04 08:00:00 +0000)
7: 1 Adar II 5790 (2030-03-06 08:00:00 +0000)
8: 1 Nisan 5790 (2030-04-04 07:00:00 +0000)
9: 1 Iyar 5790 (2030-05-04 07:00:00 +0000)
10: 1 Sivan 5790 (2030-06-02 07:00:00 +0000)
11: 1 Tamuz 5790 (2030-07-02 07:00:00 +0000)
12: 1 Av 5790 (2030-07-31 07:00:00 +0000)
13: 1 Elul 5790 (2030-08-30 07:00:00 +0000)

For each incrementation of the "month" date component, we get a different date. But when we run this in a non-leap year, we get this:

============= 5789 ============
1: 1 Tishri 5789 (2028-09-21 07:00:00 +0000)
2: 1 Heshvan 5789 (2028-10-21 07:00:00 +0000)
3: 1 Kislev 5789 (2028-11-19 08:00:00 +0000)
4: 1 Tevet 5789 (2028-12-19 08:00:00 +0000)
5: 1 Shevat 5789 (2029-01-17 08:00:00 +0000)
6: 1 Adar 5789 (2029-02-16 08:00:00 +0000)
7: 1 Adar 5789 (2029-02-16 08:00:00 +0000)
8: 1 Nisan 5789 (2029-03-17 07:00:00 +0000)
9: 1 Iyar 5789 (2029-04-16 07:00:00 +0000)
10: 1 Sivan 5789 (2029-05-15 07:00:00 +0000)
11: 1 Tamuz 5789 (2029-06-14 07:00:00 +0000)
12: 1 Av 5789 (2029-07-13 07:00:00 +0000)
13: 1 Elul 5789 (2029-08-12 07:00:00 +0000)

Here we see that have a month of 6 and 7 will both evaluate to Adar. Thus, Adar is both the 6th and the 7th month in non-leap years.


Also, since we know that the year 5790 is a leap year, we can deduce a simpler implementation of the -isHebrewLeapYear: method:

- (BOOL) isHebrewLeapYear:(NSInteger)year{
    return year % 19 == 14;
}

其他提示

To avoid making my own calculations on when a leap year is, here's the code I used to test for it (based on the previous finding that month 6 and 7 are Adar I in a regular year:

- (BOOL)isRegularYear:(NSDate *)date {
    NSCalendar *hebrew = [[NSCalendar alloc] initWithCalendarIdentifier:NSHebrewCalendar];

    NSDateComponents *comp = [hebrew components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:date];

    [comp setMonth:6];
    NSDate *adar_i = [hebrew dateFromComponents:comp];
    [comp setMonth:7];
    NSDate *adar_ii = [hebrew dateFromComponents:comp];

    return [adar_i isEqualToDate:adar_ii];
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top