32

標準のグレゴリオ暦の日付をユリウス日に変換する必要があります。

これを直接行うためにC#で文書化されたものは何も見たことがありませんが、ToOADateの使用を示唆する多くの投稿を(グーグルで)見つけました。

ToOADateのドキュメントでは、これがユリウス日の有効な変換方法として提案されていません。

この関数が正確に変換を実行するかどうか、または DateTime を Julian 形式の文字列に変換するためのより適切な方法を誰かが明確にすることはできますか?


これにより、ウィキペディアのユリウス日ページに対して検証されたときに予想される数が得られます

public static long ConvertToJulian(DateTime Date)
{
    int Month = Date.Month;
    int Day = Date.Day;
    int Year = Date.Year;

    if (Month < 3)
    {
        Month = Month + 12;
        Year = Year - 1;
    }
    long JulianDay = Day + (153 * Month - 457) / 5 + 365 * Year + (Year / 4) - (Year / 100) + (Year / 400) + 1721119;
    return JulianDay;
}

ただし、これは使用されているマジック ナンバーを理解していない場合です。

ありがとう


参考文献:

4

9 に答える 9

87

OADate はユリウス暦に似ていますが、異なる開始点 (1899 年 12 月 30 日と紀元前 4713 年 1 月 1 日) と、異なる「新しい日」の点を使用します。ユリウス日は正午を新しい一日の始まりと見なしますが、OADates は現代の定義である真夜中を使用します。

1899 年 12 月 30 日午前 0 時のユリウス日は 2415018.5 です。このメソッドは、適切な値を提供する必要があります。

public static double ToJulianDate(this DateTime date)
{
    return date.ToOADate() + 2415018.5;
}

アルゴリズムに関しては:

  • if (Month < 3) ...: マジック ナンバーを適切に機能させるために、2 月を 1 年の「終わり」にしています。
  • (153 * Month - 457) / 5: うわー、それはいくつかの深刻な魔法の数字です。
    • 通常、各月の日数は 31 28 31 30 31 30 31 31 30 31 30 31 ですが、if ステートメントで調整すると、31 30 31 30 31 31 30 31 30 31 31 28 になります。 30 とすると、1 0 1 0 1 1 0 1 0 1 1 -2 になります。彼らは、整数空間でその除算を行うことによって、1 と 0 のパターンを作成しています。
    • 浮動小数点に書き直すと、(int)(30.6 * Month - 91.4). 30.6 は、2 月を除く 1 か月あたりの平均日数です (正確には 30.63 繰り返し)。91.4 は、2 月以外の平均的な 3 か月の日数にほぼ匹敵します。(30.6 * 3 は 91.8)。
    • では、30 を削除して、その 0.6 日に注目してみましょう。これに月数を掛けて整数に切り捨てると、0 と 1 のパターンが得られます。
      • 0.6 * 0 = 0.0 -> 0
      • 0.6 * 1 = 0.6 -> 0 (0 の差)
      • 0.6 * 2 = 1.2 -> 1 (1 の差)
      • 0.6 * 3 = 1.8 -> 1 (差 0)
      • 0.6 * 4 = 2.4 -> 2 (1 の差)
      • 0.6 * 5 = 3.0 -> 3 (1 の差)
      • 0.6 * 6 = 3.6 -> 3 (0 の差)
      • 0.6 * 7 = 4.2 -> 4 (1 の差)
      • 0.6 * 8 = 4.8 -> 4 (差 0)
    • 右の違いのパターンがわかりますか?これは上記のリストと同じパターンで、各月の日数から 30 を引いたものです。91.8 を引くと、最初の 3 か月の日数が補正され、年末に移動され、調整されます。連続する 1 の差 (上の表の 0.6 * 4 と 0.6 * 5) を 0.4 移動して、31 日である隣接する月に合わせます。
    • 2 月は現在 1 年の「終わり」にあるため、その長さに対処する必要はありません。これは 45 日 (閏年では 46 日) になる可能性があり、変更する必要があるのは、1 年の日数の定数である 365 だけです。
    • これは、30 か月日と 31 か月日のパターンに依存することに注意してください。2 か月連続で 30 日だった場合、これは不可能です。
  • 365 * Year: 年間日数
  • (Year / 4) - (Year / 100) + (Year / 400): うるう日は 4 年ごとに 1 日プラス、100 年ごとにマイナス 1 日、プラス 400 年ごとに 1 日。
  • + 1721119: これは紀元前 1 年 3 月 2 日のユリウス日です。カレンダーの「開始」を 1 月から 3 月に移動したため、1 月 1 日ではなく、これをオフセットとして使用します。ゼロ年がないので、紀元前 1 年は整数値 0 を取得します。3 月 1 日ではなく 3 月 2 日である理由については、その月全体の計算が最後にまだ少しずれていたためだと思います。元の作成者が浮動小数点数の- 462代わりに- 457(- 92.4の代わりに) を使用した場合、オフセットは 3 月 1 日になります。- 91.4
于 2011-03-10T02:33:39.647 に答える
11

メソッド

public static double ToJulianDate(this DateTime date) { return date.ToOADate() + 2415018.5; }

現代の日付で機能しますが、重大な欠点があります。

ユリウス日は負の日付、つまり紀元前 (紀元前) の日付に対して定義され、天文学の計算では一般的です。年が 0 未満の DateTime オブジェクトを作成することはできないため、上記の方法を使用して紀元前の日付のユリウス日を計算することはできません。

1582 年のグレゴリオ暦の改革により、暦には 10 月 4 日から 15 日までの 11 日間の穴ができました。これらの日付は、ユリウス暦でもグレゴリオ暦でも定義されていませんが、DateTime はそれらを引数として受け入れます。さらに、上記のメソッドを使用すると、ユリウス日付の正しい値が返されません。System.Globalization.JulianCalendar.ToDateTime() を使用したり、JulianCalendar の紀元を DateTime コンストラクターに渡したりして実験を行っても、1582 年 10 月 5 日より前のすべての日付に対して正しくない結果が生成されます。

次のルーチンは、Jean Meeus の「Astronomical Algorithms」から採用されたもので、ユリウス暦のタイム ゼロである -4712 年 1 月 1 日の正午から始まるすべての日付に対して正しい結果を返します。また、無効な日付が渡された場合、ArgumentOutOfRangeException もスローします。

 public class JulianDate
{
    public static bool isJulianDate(int year, int month, int day)
    {
        // All dates prior to 1582 are in the Julian calendar
        if (year < 1582)
            return true;
        // All dates after 1582 are in the Gregorian calendar
        else if (year > 1582)
            return false;
        else
        {
            // If 1582, check before October 4 (Julian) or after October 15 (Gregorian)
            if (month < 10)
                return true;
            else if (month > 10)
                return false;
            else
            {
                if (day < 5)
                    return true;
                else if (day > 14)
                    return false;
                else
                    // Any date in the range 10/5/1582 to 10/14/1582 is invalid 
                    throw new ArgumentOutOfRangeException(
                        "This date is not valid as it does not exist in either the Julian or the Gregorian calendars.");
            }
        }
    }

    static private double DateToJD(int year, int month, int day, int hour, int minute, int second, int millisecond)
    {
        // Determine correct calendar based on date
        bool JulianCalendar = isJulianDate(year, month, day);

        int M = month > 2 ? month : month + 12;
        int Y = month > 2 ? year : year - 1;
        double D = day + hour/24.0 + minute/1440.0 + (second + millisecond / 1000.0)/86400.0;
        int B = JulianCalendar ? 0 : 2 - Y/100 + Y/100/4;

        return (int) (365.25*(Y + 4716)) + (int) (30.6001*(M + 1)) + D + B - 1524.5;
    }

    static public double JD(int year, int month, int day, int hour, int minute, int second, int millisecond)
    {
        return DateToJD(year, month, day, hour, minute, second, millisecond);
    }


    static public double JD(DateTime date) 
    {
        return DateToJD(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);
    }
}
于 2013-01-28T02:05:10.890 に答える
4

ユリウス日からDateTimeに変換する必要がある場合は、以下を参照してください。

public static DateTime FromJulianDate(double julianDate)
{
    return DateTime.FromOADate(julianDate - 2415018.5);
}
于 2016-12-28T20:39:47.137 に答える
1

Modified Julian Date のコードは、同じアルゴリズムを使用しますが、最後に別のマジック ナンバーを使用しているため、結果の値はWikipediaに表示されている Modified Julian Date と一致します。私はこの同じアルゴリズムを少なくとも 10 年間、毎日の時系列のキーとして使用してきました (元は Java)。

public static int IntegerDate(DateTime date)
    {
        int Month = date.Month;
        int Day = date.Day;
        int Year = date.Year;

        if (Month < 3)
        {
            Month = Month + 12;
            Year = Year - 1;
        }
        //modified Julian Date
        return Day + (153 * Month - 457) / 5 + 365 * Year + (Year / 4) - (Year / 100) + (Year / 400) - 678882;
    }

逆の計算には、娯楽のためのより多くの魔法の数があります。

public static DateTime FromDateInteger(int mjd)
    {
        long a = mjd + 2468570;
        long b = (long)((4 * a) / 146097);
        a = a - ((long)((146097 * b + 3) / 4));
        long c = (long)((4000 * (a + 1) / 1461001));
        a = a - (long)((1461 * c) / 4) + 31;
        long d = (long)((80 * a) / 2447);
        int Day = (int)(a - (long)((2447 * d) / 80));
        a = (long)(d / 11);
        int Month = (int)(d + 2 - 12 * a);
        int Year = (int)(100 * (b - 49) + c + a);
        return new DateTime(Year, Month, Day);
    }
于 2016-11-11T14:45:32.703 に答える