Преобразование григорианской даты в юлианский подсчет дней в задаче C

Мне нужен метод Objective C для преобразования григорианской даты в юлианские дни так же, как этот метод PHP (GregorianToJD).

3 ответа

Решение

Согласно http://en.wikipedia.org/wiki/Julian_day, число юлианских дней на 1 января 2000 года составляло 2 451 545. Таким образом, вы можете вычислить количество дней между вашей датой и этой контрольной датой. Например (1 января 2014 г.):

NSUInteger julianDayFor01012000 = 2451545;
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[cal setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDateComponents *comp = [[NSDateComponents alloc] init];
comp.year = 2014;
comp.month = 1;
comp.day = 1;
NSDate *date = [cal dateFromComponents:comp];
comp.year = 2000;
comp.month = 1;
comp.day = 1;
NSDate *ref = [cal dateFromComponents:comp];

NSDateComponents *diff = [cal components:NSDayCalendarUnit fromDate:ref toDate:date options:0];
NSInteger julianDays = diff.day + julianDayFor01012000;
NSLog(@"%ld", (long)julianDays);
// Output: 2456659

Это дает тот же результат, что и http://www.php.net/manual/en/function.gregoriantojd.php:

<?php
$jd = GregorianToJD(1, 1, 2014);
echo "$jd\n";
?>

Обратное направление (юлианские дни в григорианский год / месяц / день):

NSInteger julianDays = 2456659; // From above example
NSUInteger julianDayFor01012000 = 2451545;
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[cal setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDateComponents *comp = [[NSDateComponents alloc] init];
comp.year = 2000;
comp.month = 1;
comp.day = 1;
NSDate *ref = [cal dateFromComponents:comp];
NSDateComponents *diff = [[NSDateComponents alloc] init];
diff.day = julianDays - julianDayFor01012000;

NSDate *date = [cal dateByAddingComponents:diff toDate:ref options:0];
comp = [cal components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:date];
NSLog(@"%04ld-%02ld-%02ld", (long)comp.year, (long)comp.month, (long)comp.day);
// Output: 2014-01-01

ОБНОВЛЕНИЕ: Как Hot Licks правильно указал в комментарии, проще использовать форматер даты с форматом "g":

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comp = [[NSDateComponents alloc] init];
comp.year = 2014;
comp.month = 1;
comp.day = 1;
NSDate *date = [cal dateFromComponents:comp];
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"g"];
NSInteger julianDays = [[fmt stringFromDate:date] integerValue];
NSLog(@"%ld", (long)julianDays);
// Output: 2456659

И для обратного направления:

NSInteger julianDays = 2456659;
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"g"];
NSDate *date = [fmt dateFromString:[@(julianDays) stringValue]];
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comp = [cal components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:date];
NSLog(@"%04ld-%02ld-%02ld", (long)comp.year, (long)comp.month, (long)comp.day);
// Output: 2014-01-01

Точность: учет времени суток в юлианских датах

Эти юлианские методы преобразования дат дают результаты, идентичные онлайновому конвертеру дат Джулиана военно-морской обсерватории США, который является более точным NSDateFormatter's Юлиан Конвертация дат. В частности, приведенные ниже функции включают время суток (например, часы, минуты и секунды), тогда как NSDateFormatter раунды до полудня по Гринвичу.

Быстрые примеры:

func jdFromDate(date : NSDate) -> Double {
    let JD_JAN_1_1970_0000GMT = 2440587.5
    return JD_JAN_1_1970_0000GMT + date.timeIntervalSince1970 / 86400
}

func dateFromJd(jd : Double) -> NSDate {
    let JD_JAN_1_1970_0000GMT = 2440587.5
    return  NSDate(timeIntervalSince1970: (jd - JD_JAN_1_1970_0000GMT) * 86400)
}

Примеры Objective-C:

double jdFromDate(NSDate *date) {
   double JD_JAN_1_1970_0000GMT = 2440587.5;
   return JD_JAN_1_1970_0000GMT + date.timeIntervalSince1970 / 86400;
}

NSDate dataFromJd(double jd) {
   double JD_JAN_1_1970_0000GMT = 2440587.5;
   return [[NSDate alloc] initWithTimeIntervalSince1970: (jd - JD_JAN_1_1970_0000GMT) * 86400)];        
}

Примечание. Исследования подтверждают, что принятый ответ округляет дату до 24-часового интервала, поскольку используется g спецификатор формата NSDateFormatter , который возвращает Модифицированный юлианский день в соответствии с шаблонами формата даты стандарта UNICODE, которых придерживаются API форматирования даты Apple (согласно Руководству по форматированию даты).

      let date = Date() // now
let cal = Calendar.current
var day = 0
day = cal.ordinality(of: .day, in: .year, for: date) ?? 0
Другие вопросы по тегам