2

I'm trying to convert a Julian Date which includes hours minutes and seconds to a DateTime in C#.

This is the number: 2457285.7795969

I can calculate the DateTime excluding the hours and the minutes with this function.

public static DateTime FromJulian(long julianDate)
{
    long L = julianDate + 68569;
    long N = (long)((4 * L) / 146097);
    L = L - ((long)((146097 * N + 3) / 4));
    long I = (long)((4000 * (L + 1) / 1461001));
    L = L - (long)((1461 * I) / 4) + 31;
    long J = (long)((80 * L) / 2447);
    int Day = (int)(L - (long)((2447 * J) / 80));
    L = (long)(J / 11);
    int Month = (int)(J + 2 - 12 * L);
    int Year = (int)(100 * (N - 49) + I + L);

    return new DateTime(Year, Month, Day);
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Madthew
  • 686
  • 6
  • 15
  • Since you want time to the second, keep in mind that a leap second can make a day 86,001 seconds long rather than the usual 86,000. It is universally agreed that the integer part of the JD should only depend on the UT date (that is, the date at Royal Greenwich Time if winter time were kept year round). What to do about the fraction on a day with a leap second is not universally agreed. One solution is to divide the seconds since midnight by 86,001. What are the earliest and latest dates you have to deal with? – Gerard Ashton Sep 20 '15 at 13:58

3 Answers3

2

It should be as simple as:

public static DateTime FromJulian(double julianDate)
{
  return new DateTime(
    (long)((julianDate - 1721425.5) * TimeSpan.TicksPerDay),
    DateTimeKind.Utc);
}

As you can see, 1721425.5 is the so-called Gregorian epoch, i.e. the value the Julian date had at the beginning of the proleptic Gregorian calendar, at 0001 January 1, 00:00:00.0000000, where the .NET DateTime has its origin.

EDIT: If you want to make sure your method throws an exception on "extreme" inputs instead of returning an invalid value, do this:

public static DateTime FromJulian(double julianDate)
{
  return new DateTime(
    checked((long)((julianDate - 1721425.5) * TimeSpan.TicksPerDay)),
    DateTimeKind.Utc);
}

Note that we do the multiplication with the double operator *(double, double) overload (built-in in C#). This gives an error as little as possible. The conversion from double to long will throw in checked context if the double is outside the range of long. If that conversion goes well, the DateTime constructor may throw if the value of the long is out of range for a .NET DateTime.


NEW EDIT: Inspired by another thread (Convert DateTime to Julian Date in C# (ToOADate Safe?)) you can also work out a very simple solution using DateTime.FromOADate. However, see another Stack Overflow post by myself on precision short-comings of the FromOADate method.

Community
  • 1
  • 1
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
1

Is this what you are looking for: Convert Julian Date with Time (H/m/s) to Date Time in C#?
Applying that answer, converting your value of 2457285.7795969 results in 9/19/2015 11:42:37 PM.

Ladi
  • 1,274
  • 9
  • 17
  • 1
    Maybe worth copy some code from that link, as it can go dead as time goes by – Rubens Farias Sep 20 '15 at 09:01
  • Entering 2457285.7795969 into the US Naval Observatory's Multiyear Computer Interactive Almanac yields 2015 Sep 20 06:42:37.2 UT1 (which is within 0.9 seconds of UTC). Their website(http://aa.usno.navy.mil/cgi-bin/aa_jdconv.pl?form=2&jd=2457285.779596) gives nearly the same results, but the seconds are 37.1. If Landi implemented the code he/she linked to correctly, it's wrong. – Gerard Ashton Sep 20 '15 at 13:31
  • The difference is probably cause by my local time zone (Pacific Time: UTC - 7). I was careless and did not specify that I printed the result in my local time – Ladi Sep 20 '15 at 13:37
  • The linked answer (you should copy it to here to make your post self-contained) goes via the Unix time (which has origin 1970 January 1) for no good reason. The time in .NET has origin 0001 January 1 in the proleptic Gregorian calendar. See my answer. – Jeppe Stig Nielsen Sep 20 '15 at 20:08
  • Stack Overflow has [another answer](http://stackoverflow.com/a/26676794/1336654) which uses the same external source as yours. – Jeppe Stig Nielsen Sep 20 '15 at 21:23
0

Before Ladi answered with what I was looking for....

double L = DateTime.Now.ToOADate() + 2415018.5 + 68569;

double HMS = L-(int)L-0.5;  

int Hours = (int)(24*HMS);
HMS=HMS - (double)(Hours/24.0);
int Mins = (int)(24*60*HMS);
HMS=HMS - (double)(Mins/(24.0*60));

int Secs = (int)(24*60*60*HMS);

long N = (long)((4 * L) / 146097);
L = L - ((long)((146097 * N + 3) / 4));
long I = (long)((4000 * (L + 1) / 1461001));
L = L - (long)((1461 * I) / 4) + 31;
long J = (long)((80 * L) / 2447);
int Day = (int)(L - (long)((2447 * J) / 80));
L = (long)(J / 11);
int Month = (int)(J + 2 - 12 * L);
int Year = (int)(100 * (N - 49) + I + L);

DateTime test = new DateTime(Year, Month, Day);
Console.WriteLine("Hours-"+Hours);
Console.WriteLine("Mins-" + Mins);
Console.WriteLine("Secs-"+ Secs);

Console.WriteLine(test);
Console.WriteLine(DateTime.Now.ToString());
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Madthew
  • 686
  • 6
  • 15