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.