Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit05506fc

Browse files
committed
Fix datetime input to behave correctly for Feb 29 in years BC.
Formerly, DecodeDate attempted to verify the day-of-the-month exactly, butit was under the misapprehension that it would know whether we were lookingat a BC year or not. In reality this check can't be made until the callingfunction (eg DecodeDateTime) has processed all the fields. So, split theBC adjustment and validity checks out into a new function ValidateDate thatis called only after processing all the fields. In passing, this patchmakes DecodeTimeOnly work for BC inputs, which it never did before.(The historical veracity of all this is nonexistent, of course, but ifwe're going to say we support proleptic Gregorian calendar then we shoulddo it correctly. In any case the unpatched code is broken because it couldemit dates that it would then reject on re-inputting.)Per report from Bernd Helmle. Back-patch as far as 8.0; in 7.x we werenot using our own calendar support and so this seems a bit too riskyto put into 7.4.
1 parent9956ddc commit05506fc

File tree

1 file changed

+93
-99
lines changed

1 file changed

+93
-99
lines changed

‎src/backend/utils/adt/datetime.c

Lines changed: 93 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.185 2008/02/17 02:09:28 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.186 2008/02/25 23:21:01 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -40,7 +40,10 @@ static int DecodeTime(char *str, int fmask, int *tmask,
4040
structpg_tm*tm,fsec_t*fsec);
4141
staticintDecodeTimezone(char*str,int*tzp);
4242
staticconstdatetkn*datebsearch(constchar*key,constdatetkn*base,intnel);
43-
staticintDecodeDate(char*str,intfmask,int*tmask,structpg_tm*tm);
43+
staticintDecodeDate(char*str,intfmask,int*tmask,bool*is2digits,
44+
structpg_tm*tm);
45+
staticintValidateDate(intfmask,boolis2digits,boolbc,
46+
structpg_tm*tm);
4447
staticvoidTrimTrailingZeros(char*str);
4548

4649

@@ -805,7 +808,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
805808
}
806809
else
807810
{
808-
dterr=DecodeDate(field[i],fmask,&tmask,tm);
811+
dterr=DecodeDate(field[i],fmask,
812+
&tmask,&is2digits,tm);
809813
if (dterr)
810814
returndterr;
811815
}
@@ -1000,7 +1004,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
10001004
/* Embedded decimal and no date yet? */
10011005
if (cp!=NULL&& !(fmask&DTK_DATE_M))
10021006
{
1003-
dterr=DecodeDate(field[i],fmask,&tmask,tm);
1007+
dterr=DecodeDate(field[i],fmask,
1008+
&tmask,&is2digits,tm);
10041009
if (dterr)
10051010
returndterr;
10061011
}
@@ -1234,51 +1239,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
12341239
if (tmask&fmask)
12351240
returnDTERR_BAD_FORMAT;
12361241
fmask |=tmask;
1237-
}
1238-
1239-
if (fmask&DTK_M(YEAR))
1240-
{
1241-
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
1242-
if (bc)
1243-
{
1244-
if (tm->tm_year>0)
1245-
tm->tm_year=-(tm->tm_year-1);
1246-
else
1247-
ereport(ERROR,
1248-
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1249-
errmsg("inconsistent use of year %04d and \"BC\"",
1250-
tm->tm_year)));
1251-
}
1252-
elseif (is2digits)
1253-
{
1254-
if (tm->tm_year<70)
1255-
tm->tm_year+=2000;
1256-
elseif (tm->tm_year<100)
1257-
tm->tm_year+=1900;
1258-
}
1259-
}
1260-
1261-
/* now that we have correct year, decode DOY */
1262-
if (fmask&DTK_M(DOY))
1263-
{
1264-
j2date(date2j(tm->tm_year,1,1)+tm->tm_yday-1,
1265-
&tm->tm_year,&tm->tm_mon,&tm->tm_mday);
1266-
}
1267-
1268-
/* check for valid month */
1269-
if (fmask&DTK_M(MONTH))
1270-
{
1271-
if (tm->tm_mon<1||tm->tm_mon>MONTHS_PER_YEAR)
1272-
returnDTERR_MD_FIELD_OVERFLOW;
1273-
}
1242+
}/* end loop over fields */
12741243

1275-
/* minimal check for valid day */
1276-
if (fmask&DTK_M(DAY))
1277-
{
1278-
if (tm->tm_mday<1||tm->tm_mday>31)
1279-
returnDTERR_MD_FIELD_OVERFLOW;
1280-
}
1244+
/* do final checking/adjustment of Y/M/D fields */
1245+
dterr=ValidateDate(fmask,is2digits,bc,tm);
1246+
if (dterr)
1247+
returndterr;
12811248

1249+
/* handle AM/PM */
12821250
if (mer!=HR24&&tm->tm_hour>12)
12831251
returnDTERR_FIELD_OVERFLOW;
12841252
if (mer==AM&&tm->tm_hour==12)
@@ -1296,14 +1264,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
12961264
returnDTERR_BAD_FORMAT;
12971265
}
12981266

1299-
/*
1300-
* Check for valid day of month, now that we know for sure the month
1301-
* and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
1302-
* unlikely that "Feb 29" is a YMD-order error.
1303-
*/
1304-
if (tm->tm_mday>day_tab[isleap(tm->tm_year)][tm->tm_mon-1])
1305-
returnDTERR_FIELD_OVERFLOW;
1306-
13071267
/*
13081268
* If we had a full timezone spec, compute the offset (we could not do
13091269
* it before, because we need the date to resolve DST status).
@@ -1486,6 +1446,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
14861446
intval;
14871447
intdterr;
14881448
boolis2digits= FALSE;
1449+
boolbc= FALSE;
14891450
intmer=HR24;
14901451
pg_tz*namedTz=NULL;
14911452

@@ -1517,7 +1478,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
15171478
if (i==0&&nf >=2&&
15181479
(ftype[nf-1]==DTK_DATE||ftype[1]==DTK_TIME))
15191480
{
1520-
dterr=DecodeDate(field[i],fmask,&tmask,tm);
1481+
dterr=DecodeDate(field[i],fmask,
1482+
&tmask,&is2digits,tm);
15211483
if (dterr)
15221484
returndterr;
15231485
}
@@ -1783,7 +1745,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
17831745
*/
17841746
if (i==0&&nf >=2&&ftype[nf-1]==DTK_DATE)
17851747
{
1786-
dterr=DecodeDate(field[i],fmask,&tmask,tm);
1748+
dterr=DecodeDate(field[i],fmask,
1749+
&tmask,&is2digits,tm);
17871750
if (dterr)
17881751
returndterr;
17891752
}
@@ -1912,6 +1875,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
19121875
mer=val;
19131876
break;
19141877

1878+
caseADBC:
1879+
bc= (val==BC);
1880+
break;
1881+
19151882
caseUNITS:
19161883
tmask=0;
19171884
ptype=val;
@@ -1960,8 +1927,14 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
19601927
if (tmask&fmask)
19611928
returnDTERR_BAD_FORMAT;
19621929
fmask |=tmask;
1963-
}
1930+
}/* end loop over fields */
19641931

1932+
/* do final checking/adjustment of Y/M/D fields */
1933+
dterr=ValidateDate(fmask,is2digits,bc,tm);
1934+
if (dterr)
1935+
returndterr;
1936+
1937+
/* handle AM/PM */
19651938
if (mer!=HR24&&tm->tm_hour>12)
19661939
returnDTERR_FIELD_OVERFLOW;
19671940
if (mer==AM&&tm->tm_hour==12)
@@ -2047,24 +2020,29 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
20472020
* Decode date string which includes delimiters.
20482021
* Return 0 if okay, a DTERR code if not.
20492022
*
2050-
* Insist on a complete set of fields.
2023+
*str: field to be parsed
2024+
*fmask: bitmask for field types already seen
2025+
**tmask: receives bitmask for fields found here
2026+
**is2digits: set to TRUE if we find 2-digit year
2027+
**tm: field values are stored into appropriate members of this struct
20512028
*/
20522029
staticint
2053-
DecodeDate(char*str,intfmask,int*tmask,structpg_tm*tm)
2030+
DecodeDate(char*str,intfmask,int*tmask,bool*is2digits,
2031+
structpg_tm*tm)
20542032
{
20552033
fsec_tfsec;
20562034
intnf=0;
20572035
inti,
20582036
len;
20592037
intdterr;
20602038
boolhaveTextMonth= FALSE;
2061-
boolbc= FALSE;
2062-
boolis2digits= FALSE;
20632039
inttype,
20642040
val,
20652041
dmask=0;
20662042
char*field[MAXDATEFIELDS];
20672043

2044+
*tmask=0;
2045+
20682046
/* parse this string... */
20692047
while (*str!='\0'&&nf<MAXDATEFIELDS)
20702048
{
@@ -2090,14 +2068,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
20902068
nf++;
20912069
}
20922070

2093-
#if0
2094-
/* don't allow too many fields */
2095-
if (nf>3)
2096-
returnDTERR_BAD_FORMAT;
2097-
#endif
2098-
2099-
*tmask=0;
2100-
21012071
/* look first for text fields, since that will be unambiguous month */
21022072
for (i=0;i<nf;i++)
21032073
{
@@ -2115,10 +2085,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21152085
haveTextMonth= TRUE;
21162086
break;
21172087

2118-
caseADBC:
2119-
bc= (val==BC);
2120-
break;
2121-
21222088
default:
21232089
returnDTERR_BAD_FORMAT;
21242090
}
@@ -2144,7 +2110,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21442110

21452111
dterr=DecodeNumber(len,field[i],haveTextMonth,fmask,
21462112
&dmask,tm,
2147-
&fsec,&is2digits);
2113+
&fsec,is2digits);
21482114
if (dterr)
21492115
returndterr;
21502116

@@ -2158,23 +2124,38 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21582124
if ((fmask& ~(DTK_M(DOY) |DTK_M(TZ)))!=DTK_DATE_M)
21592125
returnDTERR_BAD_FORMAT;
21602126

2161-
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2162-
if (bc)
2163-
{
2164-
if (tm->tm_year>0)
2165-
tm->tm_year=-(tm->tm_year-1);
2166-
else
2167-
ereport(ERROR,
2168-
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2169-
errmsg("inconsistent use of year %04d and \"BC\"",
2170-
tm->tm_year)));
2171-
}
2172-
elseif (is2digits)
2127+
/* validation of the field values must wait until ValidateDate() */
2128+
2129+
return0;
2130+
}
2131+
2132+
/* ValidateDate()
2133+
* Check valid year/month/day values, handle BC and DOY cases
2134+
* Return 0 if okay, a DTERR code if not.
2135+
*/
2136+
staticint
2137+
ValidateDate(intfmask,boolis2digits,boolbc,structpg_tm*tm)
2138+
{
2139+
if (fmask&DTK_M(YEAR))
21732140
{
2174-
if (tm->tm_year<70)
2175-
tm->tm_year+=2000;
2176-
elseif (tm->tm_year<100)
2177-
tm->tm_year+=1900;
2141+
/* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2142+
if (bc)
2143+
{
2144+
if (tm->tm_year>0)
2145+
tm->tm_year=-(tm->tm_year-1);
2146+
else
2147+
ereport(ERROR,
2148+
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2149+
errmsg("inconsistent use of year %04d and \"BC\"",
2150+
tm->tm_year)));
2151+
}
2152+
elseif (is2digits)
2153+
{
2154+
if (tm->tm_year<70)
2155+
tm->tm_year+=2000;
2156+
elseif (tm->tm_year<100)
2157+
tm->tm_year+=1900;
2158+
}
21782159
}
21792160

21802161
/* now that we have correct year, decode DOY */
@@ -2185,16 +2166,29 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21852166
}
21862167

21872168
/* check for valid month */
2188-
if (tm->tm_mon<1||tm->tm_mon>MONTHS_PER_YEAR)
2189-
returnDTERR_MD_FIELD_OVERFLOW;
2169+
if (fmask&DTK_M(MONTH))
2170+
{
2171+
if (tm->tm_mon<1||tm->tm_mon>MONTHS_PER_YEAR)
2172+
returnDTERR_MD_FIELD_OVERFLOW;
2173+
}
21902174

2191-
/* check for valid day */
2192-
if (tm->tm_mday<1||tm->tm_mday>31)
2193-
returnDTERR_MD_FIELD_OVERFLOW;
2175+
/* minimal check for valid day */
2176+
if (fmask&DTK_M(DAY))
2177+
{
2178+
if (tm->tm_mday<1||tm->tm_mday>31)
2179+
returnDTERR_MD_FIELD_OVERFLOW;
2180+
}
21942181

2195-
/* We don't want to hint about DateStyle for Feb 29 */
2196-
if (tm->tm_mday>day_tab[isleap(tm->tm_year)][tm->tm_mon-1])
2197-
returnDTERR_FIELD_OVERFLOW;
2182+
if ((fmask&DTK_DATE_M)==DTK_DATE_M)
2183+
{
2184+
/*
2185+
* Check for valid day of month, now that we know for sure the month
2186+
* and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
2187+
* unlikely that "Feb 29" is a YMD-order error.
2188+
*/
2189+
if (tm->tm_mday>day_tab[isleap(tm->tm_year)][tm->tm_mon-1])
2190+
returnDTERR_FIELD_OVERFLOW;
2191+
}
21982192

21992193
return0;
22002194
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp