年齢コード>
timestamptz_age
によって計算されます src / backend / utils / adt / timestamp.c
の関数 。コメントによると:
/* 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.
*/
コードは最初に引数をstructpg_tm
に変換します 変数tm1
およびtm2
( struct pg_tm
Cライブラリのstructtm
に似ています 、ただし追加のタイムゾーンフィールドがあります)、差を計算します tm
フィールドごと。
age( '2018-07-01'、 '2018-05-20')
の場合 、その違いの関連フィールドは次のようになります:
tm_mday = -19
tm_mon = 2
tm_year = 0
これで、負のフィールドが調整されます。 tm_mday
の場合 、コードは次のようになります:
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--;
}
}
dt1> dt2
以降 、 else
分岐が行われ、コードは5月の日数(31)を追加し、月を1減らして、最終的に
tm_mday = 12
tm_mon = 1
tm_year = 0
それがあなたが得る結果です。
一見すると、 tm2-> tm_mon
のように見えます 選択するのに適切な月ではありません。左の引数の前の月を取る方がよいでしょう:
day_tab[isleap(tm1->tm_year)][(tm1->tm_mon + 10) % 12]
しかし、その選択がすべての場合に適しているかどうかはわかりません。いずれにしても、コメントは関数を補償するので、バグと呼ぶことを躊躇します。
ハッカーのメーリングリストで取り上げることをお勧めします。