Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a Gregorian date to Julian Day Count in Objective C

I need Objective C method for converting Gregorian date to Julian days same as this PHP method (GregorianToJD).

like image 672
wod Avatar asked Apr 03 '14 06:04

wod


2 Answers

Precision: Incorporating time of day in Julian Date conversions

These Julian date conversion methods yield results identical to the U.S. Naval Observatory's Online Julian Date Converter, which is more precise than NSDateFormatter's Julian Date conversion. Specifically, the functions below incorporate time-of-day (e.g. hour, minute and seconds), whereas NSDateFormatter rounds to noon GMT.

Update: Link to US Naval Observatory's online Julian date converter was removed, because it was to moved to a new website address which refers to a server that is offline or missing at the time of this edit. Search Google if you want to see if it has become available again.

Swift examples:

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 examples:

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

Note: Research confirms that the accepted answer rounds the date to a 24-hour interval because it uses the g format-specifier of NSDateFormatter, which returns the Modified Julian Day, according to the UNICODE standard's Date Format Patterns that Apple's date formatting APIs adhere to (according to the Date Formatting Guide).

like image 89
clearlight Avatar answered Oct 06 '22 00:10

clearlight


According to http://en.wikipedia.org/wiki/Julian_day, the Julian day number for January 1, 2000, was 2,451,545. So you can compute the number of days between your date and this reference date. For example (Jan 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

This gives the same result as http://www.php.net/manual/en/function.gregoriantojd.php:

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

Inverse direction (Julian days to Gregorian year/month/day):

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

UPDATE: As Hot Licks correctly stated in a comment, it is easier to use a date formatter with the "g" format:

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

And for the inverse direction:

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
like image 45
Martin R Avatar answered Oct 06 '22 00:10

Martin R