age dihitung dengan timestamptz_age fungsi di src/backend/utils/adt/timestamp.c . Komentarnya berbunyi:
/* 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.
*/
Kode pertama-tama mengubah argumen menjadi struct pg_tm variabel tm1 dan tm2 (struct pg_tm mirip dengan struct tm perpustakaan C , tetapi memiliki bidang zona waktu tambahan) dan kemudian menghitung perbedaan tm per bidang.
Dalam kasus age('2018-07-01','2018-05-20') , bidang yang relevan dari perbedaan itu akan terlihat seperti ini:
tm_mday = -19
tm_mon = 2
tm_year = 0
Sekarang bidang negatif disesuaikan. untuk tm_mday , kodenya terlihat seperti ini:
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--;
}
}
Sejak dt1 > dt2 , else cabang diambil, dan kode menambahkan jumlah hari di bulan Mei (31) dan mengurangi bulan sebanyak 1, berakhir dengan
tm_mday = 12
tm_mon = 1
tm_year = 0
Itulah hasil yang Anda dapatkan.
Sekarang pada pandangan pertama tampaknya tm2->tm_mon bukan bulan yang tepat untuk dipilih, dan akan lebih baik untuk mengambil bulan sebelumnya dari argumen kiri:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
Tetapi saya tidak dapat mengatakan apakah pilihan itu akan lebih baik dalam semua kasus, dan bagaimanapun juga, komentar tersebut mengganti kerugian fungsi tersebut, jadi saya ragu untuk menyebutnya sebagai bug.
Anda mungkin ingin membawanya ke milis peretas.