age
jest obliczana przez timestamptz_age
funkcja w src/backend/utils/adt/timestamp.c
. Komentarz mówi:
/* 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.
*/
Kod najpierw konwertuje argumenty na struct pg_tm
zmienne tm1
i tm2
(struct pg_tm
jest podobny do struct tm
z biblioteki C , ale ma dodatkowe pola strefy czasowej), a następnie oblicza różnicę tm
na pole.
W przypadku age('2018-07-01','2018-05-20')
, odpowiednie pola tej różnicy będą wyglądać tak:
tm_mday = -19
tm_mon = 2
tm_year = 0
Teraz pola ujemne są dostosowywane. dla tm_mday
, kod wygląda tak:
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--;
}
}
Od dt1 > dt2
, else
brana jest gałąź, a kod dodaje liczbę dni w maju (31) i zmniejsza miesiąc o 1, kończąc na
tm_mday = 12
tm_mon = 1
tm_year = 0
To jest wynik, który otrzymujesz.
Teraz na pierwszy rzut oka wydaje się, że tm2->tm_mon
nie jest właściwym miesiącem do wyboru i lepiej byłoby wziąć poprzedni miesiąc z lewego argumentu:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
Ale nie mogę powiedzieć, czy ten wybór byłby lepszy we wszystkich przypadkach, aw każdym razie komentarz zabezpiecza funkcję, więc waham się nazwać to błędem.
Możesz to zrobić z listą dyskusyjną hakerów.