Saltar al contenido

Convertir DateTime en fecha juliana en C # (¿ToOADate Safe?)

Hola usuario de nuestro sitio, hallamos la respuesta a tu búsqueda, deslízate y la obtendrás un poco más abajo.

Solución:

OADate es similar a Julian Dates, pero utiliza un punto de partida diferente (30 de diciembre de 1899 frente al 1 de enero de 4713 aC) y un punto de “nuevo día” diferente. Julian Dates considera que el mediodía es el comienzo de un nuevo día, los OADates usan la definición moderna, medianoche.

La fecha juliana de la medianoche del 30 de diciembre de 1899 es 2415018.5. Este método debería proporcionarle los valores adecuados:

public static double ToJulianDate(this DateTime date)

    return date.ToOADate() + 2415018.5;

En cuanto al algoritmo:

  • if (Month < 3) ...: Para hacer que los números mágicos funcionen correctamente, están poniendo febrero al 'fin' del año.
  • (153 * Month - 457) / 5: Vaya, esos son algunos números mágicos serios.
    • Normalmente, el número de días de cada mes es 31 28 31 30 31 30 31 31 30 31 30 31, pero después de ese ajuste en la declaración if, se convierte en 31 30 31 30 31 31 30 31 30 31 31 28. O reste 30 y terminas con 1 0 1 0 1 1 0 1 0 1 1-2. Están creando ese patrón de 1 y 0 al hacer esa división en el espacio entero.
    • Reescrito en coma flotante, sería (int)(30.6 * Month - 91.4). 30,6 es el número medio de días por mes, excluyendo febrero (30,63 repitiendo, para ser exactos). 91,4 es casi la cantidad de días en 3 meses promedio distintos de febrero. (30,6 * 3 es 91,8).
    • Entonces, eliminemos los 30 y concentrémonos en esos 0,6 días. Si lo multiplicamos por el número de meses y luego lo truncamos a un número entero, obtendremos un patrón de 0 y 1.
      • 0,6 * 0 = 0,0 -> 0
      • 0,6 * 1 = 0,6 -> 0 (diferencia de 0)
      • 0,6 * 2 = 1,2 -> 1 (diferencia de 1)
      • 0,6 * 3 = 1,8 -> 1 (diferencia de 0)
      • 0,6 * 4 = 2,4 -> 2 (diferencia de 1)
      • 0,6 * 5 = 3,0 -> 3 (diferencia de 1)
      • 0,6 * 6 = 3,6 -> 3 (diferencia de 0)
      • 0,6 * 7 = 4,2 -> 4 (diferencia de 1)
      • 0,6 * 8 = 4,8 -> 4 (diferencia de 0)
    • ¿Ves ese patrón de diferencias en la derecha? Ese es el mismo patrón en la lista anterior, la cantidad de días en cada mes menos 30. La resta de 91.8 compensaría la cantidad de días en los primeros tres meses, que se movieron al "final" del año y ajustando en 0.4 mueve las diferencias sucesivas de 1 (0.6 * 4 y 0.6 * 5 en la tabla anterior) para alinearse con los meses adyacentes que son 31 días.
    • Dado que febrero está ahora al "final" del año, no tenemos que ocuparnos de su duración. Podría tener una duración de 45 días (46 en un año bisiesto), y lo único que tendría que cambiar es la constante del número de días en un año, 365.
    • Tenga en cuenta que esto se basa en el patrón de días de 30 y 31 meses. Si tuviéramos dos meses seguidos que fueran 30 días, esto no sería posible.
  • 365 * Year: Días por año
  • (Year / 4) - (Year / 100) + (Year / 400): Más un día bisiesto cada 4 años, menos uno cada 100, más uno cada 400.
  • + 1721119: Esta es la fecha juliana del 2 de marzo del 1 a. C. Dado que movimos el "inicio" del calendario de enero a marzo, usamos esto como nuestro desplazamiento, en lugar del 1 de enero. Como no hay año cero, 1 BC obtiene el valor entero 0. En cuanto a por qué el 2 de marzo en lugar del 1 de marzo, supongo que es porque el cálculo del mes completo todavía estaba un poco fuera de lugar al final. Si el escritor original hubiera usado - 462 en lugar de - 457 (- 92.4 en lugar de - 91.4 en matemáticas de coma flotante), entonces el desplazamiento habría sido al 1 de marzo.

Mientras que el método

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

funciona para fechas modernas, tiene deficiencias importantes.

La fecha juliana se define para fechas negativas, es decir, fechas BCE (antes de la era común) y es común en los cálculos astronómicos. No puede construir un objeto DateTime con el año menor que 0, por lo que la fecha juliana no se puede calcular para las fechas BCE utilizando el método anterior.

La reforma del calendario gregoriano de 1582 puso un hueco de 11 días en el calendario entre el 4 y el 15 de octubre. Esas fechas no están definidas ni en el calendario juliano ni en el calendario gregoriano, pero DateTime las acepta como argumentos. Además, el uso del método anterior no devuelve el valor correcto para ninguna fecha juliana. Los experimentos con el uso de System.Globalization.JulianCalendar.ToDateTime () o el paso de la era JulianCalendar al constructor DateTime aún producen resultados incorrectos para todas las fechas anteriores al 5 de octubre de 1582.

Las siguientes rutinas, adaptadas de los "Algoritmos astronómicos" de Jean Meeus, devuelven resultados correctos para todas las fechas a partir del mediodía del 1 de enero de -4712, hora cero en el calendario juliano. También lanzan una ArgumentOutOfRangeException si se pasa una fecha no válida.

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

La explicación de David Yaw es acertada, pero el cálculo del número acumulado de días del año para los meses anteriores al mes dado es anti-intuitivo. Si prefieres un array de enteros para que el algoritmo sea más claro, entonces esto hará:

    /*
     * convert magic numbers created by:
     *    (153*month - 457)/5) 
     * into an explicit array of integers
     */
    int[] CumulativeDays = new int[]
    
        -92   // Month = 0  (Should not be accessed by algorithm)
      , -61   // Month = 1  (Should not be accessed by algorithm)
      , -31   // Month = 2  (Should not be accessed by algorithm)
      ,   0   // Month = 3  (March)
      ,  31   // Month = 4  (April)
      ,  61   // Month = 5  (May)
      ,  92   // Month = 6  (June)
      , 122   // Month = 7  (July)
      , 153   // Month = 8  (August)
      , 184   // Month = 9  (September)
      , 214   // Month = 10 (October)
      , 245   // Month = 11 (November)
      , 275   // Month = 12 (December)
      , 306   // Month = 13 (January, next year)
      , 337   // Month = 14 (February, next year)
    ;

y las primeras tres líneas del cálculo se convierten en:

  int julianDay = day
                  + CumulativeDays[month]
                  + 365*year
                  + (year/4)

La expresion

(153*month - 457)/5)

aunque produce exactamente la misma secuencia, los mismos enteros que el array arriba para valores en el rango: 3 a 14; inclusive y lo hace sin requisitos de almacenamiento. La falta de requisitos de almacenamiento es solo una virtud para calcular el número acumulado de días de una manera tan confusa.

Si tienes alguna desconfianza y capacidad de limar nuestro sección te recomendamos ejecutar una anotación y con deseo lo ojearemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *