Strange results from to_timestamp

Started by Mario Weilgunialmost 20 years ago9 messages
#1Mario Weilguni
mweilguni@sime.com

mydb=# select to_timestamp('00000000 0300','yyyymmdd hh24mi');
to_timestamp
---------------------------
0001-01-01 03:00:00+01 BC
(1 row)

Questionable, but probably valid.

mydb=# select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-12-25 03:00:00+01
(1 row)

This puzzles me. Where is the 25th of december coming from?

mydb=# select to_timestamp(' 030004','yyyymmdd hh24mi');
to_timestamp
------------------------
0382-04-23 03:00:00+01
(1 row)

Same as above.

mydb=# select to_timestamp(' 040004','yyyymmdd hh24mi');
to_timestamp
------------------------
0509-10-10 04:00:00+01

I think all except the first one should raise a warning, isn't it? Where can I
find the source code of this function?

Best regards,
Mario Weilguni

#2Mario Weilguni
mweilguni@sime.com
In reply to: Mario Weilguni (#1)
Re: Strange results from to_timestamp

Am Donnerstag, 6. April 2006 14:57 schrieb Mario Weilguni:

mydb=# select to_timestamp('00000000 0300','yyyymmdd hh24mi');
to_timestamp
---------------------------
0001-01-01 03:00:00+01 BC
(1 row)

Questionable, but probably valid.

mydb=# select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-12-25 03:00:00+01
(1 row)

This puzzles me. Where is the 25th of december coming from?

Sorry, forgot to mention, this is from PostgreSQL 8.1.3

#3William ZHANG
uniware@zedware.org
In reply to: Mario Weilguni (#1)
Re: Strange results from to_timestamp

ISTM, and mismatch between the date/time string and the format string will
lead to
strange results.
The source code of to_timestamp() is in src/backend/utils/adt/formatting.c:

Datum
to_timestamp(PG_FUNCTION_ARGS)

Regards,
William ZHANG

"Mario Weilguni" <mweilguni@sime.com>

Show quoted text

Am Donnerstag, 6. April 2006 14:57 schrieb Mario Weilguni:

mydb=# select to_timestamp('00000000 0300','yyyymmdd hh24mi');
to_timestamp
---------------------------
0001-01-01 03:00:00+01 BC
(1 row)

Questionable, but probably valid.

mydb=# select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-12-25 03:00:00+01
(1 row)

This puzzles me. Where is the 25th of december coming from?

Sorry, forgot to mention, this is from PostgreSQL 8.1.3

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mario Weilguni (#1)
Re: Strange results from to_timestamp

Mario Weilguni <mweilguni@sime.com> writes:

I think all except the first one should raise a warning, isn't it?

to_timestamp (and friends) all seem to me to act pretty bizarre when
faced with input that doesn't match the given format string. However,
in the end that is an Oracle-compatibility function, and there is only
one measure of what it should do: what does Oracle do in the same case.
Can anyone try these examples on a recent Oracle version?

regards, tom lane

#5Adrian Maier
adrian.maier@gmail.com
In reply to: Tom Lane (#4)
Re: Strange results from to_timestamp

On 4/7/06, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Mario Weilguni <mweilguni@sime.com> writes:

I think all except the first one should raise a warning, isn't it?

to_timestamp (and friends) all seem to me to act pretty bizarre when
faced with input that doesn't match the given format string. However,
in the end that is an Oracle-compatibility function, and there is only
one measure of what it should do: what does Oracle do in the same case.
Can anyone try these examples on a recent Oracle version?

In Oracle10g Express those dates are rejected as invalid :

SQL> select to_timestamp('00000000 0300','yyyymmdd hh24mi') from dual;
select to_timestamp('00000000 0300','yyyymmdd hh24mi') from dual
*
ERROR at line 1:
ORA-01843: not a valid month

SQL> select to_timestamp(' 0300','yyyymmdd hh24mi') from dual;
select to_timestamp(' 0300','yyyymmdd hh24mi') from dual
*
ERROR at line 1:
ORA-01843: not a valid month

Cheers,
Adrian Maier

#6Mario Weilguni
mario.weilguni@icomedias.com
In reply to: Adrian Maier (#5)
Re: Strange results from to_timestamp

to_timestamp is only for Oracle compatibility? I always thought it's some sort of sql standard. What's the sql compliant way to do this?

Regards,
mario weilguni

-----Ursprüngliche Nachricht-----
Von: pgsql-hackers-owner@postgresql.org [mailto:pgsql-hackers-owner@postgresql.org] Im Auftrag von Tom Lane
Gesendet: Freitag, 07. April 2006 06:09
An: Mario Weilguni
Cc: PostgreSQL-development
Betreff: Re: [HACKERS] Strange results from to_timestamp

Mario Weilguni <mweilguni@sime.com> writes:

I think all except the first one should raise a warning, isn't it?

to_timestamp (and friends) all seem to me to act pretty bizarre when faced with input that doesn't match the given format string. However, in the end that is an Oracle-compatibility function, and there is only one measure of what it should do: what does Oracle do in the same case.
Can anyone try these examples on a recent Oracle version?

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

#7Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Mario Weilguni (#6)
Re: Strange results from to_timestamp

Mario Weilguni wrote:

to_timestamp is only for Oracle compatibility? I always thought it's
some sort of sql standard. What's the sql compliant way to do this?

There isn't a standard method, which is why we added Oracle functions.

---------------------------------------------------------------------------

Regards,
mario weilguni

-----Urspr?ngliche Nachricht----- Von:
pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] Im Auftrag von Tom Lane
Gesendet: Freitag, 07. April 2006 06:09 An: Mario Weilguni Cc:
PostgreSQL-development Betreff: Re: [HACKERS] Strange results from
to_timestamp

Mario Weilguni <mweilguni@sime.com> writes:

I think all except the first one should raise a warning, isn't it?

to_timestamp (and friends) all seem to me to act pretty bizarre when
faced with input that doesn't match the given format string. However,
in the end that is an Oracle-compatibility function, and there is only
one measure of what it should do: what does Oracle do in the same case.
Can anyone try these examples on a recent Oracle version?

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

--
Bruce Momjian http://candle.pha.pa.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#8Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Mario Weilguni (#1)
Re: Strange results from to_timestamp

Interesting bug report. The problem is that sscanf(buf, "%d", &val)
eats leading white space, but our functions were not handling that.

I have applied the attached patch that fixes this:

test=> select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-01-01 00:00:00-05
(1 row)

test=> select to_timestamp(' 030004','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-04-01 00:00:00-05
(1 row)

test=> select to_timestamp(' 040004','yyyymmdd hh24mi');
to_timestamp
------------------------
0400-04-01 00:00:00-05
(1 row)

It doesn't throw an error for too mamy format strings, but it does avoid
the incorrect values. The fix will appear in 8.2.

---------------------------------------------------------------------------

Mario Weilguni wrote:

mydb=# select to_timestamp('00000000 0300','yyyymmdd hh24mi');
to_timestamp
---------------------------
0001-01-01 03:00:00+01 BC
(1 row)

Questionable, but probably valid.

mydb=# select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-12-25 03:00:00+01
(1 row)

This puzzles me. Where is the 25th of december coming from?

mydb=# select to_timestamp(' 030004','yyyymmdd hh24mi');
to_timestamp
------------------------
0382-04-23 03:00:00+01
(1 row)

Same as above.

mydb=# select to_timestamp(' 040004','yyyymmdd hh24mi');
to_timestamp
------------------------
0509-10-10 04:00:00+01

I think all except the first one should raise a warning, isn't it? Where can I
find the source code of this function?

Best regards,
Mario Weilguni

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

--
Bruce Momjian http://candle.pha.pa.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

#9Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Bruce Momjian (#8)
1 attachment(s)
Re: Strange results from to_timestamp

Attachment now attached. :-)

---------------------------------------------------------------------------

Bruce Momjian wrote:

Interesting bug report. The problem is that sscanf(buf, "%d", &val)
eats leading white space, but our functions were not handling that.

I have applied the attached patch that fixes this:

test=> select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-01-01 00:00:00-05
(1 row)

test=> select to_timestamp(' 030004','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-04-01 00:00:00-05
(1 row)

test=> select to_timestamp(' 040004','yyyymmdd hh24mi');
to_timestamp
------------------------
0400-04-01 00:00:00-05
(1 row)

It doesn't throw an error for too mamy format strings, but it does avoid
the incorrect values. The fix will appear in 8.2.

---------------------------------------------------------------------------

Mario Weilguni wrote:

mydb=# select to_timestamp('00000000 0300','yyyymmdd hh24mi');
to_timestamp
---------------------------
0001-01-01 03:00:00+01 BC
(1 row)

Questionable, but probably valid.

mydb=# select to_timestamp(' 0300','yyyymmdd hh24mi');
to_timestamp
------------------------
0300-12-25 03:00:00+01
(1 row)

This puzzles me. Where is the 25th of december coming from?

mydb=# select to_timestamp(' 030004','yyyymmdd hh24mi');
to_timestamp
------------------------
0382-04-23 03:00:00+01
(1 row)

Same as above.

mydb=# select to_timestamp(' 040004','yyyymmdd hh24mi');
to_timestamp
------------------------
0509-10-10 04:00:00+01

I think all except the first one should raise a warning, isn't it? Where can I
find the source code of this function?

Best regards,
Mario Weilguni

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

--
Bruce Momjian http://candle.pha.pa.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

--
Bruce Momjian http://candle.pha.pa.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

Attachments:

/rtmp/difftext/plainDownload
Index: src/backend/utils/adt/formatting.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v
retrieving revision 1.109
diff -c -c -r1.109 formatting.c
*** src/backend/utils/adt/formatting.c	19 Apr 2006 14:48:06 -0000	1.109
--- src/backend/utils/adt/formatting.c	19 Apr 2006 16:07:35 -0000
***************
*** 917,922 ****
--- 917,923 ----
  
  static char *get_th(char *num, int type);
  static char *str_numth(char *dest, char *num, int type);
+ static int	strspace_len(char *str);
  static int	strdigits_len(char *str);
  static char *str_toupper(char *buff);
  static char *str_tolower(char *buff);
***************
*** 1687,1697 ****
  }
  
  static int
  strdigits_len(char *str)
  {
  	char	   *p = str;
! 	int			len = 0;
  
  	while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
  	{
  		len++;
--- 1688,1714 ----
  }
  
  static int
+ strspace_len(char *str)
+ {
+ 	int			len = 0;
+ 
+ 	while (*str && isspace((unsigned char) *str))
+ 	{
+ 		str++;
+ 		len++;
+ 	}
+ 	return len;
+ }
+ 
+ static int
  strdigits_len(char *str)
  {
  	char	   *p = str;
! 	int			len;
  
+ 	len = strspace_len(str);
+ 	p += len;
+ 	
  	while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
  	{
  		len++;
***************
*** 1826,1832 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->hh);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 1843,1849 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->hh);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 1848,1854 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->hh);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 1865,1871 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->hh);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 1870,1876 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->mi);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 1887,1893 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->mi);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 1892,1898 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->ss);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 1909,1915 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->ss);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 1998,2004 ****
  				else
  				{
  					sscanf(inout, "%05d", &tmfc->ssss);
! 					return 5 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2015,2021 ----
  				else
  				{
  					sscanf(inout, "%05d", &tmfc->ssss);
! 					return strspace_len(inout) + 5 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2249,2255 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->mm);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2266,2272 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->mm);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2323,2329 ****
  				else
  				{
  					sscanf(inout, "%03d", &tmfc->ddd);
! 					return 3 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2340,2346 ----
  				else
  				{
  					sscanf(inout, "%03d", &tmfc->ddd);
! 					return strspace_len(inout) + 3 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2345,2351 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->dd);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2362,2368 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->dd);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2360,2366 ****
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->d);
! 				return 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_WW:
--- 2377,2383 ----
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->d);
! 				return strspace_len(inout) + 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_WW:
***************
*** 2382,2388 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->ww);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2399,2405 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->ww);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2405,2411 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->iw);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2422,2428 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->iw);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2422,2428 ****
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->q);
! 				return 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_CC:
--- 2439,2445 ----
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->q);
! 				return strspace_len(inout) + 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_CC:
***************
*** 2447,2453 ****
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->cc);
! 					return 2 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2464,2470 ----
  				else
  				{
  					sscanf(inout, "%02d", &tmfc->cc);
! 					return strspace_len(inout) + 2 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2507,2513 ****
  				{
  					sscanf(inout, "%04d", &tmfc->year);
  					tmfc->yysz = 4;
! 					return 4 + SKIP_THth(suf);
  				}
  			}
  			break;
--- 2524,2530 ----
  				{
  					sscanf(inout, "%04d", &tmfc->year);
  					tmfc->yysz = 4;
! 					return strspace_len(inout) + 4 + SKIP_THth(suf);
  				}
  			}
  			break;
***************
*** 2540,2546 ****
  				else
  					tmfc->year += 2000;
  				tmfc->yysz = 3;
! 				return 3 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_YY:
--- 2557,2563 ----
  				else
  					tmfc->year += 2000;
  				tmfc->yysz = 3;
! 				return strspace_len(inout) + 3 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_YY:
***************
*** 2572,2578 ****
  				else
  					tmfc->year += 1900;
  				tmfc->yysz = 2;
! 				return 2 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_Y:
--- 2589,2595 ----
  				else
  					tmfc->year += 1900;
  				tmfc->yysz = 2;
! 				return strspace_len(inout) + 2 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_Y:
***************
*** 2600,2606 ****
  				 */
  				tmfc->year += 2000;
  				tmfc->yysz = 1;
! 				return 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_RM:
--- 2617,2623 ----
  				 */
  				tmfc->year += 2000;
  				tmfc->yysz = 1;
! 				return strspace_len(inout) + 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_RM:
***************
*** 2652,2658 ****
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->w);
! 				return 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_J:
--- 2669,2675 ----
  			else
  			{
  				sscanf(inout, "%1d", &tmfc->w);
! 				return strspace_len(inout) + 1 + SKIP_THth(suf);
  			}
  			break;
  		case DCH_J: