sql >> Base de Datos >  >> RDS >> PostgreSQL

Función age() de PostgreSQL:resultados diferentes/inesperados al aterrizar en un mes diferente

age se calcula por el timestamptz_age función en src/backend/utils/adt/timestamp.c . El comentario dice:

/* timestamptz_age()
 * Calculate time difference while retaining year/month fields.
 * Note that this does not result in an accurate absolute time span
 *  since year and month are out of context once the arithmetic
 *  is done.
 */

El código primero convierte los argumentos a struct pg_tm variables tm1 y tm2 (struct pg_tm es similar al struct tm de la biblioteca C , pero tiene campos de zona horaria adicionales) y luego calcula la diferencia tm por campo.

En el caso de age('2018-07-01','2018-05-20') , los campos relevantes de esa diferencia se verían así:

tm_mday = -19
tm_mon  =   2
tm_year =   0

Ahora se ajustan los campos negativos. para tm_mday , el código se ve así:

while (tm->tm_mday < 0)
{
    if (dt1 < dt2)
    {
        tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
        tm->tm_mon--;
    }
    else
    {
        tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
        tm->tm_mon--;
    }
}

Desde dt1 > dt2 , el else se toma la rama, y ​​el código agrega el número de días en mayo (31) y reduce el mes en 1, terminando con

tm_mday = 12
tm_mon  =  1
tm_year =  0

Ese es el resultado que obtienes.

Ahora, a primera vista, parece que tm2->tm_mon no es el mes correcto para elegir, y hubiera sido mejor tomar el mes anterior del argumento de la izquierda:

day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]

Pero no puedo decir si esa elección sería mejor en todos los casos y, en cualquier caso, el comentario indemniza la función, por lo que dudaría en llamarlo un error.

Es posible que desee retomarlo con la lista de correo de piratas informáticos.