Конвертировать дату (год, месяц, день) в юлианский номер дня и обратно в дату

Я пытаюсь реализовать две функции: 1) преобразование даты в юлианский номер дня и 2) преобразование юлианского дня обратно в дату (год, месяц и день). Результат, который возвращает мой код, отключен на один день. Я не знаком с тем, как работает алгоритм, но я вижу, что если я возьму Math.Ceiling Юлианского числа это работает, но я не уверен, что это лучший способ исправить код. Любая помощь будет принята с благодарностью. Спасибо.

public class Program
{
    /// <summary>
    /// Converts year, month and day to a Julian number
    /// </summary>
    /// <param name="year"></param>
    /// <param name="month"></param>
    /// <param name="day"></param>
    /// <returns></returns>
    public static decimal JulianNumber(int year, int month, int day)
    {
        decimal a, b, c, e, f;

        if (month == 1 || month == 2)
        {
            year -= 1;
            month += 12;
        }
        a = Math.Truncate((decimal) year / 100);
        b = Math.Truncate(a / 4);
        c = 2 - a + b;
        e = Math.Truncate((365.25m * (year + 4716)));
        f = Math.Truncate((30.6001m * (month + 1)));

        return (c + day + e + f - 1524.5m);
        // return Math.Ceiling(c + day + e + f - 1524.5m);
    }

    /// <summary>
    /// Converts Julian number to year, month and day
    /// </summary>
    /// <param name="julianNumber"></param>
    /// <returns></returns>
    public static (int year, int month, int day) GregorianDate(decimal julianNumber)
    {
        int l, n, i, j, k;

        l = (int)julianNumber + 68569;
        n = 4 * l / 146097;
        l = l - (146097 * n + 3) / 4;
        i = 4000 * (l + 1) / 1461001;
        l = l - 1461 * i / 4 + 31;
        j = 80 * l / 2447;
        k = l - 2447 * j / 80;
        l = j / 11;
        j = j + 2 - 12 * l;
        i = 100 * (n - 49) + i + l;

        return (i, j, k);
    }

    public static void Main(string[] args)
    {
        var (year1, month1, day1) = (2010, 1, 2);

        var (year2, month2, day2) = GregorianDate(JulianNumber(year1, month1, day1));

        Console.WriteLine(year1 == year2);     // True
        Console.WriteLine(month1 == month2);   // True
        Console.WriteLine(day1 == day2);       // False!
    }
}

1 ответ

Решение

Проблема в определении юлианского дня. Взято со страницы, на которую вы ссылаетесь:

Вслед за ведущими астрономами Гершеля эта система была принята и в полдень по Гринвичу GMT -4712-01-01 JC (1 января 4713 г. до н.э.)

Таким образом, 2018-05-28 в 00.00 - 2458266.5, а 2018-05-28 в 12.00 - 2458267. Если вы смотрите JulianNumber без Math.Ceiling фактически возвращает 2458266,5. Теперь страница, на которую вы ссылались (с которой вы взяли второй метод, GregorianDate, использует только целые числа, поэтому он работает для дат, которые в полдень (12.00). Таким образом, округляя (потолок) результат JulianNumber Вы переносите дату на 12.00 часов и делаете ее "совместимой" с GregorianDate,

Возможные решения: использовать для JulianNumber алгоритм, который присутствует на той же странице и использовать только int везде (чтобы показать тот факт, что вы игнорируете часы, минуты, секунды), или искать другой алгоритм для GregorianDate,

Другие вопросы по тегам