
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message



Here is another attempt at the datetime fix, to stop the ambiguity 
for dates like "01-13-2003". I put the > 12 month validation in because 
otherwise it is still read in as a "month", but it rolls over. 
In other words, '2003-14-03' becomes '2004-02-03'



--
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200306301327





Index: datetime.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
retrieving revision 1.106
diff -c -r1.106 datetime.c
*** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
--- datetime.c	30 Jun 2003 17:26:22 -0000
***************
*** 2379,2440 ****
  	 ***/
  	else if (flen >= 4)
  	{
! 		*tmask = DTK_M(YEAR);
  
! 		/* already have a year? then see if we can substitute... */
! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  		{
! 			tm->tm_mday = tm->tm_year;
! 			*tmask = DTK_M(DAY);
  		}
! 
! 		tm->tm_year = val;
  	}
! 
! 	/* already have year? then could be month */
! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
  	}
! 	/* no year and EuroDates enabled? then could be day */
! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	else if ((!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	else if ((!(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 
! 	/*
! 	 * Check for 2 or 4 or more digits, but currently we reach here only
! 	 * if two digits. - thomas 2000-03-28
! 	 */
! 	else if (!(fmask & DTK_M(YEAR))
! 			 && ((flen >= 4) || (flen == 2)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 
! 		/* adjust ONLY if exactly two digits... */
! 		*is2digits = (flen == 2);
  	}
  	else
! 		return -1;
  
  	return 0;
  }	/* DecodeNumber() */
--- 2379,2447 ----
  	 ***/
  	else if (flen >= 4)
  	{
! 		/* 
! 		 * If no month or day, start of YYYY-MM-DD
! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
! 		 * If neither case, throw an error
! 		 */
  
! 		if ((!(fmask & DTK_M(YEAR)))
! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
! 				||
! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
  		{
! 			*tmask = DTK_M(YEAR);
! 			tm->tm_year = val;
  		}
! 		else
! 			return -1;
  	}
! 	/* If we already have a day AND month, must be a 2-digit year */
! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 		*is2digits = TRUE;
  	}
! 
! 	/* If we already have a year and a month, must be day */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
! 		return -1;
! 	/* If have year or day, set the month */
! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
  	{
+ 		/* Do not allow month to roll over */
+ 		if (val > 12)
+ 			return -1;
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	/* If have a month, set the day */
! 	else if ((fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* If using EuroDates, this must be the day, otherwise month */
! 	else if (EuroDates)
  	{
! 		*tmask = DTK_M(DAY);
! 		tm->tm_mday = val;
  	}
  	else
! 	{
! 		/* Do not allow month to roll over */
! 		if (val > 12)
! 			return -1;
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
! 	}
  
  	return 0;
  }	/* DecodeNumber() */




-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iD8DBQE/AHNDvJuQZxSWSsgRApuiAKDB5CcBTxwQBnOdRkzPpLCOKHMmNgCeLJ//
Nz5sB+KyQUWv+MEVLXztBJw=
=kXb4
-----END PGP SIGNATURE-----




Mon, 30 Jun 2003 17:31:27 -0000
greg@turnstep.com
Datetime patch
greg@turnstep.com writes:

> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
> ! 		return -1;

I believe this conditional is incorrect.  The second part should be
DTK_M(DAY).

-- 
Peter Eisentraut   peter_e@gmx.net


Tue, 1 Jul 2003 02:08:27 +0200 (CEST)
Peter Eisentraut <peter_e@gmx.net>
Re: Datetime patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message


> I believe this conditional is incorrect.  The second part should be DTK_M(DAY).

Thank you - that is correct. Revised patch below.




Index: datetime.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
retrieving revision 1.106
diff -c -r1.106 datetime.c
*** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
--- datetime.c	30 Jun 2003 17:26:22 -0000
***************
*** 2379,2440 ****
  	 ***/
  	else if (flen >= 4)
  	{
! 		*tmask = DTK_M(YEAR);
  
! 		/* already have a year? then see if we can substitute... */
! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  		{
! 			tm->tm_mday = tm->tm_year;
! 			*tmask = DTK_M(DAY);
  		}
! 
! 		tm->tm_year = val;
  	}
! 
! 	/* already have year? then could be month */
! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
  	}
! 	/* no year and EuroDates enabled? then could be day */
! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	else if ((!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	else if ((!(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 
! 	/*
! 	 * Check for 2 or 4 or more digits, but currently we reach here only
! 	 * if two digits. - thomas 2000-03-28
! 	 */
! 	else if (!(fmask & DTK_M(YEAR))
! 			 && ((flen >= 4) || (flen == 2)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 
! 		/* adjust ONLY if exactly two digits... */
! 		*is2digits = (flen == 2);
  	}
  	else
! 		return -1;
  
  	return 0;
  }	/* DecodeNumber() */
--- 2379,2447 ----
  	 ***/
  	else if (flen >= 4)
  	{
! 		/* 
! 		 * If no month or day, start of YYYY-MM-DD
! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
! 		 * If neither case, throw an error
! 		 */
  
! 		if ((!(fmask & DTK_M(YEAR)))
! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
! 				||
! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
  		{
! 			*tmask = DTK_M(YEAR);
! 			tm->tm_year = val;
  		}
! 		else
! 			return -1;
  	}
! 	/* If we already have a day AND month, must be a 2-digit year */
! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 		*is2digits = TRUE;
  	}
! 
! 	/* If we already have a year and a month, must be day */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
! 		return -1;
! 	/* If have year or day, set the month */
! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
  	{
+ 		/* Do not allow month to roll over */
+ 		if (val > 12)
+ 			return -1;
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	/* If have a month, set the day */
! 	else if ((fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* If using EuroDates, this must be the day, otherwise month */
! 	else if (EuroDates)
  	{
! 		*tmask = DTK_M(DAY);
! 		tm->tm_mday = val;
  	}
  	else
! 	{
! 		/* Do not allow month to roll over */
! 		if (val > 12)
! 			return -1;
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message


> I believe this conditional is incorrect.  The second part should be DTK_M(DAY).

Thank you - that is correct. Revised patch below.




Index: datetime.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
retrieving revision 1.106
diff -c -r1.106 datetime.c
*** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
--- datetime.c	30 Jun 2003 17:26:22 -0000
***************
*** 2379,2440 ****
  	 ***/
  	else if (flen >= 4)
  	{
! 		*tmask = DTK_M(YEAR);
  
! 		/* already have a year? then see if we can substitute... */
! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  		{
! 			tm->tm_mday = tm->tm_year;
! 			*tmask = DTK_M(DAY);
  		}
! 
! 		tm->tm_year = val;
  	}
! 
! 	/* already have year? then could be month */
! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
  	}
! 	/* no year and EuroDates enabled? then could be day */
! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	else if ((!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	else if ((!(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 
! 	/*
! 	 * Check for 2 or 4 or more digits, but currently we reach here only
! 	 * if two digits. - thomas 2000-03-28
! 	 */
! 	else if (!(fmask & DTK_M(YEAR))
! 			 && ((flen >= 4) || (flen == 2)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 
! 		/* adjust ONLY if exactly two digits... */
! 		*is2digits = (flen == 2);
  	}
  	else
! 		return -1;
  
  	return 0;
  }	/* DecodeNumber() */
--- 2379,2447 ----
  	 ***/
  	else if (flen >= 4)
  	{
! 		/* 
! 		 * If no month or day, start of YYYY-MM-DD
! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
! 		 * If neither case, throw an error
! 		 */
  
! 		if ((!(fmask & DTK_M(YEAR)))
! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
! 				||
! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
  		{
! 			*tmask = DTK_M(YEAR);
! 			tm->tm_year = val;
  		}
! 		else
! 			return -1;
  	}
! 	/* If we already have a day AND month, must be a 2-digit year */
! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 		*is2digits = TRUE;
  	}
! 
! 	/* If we already have a year and a month, must be day */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
! 		return -1;
! 	/* If have year or day, set the month */
! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
  	{
+ 		/* Do not allow month to roll over */
+ 		if (val > 12)
+ 			return -1;
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	/* If have a month, set the day */
! 	else if ((fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* If using EuroDates, this must be the day, otherwise month */
! 	else if (EuroDates)
  	{
! 		*tmask = DTK_M(DAY);
! 		tm->tm_mday = val;
  	}
  	else
! 	{
! 		/* Do not allow month to roll over */
! 		if (val > 12)
! 			return -1;
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
! 	}
  
  	return 0;
  }	/* DecodeNumber() */





--
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200307010916
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
DivxA+RBcivkseNS/yvzc/0=
=mris
-----END PGP SIGNATURE-----

! 	}
  
  	return 0;
  }	/* DecodeNumber() */





--
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200307010916
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
DivxA+RBcivkseNS/yvzc/0=
=mris
-----END PGP SIGNATURE-----




Tue,  1 Jul 2003 13:21:58 -0000
greg@turnstep.com
Re: Datetime patch

Your patch has been added to the PostgreSQL unapplied patches list at:

	http://momjian.postgresql.org/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

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


greg@turnstep.com wrote:
[ There is text before PGP section. ]
> 
[ PGP not available, raw data follows ]
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> > I believe this conditional is incorrect.  The second part should be DTK_M(DAY).
> 
> Thank you - that is correct. Revised patch below.
> 
> 
> 
> 
> Index: datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.106
> diff -c -r1.106 datetime.c
> *** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
> --- datetime.c	30 Jun 2003 17:26:22 -0000
> ***************
> *** 2379,2440 ****
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		*tmask = DTK_M(YEAR);
>   
> ! 		/* already have a year? then see if we can substitute... */
> ! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
> ! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
>   		{
> ! 			tm->tm_mday = tm->tm_year;
> ! 			*tmask = DTK_M(DAY);
>   		}
> ! 
> ! 		tm->tm_year = val;
>   	}
> ! 
> ! 	/* already have year? then could be month */
> ! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
>   	}
> ! 	/* no year and EuroDates enabled? then could be day */
> ! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
> ! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 
> ! 	/*
> ! 	 * Check for 2 or 4 or more digits, but currently we reach here only
> ! 	 * if two digits. - thomas 2000-03-28
> ! 	 */
> ! 	else if (!(fmask & DTK_M(YEAR))
> ! 			 && ((flen >= 4) || (flen == 2)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 
> ! 		/* adjust ONLY if exactly two digits... */
> ! 		*is2digits = (flen == 2);
>   	}
>   	else
> ! 		return -1;
>   
>   	return 0;
>   }	/* DecodeNumber() */
> --- 2379,2447 ----
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		/* 
> ! 		 * If no month or day, start of YYYY-MM-DD
> ! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
> ! 		 * If neither case, throw an error
> ! 		 */
>   
> ! 		if ((!(fmask & DTK_M(YEAR)))
> ! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
> ! 				||
> ! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
>   		{
> ! 			*tmask = DTK_M(YEAR);
> ! 			tm->tm_year = val;
>   		}
> ! 		else
> ! 			return -1;
>   	}
> ! 	/* If we already have a day AND month, must be a 2-digit year */
> ! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 		*is2digits = TRUE;
>   	}
> ! 
> ! 	/* If we already have a year and a month, must be day */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
> ! 		return -1;
> ! 	/* If have year or day, set the month */
> ! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
>   	{
> + 		/* Do not allow month to roll over */
> + 		if (val > 12)
> + 			return -1;
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	/* If have a month, set the day */
> ! 	else if ((fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* If using EuroDates, this must be the day, otherwise month */
> ! 	else if (EuroDates)
>   	{
> ! 		*tmask = DTK_M(DAY);
> ! 		tm->tm_mday = val;
>   	}
>   	else
> ! 	{
> ! 		/* Do not allow month to roll over */
> ! 		if (val > 12)
> ! 			return -1;
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;-----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> > I believe this conditional is incorrect.  The second part should be DTK_M(DAY).
> 
> Thank you - that is correct. Revised patch below.
> 
> 
> 
> 
> Index: datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.106
> diff -c -r1.106 datetime.c
> *** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
> --- datetime.c	30 Jun 2003 17:26:22 -0000
> ***************
> *** 2379,2440 ****
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		*tmask = DTK_M(YEAR);
>   
> ! 		/* already have a year? then see if we can substitute... */
> ! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
> ! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
>   		{
> ! 			tm->tm_mday = tm->tm_year;
> ! 			*tmask = DTK_M(DAY);
>   		}
> ! 
> ! 		tm->tm_year = val;
>   	}
> ! 
> ! 	/* already have year? then could be month */
> ! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
>   	}
> ! 	/* no year and EuroDates enabled? then could be day */
> ! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
> ! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 
> ! 	/*
> ! 	 * Check for 2 or 4 or more digits, but currently we reach here only
> ! 	 * if two digits. - thomas 2000-03-28
> ! 	 */
> ! 	else if (!(fmask & DTK_M(YEAR))
> ! 			 && ((flen >= 4) || (flen == 2)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 
> ! 		/* adjust ONLY if exactly two digits... */
> ! 		*is2digits = (flen == 2);
>   	}
>   	else
> ! 		return -1;
>   
>   	return 0;
>   }	/* DecodeNumber() */
> --- 2379,2447 ----
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		/* 
> ! 		 * If no month or day, start of YYYY-MM-DD
> ! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
> ! 		 * If neither case, throw an error
> ! 		 */
>   
> ! 		if ((!(fmask & DTK_M(YEAR)))
> ! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
> ! 				||
> ! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
>   		{
> ! 			*tmask = DTK_M(YEAR);
> ! 			tm->tm_year = val;
>   		}
> ! 		else
> ! 			return -1;
>   	}
> ! 	/* If we already have a day AND month, must be a 2-digit year */
> ! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 		*is2digits = TRUE;
>   	}
> ! 
> ! 	/* If we already have a year and a month, must be day */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
> ! 		return -1;
> ! 	/* If have year or day, set the month */
> ! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
>   	{
> + 		/* Do not allow month to roll over */
> + 		if (val > 12)
> + 			return -1;
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	/* If have a month, set the day */
> ! 	else if ((fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* If using EuroDates, this must be the day, otherwise month */
> ! 	else if (EuroDates)
>   	{
> ! 		*tmask = DTK_M(DAY);
> ! 		tm->tm_mday = val;
>   	}
>   	else
> ! 	{
> ! 		/* Do not allow month to roll over */
> ! 		if (val > 12)
> ! 			return -1;
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
> ! 	}
>   
>   	return 0;
>   }	/* DecodeNumber() */
> 
> 
> 
> 
> 
> --
> Greg Sabino Mullane greg@turnstep.com
> PGP Key: 0x14964AC8 200307010916
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
> 
> iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
> DivxA+RBcivkseNS/yvzc/0=
> =mris
> -----END PGP SIGNATURE-----
> 
> ! 	}
>   
>   	return 0;
>   }	/* DecodeNumber() */
> 
> 
> 
> 
> 
> --
> Greg Sabino Mullane greg@turnstep.com
> PGP Key: 0x14964AC8 200307010916
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
> 
> iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
> DivxA+RBcivkseNS/yvzc/0=
> =mris
> -----END PGP SIGNATURE-----
> 
> 
> 
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
>       subscribe-nomail command to majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly
> 
[ Decrypting message... End of raw data. ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Sat, 19 Jul 2003 22:40:52 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch

Greg, does this patch still reject dates with month/days out of range? 
I see some of the range checks are removed.  Where those checks used
only for the month/date detection?

For example, I don't see the <= 31 checks in there anymore.

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

greg@turnstep.com wrote:
[ There is text before PGP section. ]
> 
[ PGP not available, raw data follows ]
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> > I believe this conditional is incorrect.  The second part should be DTK_M(DAY).
> 
> Thank you - that is correct. Revised patch below.
> 
> 
> 
> 
> Index: datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.106
> diff -c -r1.106 datetime.c
> *** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
> --- datetime.c	30 Jun 2003 17:26:22 -0000
> ***************
> *** 2379,2440 ****
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		*tmask = DTK_M(YEAR);
>   
> ! 		/* already have a year? then see if we can substitute... */
> ! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
> ! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
>   		{
> ! 			tm->tm_mday = tm->tm_year;
> ! 			*tmask = DTK_M(DAY);
>   		}
> ! 
> ! 		tm->tm_year = val;
>   	}
> ! 
> ! 	/* already have year? then could be month */
> ! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
>   	}
> ! 	/* no year and EuroDates enabled? then could be day */
> ! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
> ! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 
> ! 	/*
> ! 	 * Check for 2 or 4 or more digits, but currently we reach here only
> ! 	 * if two digits. - thomas 2000-03-28
> ! 	 */
> ! 	else if (!(fmask & DTK_M(YEAR))
> ! 			 && ((flen >= 4) || (flen == 2)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 
> ! 		/* adjust ONLY if exactly two digits... */
> ! 		*is2digits = (flen == 2);
>   	}
>   	else
> ! 		return -1;
>   
>   	return 0;
>   }	/* DecodeNumber() */
> --- 2379,2447 ----
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		/* 
> ! 		 * If no month or day, start of YYYY-MM-DD
> ! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
> ! 		 * If neither case, throw an error
> ! 		 */
>   
> ! 		if ((!(fmask & DTK_M(YEAR)))
> ! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
> ! 				||
> ! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
>   		{
> ! 			*tmask = DTK_M(YEAR);
> ! 			tm->tm_year = val;
>   		}
> ! 		else
> ! 			return -1;
>   	}
> ! 	/* If we already have a day AND month, must be a 2-digit year */
> ! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 		*is2digits = TRUE;
>   	}
> ! 
> ! 	/* If we already have a year and a month, must be day */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
> ! 		return -1;
> ! 	/* If have year or day, set the month */
> ! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
>   	{
> + 		/* Do not allow month to roll over */
> + 		if (val > 12)
> + 			return -1;
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	/* If have a month, set the day */
> ! 	else if ((fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* If using EuroDates, this must be the day, otherwise month */
> ! 	else if (EuroDates)
>   	{
> ! 		*tmask = DTK_M(DAY);
> ! 		tm->tm_mday = val;
>   	}
>   	else
> ! 	{
> ! 		/* Do not allow month to roll over */
> ! 		if (val > 12)
> ! 			return -1;
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;-----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> > I believe this conditional is incorrect.  The second part should be DTK_M(DAY).
> 
> Thank you - that is correct. Revised patch below.
> 
> 
> 
> 
> Index: datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.106
> diff -c -r1.106 datetime.c
> *** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
> --- datetime.c	30 Jun 2003 17:26:22 -0000
> ***************
> *** 2379,2440 ****
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		*tmask = DTK_M(YEAR);
>   
> ! 		/* already have a year? then see if we can substitute... */
> ! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
> ! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
>   		{
> ! 			tm->tm_mday = tm->tm_year;
> ! 			*tmask = DTK_M(DAY);
>   		}
> ! 
> ! 		tm->tm_year = val;
>   	}
> ! 
> ! 	/* already have year? then could be month */
> ! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
>   	}
> ! 	/* no year and EuroDates enabled? then could be day */
> ! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
> ! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 
> ! 	/*
> ! 	 * Check for 2 or 4 or more digits, but currently we reach here only
> ! 	 * if two digits. - thomas 2000-03-28
> ! 	 */
> ! 	else if (!(fmask & DTK_M(YEAR))
> ! 			 && ((flen >= 4) || (flen == 2)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 
> ! 		/* adjust ONLY if exactly two digits... */
> ! 		*is2digits = (flen == 2);
>   	}
>   	else
> ! 		return -1;
>   
>   	return 0;
>   }	/* DecodeNumber() */
> --- 2379,2447 ----
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		/* 
> ! 		 * If no month or day, start of YYYY-MM-DD
> ! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
> ! 		 * If neither case, throw an error
> ! 		 */
>   
> ! 		if ((!(fmask & DTK_M(YEAR)))
> ! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
> ! 				||
> ! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
>   		{
> ! 			*tmask = DTK_M(YEAR);
> ! 			tm->tm_year = val;
>   		}
> ! 		else
> ! 			return -1;
>   	}
> ! 	/* If we already have a day AND month, must be a 2-digit year */
> ! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 		*is2digits = TRUE;
>   	}
> ! 
> ! 	/* If we already have a year and a month, must be day */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
> ! 		return -1;
> ! 	/* If have year or day, set the month */
> ! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
>   	{
> + 		/* Do not allow month to roll over */
> + 		if (val > 12)
> + 			return -1;
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	/* If have a month, set the day */
> ! 	else if ((fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* If using EuroDates, this must be the day, otherwise month */
> ! 	else if (EuroDates)
>   	{
> ! 		*tmask = DTK_M(DAY);
> ! 		tm->tm_mday = val;
>   	}
>   	else
> ! 	{
> ! 		/* Do not allow month to roll over */
> ! 		if (val > 12)
> ! 			return -1;
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
> ! 	}
>   
>   	return 0;
>   }	/* DecodeNumber() */
> 
> 
> 
> 
> 
> --
> Greg Sabino Mullane greg@turnstep.com
> PGP Key: 0x14964AC8 200307010916
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
> 
> iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
> DivxA+RBcivkseNS/yvzc/0=
> =mris
> -----END PGP SIGNATURE-----
> 
> ! 	}
>   
>   	return 0;
>   }	/* DecodeNumber() */
> 
> 
> 
> 
> 
> --
> Greg Sabino Mullane greg@turnstep.com
> PGP Key: 0x14964AC8 200307010916
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
> 
> iD8DBQE/AYp/vJuQZxSWSsgRAvaLAKCG9si7HhJLOnVIbhPKCo/bP6HMOACfRtlq
> DivxA+RBcivkseNS/yvzc/0=
> =mris
> -----END PGP SIGNATURE-----
> 
> 
> 
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
>       subscribe-nomail command to majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly
> 
[ Decrypting message... End of raw data. ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Fri, 25 Jul 2003 10:55:46 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


> Greg, does this patch still reject dates with month/days out of range? 
> I see some of the range checks are removed.  Where those checks used
> only for the month/date detection?

Yes and yes. The range rejection in the previous code only allowed an 
invalid date to be detected earlier than it would have otherwise. It is 
the responsibility of the code following it to determine the validity of 
the date we construct here.

Some very minimal checking could be put into place, but it would just be 
a small subset of the full checking that occurs later on, so it seemed 
better to leave all that logic in one place.


- --
Greg Sabino Mullane greg@turnstep.com
PGP Key: 0x14964AC8 200307251104
-----BEGIN PGP SIGNATURE-----
Comment: http://www.turnstep.com/pgp.html

iD8DBQE/IUhQvJuQZxSWSsgRAthUAJ42qjxGOVRX/Ak/RF5z0KlZu2CUQwCfeYoy
IxRZhzqzNWJM8NeqFKLGesE=
=4rCE
-----END PGP SIGNATURE-----



Fri, 25 Jul 2003 15:12:13 -0000
greg@turnstep.com
Re: Datetime patch
OK, I tested the patch and found that it still does proper date validity
checking:
	
	test=> select '2003-09-31'::date;
	ERROR:  Bad date external representation '2003-09-31'

I did find the following change in the regression tests:

  INSERT INTO TIMESTAMP_TBL VALUES ('02-10-1997 17:32:01 PST');
  INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 PST');
  INSERT INTO TIMESTAMP_TBL VALUES ('97FEB10 5:32:01PM UTC');
+ ERROR:  Bad timestamp external representation '97FEB10 5:32:01PM UTC'
  INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
+ ERROR:  Bad timestamp external representation '97/02/10 17:32:01 UTC'
  INSERT INTO TIMESTAMP_TBL VALUES ('97.041 17:32:01 UTC');
+ ERROR:  Bad timestamp external representation '97.041 17:32:01 UTC'
 
I didn't know we supported the first format, though it looks nice.

I don't think we want to support the second format, so the error is
correct.

The last format looks like it is year.days_from_year_start, which I also
didn't know we supported, but again looks interesting, if strange.

Comments?

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

greg@turnstep.com wrote:
[ There is text before PGP section. ]
> 
[ PGP not available, raw data follows ]
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> > I believe this conditional is incorrect.  The second part should be DTK_M(DAY).
> 
> Thank you - that is correct. Revised patch below.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Index: datetime.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
retrieving revision 1.106
diff -c -r1.106 datetime.c
*** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
--- datetime.c	30 Jun 2003 17:26:22 -0000
***************
*** 2379,2440 ****
  	 ***/
  	else if (flen >= 4)
  	{
! 		*tmask = DTK_M(YEAR);
  
! 		/* already have a year? then see if we can substitute... */
! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  		{
! 			tm->tm_mday = tm->tm_year;
! 			*tmask = DTK_M(DAY);
  		}
! 
! 		tm->tm_year = val;
  	}
! 
! 	/* already have year? then could be month */
! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
  	}
! 	/* no year and EuroDates enabled? then could be day */
! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	else if ((!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	else if ((!(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 
! 	/*
! 	 * Check for 2 or 4 or more digits, but currently we reach here only
! 	 * if two digits. - thomas 2000-03-28
! 	 */
! 	else if (!(fmask & DTK_M(YEAR))
! 			 && ((flen >= 4) || (flen == 2)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 
! 		/* adjust ONLY if exactly two digits... */
! 		*is2digits = (flen == 2);
  	}
  	else
! 		return -1;
  
  	return 0;
  }	/* DecodeNumber() */
--- 2379,2447 ----
  	 ***/
  	else if (flen >= 4)
  	{
! 		/* 
! 		 * If no month or day, start of YYYY-MM-DD
! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
! 		 * If neither case, throw an error
! 		 */
  
! 		if ((!(fmask & DTK_M(YEAR)))
! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
! 				||
! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
  		{
! 			*tmask = DTK_M(YEAR);
! 			tm->tm_year = val;
  		}
! 		else
! 			return -1;
  	}
! 	/* If we already have a day AND month, must be a 2-digit year */
! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 		*is2digits = TRUE;
  	}
! 
! 	/* If we already have a year and a month, must be day */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
! 		return -1;
! 	/* If have year or day, set the month */
! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
  	{
+ 		/* Do not allow month to roll over */
+ 		if (val > 12)
+ 			return -1;
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	/* If have a month, set the day */
! 	else if ((fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* If using EuroDates, this must be the day, otherwise month */
! 	else if (EuroDates)
  	{
! 		*tmask = DTK_M(DAY);
! 		tm->tm_mday = val;
  	}
  	else
! 	{
! 		/* Do not allow month to roll over */
! 		if (val > 12)
! 			return -1;
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message


> I believe this conditional is incorrect.  The second part should be DTK_M(DAY).

Thank you - that is correct. Revised patch below.




Index: datetime.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
retrieving revision 1.106
diff -c -r1.106 datetime.c
*** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
--- datetime.c	30 Jun 2003 17:26:22 -0000
***************
*** 2379,2440 ****
  	 ***/
  	else if (flen >= 4)
  	{
! 		*tmask = DTK_M(YEAR);
  
! 		/* already have a year? then see if we can substitute... */
! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
  		{
! 			tm->tm_mday = tm->tm_year;
! 			*tmask = DTK_M(DAY);
  		}
! 
! 		tm->tm_year = val;
  	}
! 
! 	/* already have year? then could be month */
! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
  	}
! 	/* no year and EuroDates enabled? then could be day */
! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	else if ((!(fmask & DTK_M(MONTH)))
! 			 && ((val >= 1) && (val <= 12)))
  	{
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	else if ((!(fmask & DTK_M(DAY)))
! 			 && ((val >= 1) && (val <= 31)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 
! 	/*
! 	 * Check for 2 or 4 or more digits, but currently we reach here only
! 	 * if two digits. - thomas 2000-03-28
! 	 */
! 	else if (!(fmask & DTK_M(YEAR))
! 			 && ((flen >= 4) || (flen == 2)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 
! 		/* adjust ONLY if exactly two digits... */
! 		*is2digits = (flen == 2);
  	}
  	else
! 		return -1;
  
  	return 0;
  }	/* DecodeNumber() */
--- 2379,2447 ----
  	 ***/
  	else if (flen >= 4)
  	{
! 		/* 
! 		 * If no month or day, start of YYYY-MM-DD
! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
! 		 * If neither case, throw an error
! 		 */
  
! 		if ((!(fmask & DTK_M(YEAR)))
! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
! 				||
! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
  		{
! 			*tmask = DTK_M(YEAR);
! 			tm->tm_year = val;
  		}
! 		else
! 			return -1;
  	}
! 	/* If we already have a day AND month, must be a 2-digit year */
! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
  	{
! 		*tmask = DTK_M(YEAR);
! 		tm->tm_year = val;
! 		*is2digits = TRUE;
  	}
! 
! 	/* If we already have a year and a month, must be day */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(DAY)))
! 		return -1;
! 	/* If have year or day, set the month */
! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
  	{
+ 		/* Do not allow month to roll over */
+ 		if (val > 12)
+ 			return -1;
  		*tmask = DTK_M(MONTH);
  		tm->tm_mon = val;
  	}
! 	/* If have a month, set the day */
! 	else if ((fmask & DTK_M(MONTH)))
  	{
  		*tmask = DTK_M(DAY);
  		tm->tm_mday = val;
  	}
! 	/* If using EuroDates, this must be the day, otherwise month */
! 	else if (EuroDates)
  	{
! 		*tmask = DTK_M(DAY);
! 		tm->tm_mday = val;
  	}
  	else
! 	{
! 		/* Do not allow month to roll over */
! 		if (val > 12)
! 			return -1;
! 		*tmask = DTK_M(MONTH);
! 		tm->tm_mon = val;
! 	}
  
  	return 0;
  }	/* DecodeNumber() */
Fri, 25 Jul 2003 13:28:14 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch
greg@turnstep.com writes:
> Some very minimal checking could be put into place, but it would just be 
> a small subset of the full checking that occurs later on, so it seemed 
> better to leave all that logic in one place.

Then why not move the rangechecks on month to the full check code too?
(It sure looks like you've lost the defense against month=0, btw.)

BTW, it seems to me that part of the original thread about this issue
included a demonstration that Postgres would sometimes take out-of-range
dates.  That may have just been with respect to to_date() ... but are
you sure there are no other paths for parsing a date spec in the main
date/time code?

			regards, tom lane

Fri, 25 Jul 2003 15:19:31 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Datetime patch 

I did a little more looking at this...

> 	test=> select '2003-09-31'::date;
> 	ERROR:  Bad date external representation '2003-09-31'
> 
> I did find the following change in the regression tests:
> 
>   INSERT INTO TIMESTAMP_TBL VALUES ('02-10-1997 17:32:01 PST');
>   INSERT INTO TIMESTAMP_TBL VALUES ('19970210 173201 PST');
>   INSERT INTO TIMESTAMP_TBL VALUES ('97FEB10 5:32:01PM UTC');
> + ERROR:  Bad timestamp external representation '97FEB10 5:32:01PM UTC'

We still accept 10FEB97, which is a more common format.  Seems this now
fails because the year/day detection is not gone, which is fine, I
think.  This works as expected:

	test=> select '01FEB03'::date;
	    date
	------------
	 2003-02-01
	(1 row)

>   INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
> + ERROR:  Bad timestamp external representation '97/02/10 17:32:01 UTC'

Again, this one should fail.

Seems these are all related to two-digit years.  This works when
specifying the year as 1997:

test=> select '97/02/10 17:32:01 UTC'::date;
ERROR:  Bad date external representation '97/02/10 17:32:01 UTC'
test=> select '1997/02/10 17:32:01 UTC'::date;
    date
------------
 1997-02-10
(1 row)

>   INSERT INTO TIMESTAMP_TBL VALUES ('97.041 17:32:01 UTC');
> + ERROR:  Bad timestamp external representation '97.041 17:32:01 UTC'

I just played around with this one and got it working:

	test=> select '2004.041'::date;
	    date
	------------
	 2004-02-10
	(1 row)
	
	test=> select '2004.001'::date;
	    date
	------------
	 2004-01-01
	(1 row)

Seems you now need a 4-digit year to specify this format.  Also
interesting is that the day must be three digits.

As part of the patch application, I will modify the years to have the
leading '19' so the regression tests will pass.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Fri, 25 Jul 2003 15:22:46 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch
Bruce Momjian <pgman@candle.pha.pa.us> writes:
>> INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
>> + ERROR:  Bad timestamp external representation '97/02/10 17:32:01 UTC'

> Again, this one should fail.

It should?  I think you're gonna have a lot of unhappy users if there's
no way to persuade Postgres to take that.  This is the same point we
were discussing on the phone earlier.

It might be that the cleanest way to do things is to extend the
input-side DateStyle to a three-way switch, "US" (accept mm/dd/yy)
"Euro" (accept dd/mm/yy) and a third case that accepts yy/mm/dd.
But I do not believe we can get away with deciding that common date
formats aren't common.

			regards, tom lane

Fri, 25 Jul 2003 15:33:45 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Datetime patch 
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> >> INSERT INTO TIMESTAMP_TBL VALUES ('97/02/10 17:32:01 UTC');
> >> + ERROR:  Bad timestamp external representation '97/02/10 17:32:01 UTC'
> 
> > Again, this one should fail.
> 
> It should?  I think you're gonna have a lot of unhappy users if there's
> no way to persuade Postgres to take that.  This is the same point we
> were discussing on the phone earlier.
> 
> It might be that the cleanest way to do things is to extend the
> input-side DateStyle to a three-way switch, "US" (accept mm/dd/yy)
> "Euro" (accept dd/mm/yy) and a third case that accepts yy/mm/dd.
> But I do not believe we can get away with deciding that common date
> formats aren't common.

I have never seen YY/MM/DD, only YYYY-MM-DD.  The huge problem is
deciding out how to decode 03-02-01.  I think we have to require the
century for those.  The big point is that yy-mm-dd only works for years
> 31.  For current dates, you can't specify it because it is already
taken as month first or day first, so I don't see how anyone could be
already using such a format for input.

If we go with a three-way, I am afraid things get confusing because you
have a xx/xx/xx date input that is year first, while I think we have to
insist on xxxx/xx/xx for dates.  We can try it and see what reports we
get.  I don't even know what we would call such a three-way because I
have never seen dates in that format.

If that is the only issue, I can ask on general, but I doubt someone is
going to pipe up.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Fri, 25 Jul 2003 15:46:08 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> I have never seen YY/MM/DD, only YYYY-MM-DD.

You have apparently forgotten what was standard practice just a few
years ago.

> The huge problem is
> deciding out how to decode 03-02-01.  I think we have to require the
> century for those.

No, the entire point is to drive it off datestyle, *not* off the input
value ranges.

> If that is the only issue, I can ask on general, but I doubt someone is
> going to pipe up.

I really dislike the idea that we are going to legislate this behavior
in a three-person discussion on -patches.  The people who will be
screaming about it don't read -patches.

			regards, tom lane

Fri, 25 Jul 2003 15:51:40 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Datetime patch 

[ Moved to hackers.]

(The discussion is whether we should support dates of the format
yy-mm-dd.  We already support yyyy-mm-dd, but we have code that would
see 97-01-01 and detect the first part was a year.)

Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > I have never seen YY/MM/DD, only YYYY-MM-DD.
> 
> You have apparently forgotten what was standard practice just a few
> years ago.

Well, seeing as it hasn't worked for a date in three years, I don't see
how anyone could be using it unless they are only entering dates
per-2000, which seems unlikely.  It will be come useful again in 2032.

> > The huge problem is
> > deciding out how to decode 03-02-01.  I think we have to require the
> > century for those.
> 
> No, the entire point is to drive it off datestyle, *not* off the input
> value ranges.

If they supply a four-digit year, we assume yyyy-mm-dd, if not we follow
datestyle.  I can see someone wanting yy-mm-dd, but then we need a _new_
setting to control that, because the detection code for a year being >
31 just doesn't work in 2003.

I see what you are saying, that using the four-digit leading as
specifying a year is arbitrary, but it does allow us to accept both ISO
and US/European dates cleanly.  I guess the question is whether it is
worth allowing yy-mm-dd using a _new_ setting.  I still think we will
need the 4-digit rule for ordinary users.

The driving thing here was consistency, so the same session didn't
accept 19-8-03 and 8-19-03 while other dates like 01-01-03 were
following datestyle.  I don't see how the 4-digit rule actually is
inconsistent in that way.

> > If that is the only issue, I can ask on general, but I doubt someone is
> > going to pipe up.
> 
> I really dislike the idea that we are going to legislate this behavior
> in a three-person discussion on -patches.  The people who will be
> screaming about it don't read -patches.

I would be shocked to find someone screaming.  I have asked on general,
and if someone come up with a valid use for it, we can adjust it, even
during beta.  We can't tighten during beta, but we can loosen.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Fri, 25 Jul 2003 16:12:24 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: [PATCHES] Datetime patch

The newest version of this patch was applied by Tom.  Thanks.

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

greg@turnstep.com wrote:
[ There is text before PGP section. ]
> 
[ PGP not available, raw data follows ]
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> NotDashEscaped: You need GnuPG to verify this message
> 
> 
> 
> Here is another attempt at the datetime fix, to stop the ambiguity 
> for dates like "01-13-2003". I put the > 12 month validation in because 
> otherwise it is still read in as a "month", but it rolls over. 
> In other words, '2003-14-03' becomes '2004-02-03'
> 
> 
> 
> --
> Greg Sabino Mullane greg@turnstep.com
> PGP Key: 0x14964AC8 200306301327
> 
> 
> 
> 
> 
> Index: datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.106
> diff -c -r1.106 datetime.c
> *** datetime.c	25 Jun 2003 21:14:14 -0000	1.106
> --- datetime.c	30 Jun 2003 17:26:22 -0000
> ***************
> *** 2379,2440 ****
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		*tmask = DTK_M(YEAR);
>   
> ! 		/* already have a year? then see if we can substitute... */
> ! 		if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(DAY)))
> ! 			&& ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
>   		{
> ! 			tm->tm_mday = tm->tm_year;
> ! 			*tmask = DTK_M(DAY);
>   		}
> ! 
> ! 		tm->tm_year = val;
>   	}
> ! 
> ! 	/* already have year? then could be month */
> ! 	else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
>   	}
> ! 	/* no year and EuroDates enabled? then could be day */
> ! 	else if ((EuroDates || (fmask & DTK_M(MONTH)))
> ! 			 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(MONTH)))
> ! 			 && ((val >= 1) && (val <= 12)))
>   	{
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	else if ((!(fmask & DTK_M(DAY)))
> ! 			 && ((val >= 1) && (val <= 31)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 
> ! 	/*
> ! 	 * Check for 2 or 4 or more digits, but currently we reach here only
> ! 	 * if two digits. - thomas 2000-03-28
> ! 	 */
> ! 	else if (!(fmask & DTK_M(YEAR))
> ! 			 && ((flen >= 4) || (flen == 2)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 
> ! 		/* adjust ONLY if exactly two digits... */
> ! 		*is2digits = (flen == 2);
>   	}
>   	else
> ! 		return -1;
>   
>   	return 0;
>   }	/* DecodeNumber() */
> --- 2379,2447 ----
>   	 ***/
>   	else if (flen >= 4)
>   	{
> ! 		/* 
> ! 		 * If no month or day, start of YYYY-MM-DD
> ! 		 * If have month AND day, end of MM-DD-YYYY or DD-MM-YYYY
> ! 		 * If neither case, throw an error
> ! 		 */
>   
> ! 		if ((!(fmask & DTK_M(YEAR)))
> ! 			&& (((!(fmask & DTK_M(DAY))) && (!(fmask & DTK_M(MONTH))))
> ! 				||
> ! 				((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))))
>   		{
> ! 			*tmask = DTK_M(YEAR);
> ! 			tm->tm_year = val;
>   		}
> ! 		else
> ! 			return -1;
>   	}
> ! 	/* If we already have a day AND month, must be a 2-digit year */
> ! 	else if ((fmask & DTK_M(DAY)) && (fmask & DTK_M(MONTH)))
>   	{
> ! 		*tmask = DTK_M(YEAR);
> ! 		tm->tm_year = val;
> ! 		*is2digits = TRUE;
>   	}
> ! 
> ! 	/* If we already have a year and a month, must be day */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* A year and a day is currently an error, as YYYY-DD-MM is not allowed */
> ! 	else if ((fmask & DTK_M(YEAR)) && (fmask & DTK_M(MONTH)))
> ! 		return -1;
> ! 	/* If have year or day, set the month */
> ! 	else if ((fmask & DTK_M(YEAR)) || (fmask & DTK_M(DAY)))
>   	{
> + 		/* Do not allow month to roll over */
> + 		if (val > 12)
> + 			return -1;
>   		*tmask = DTK_M(MONTH);
>   		tm->tm_mon = val;
>   	}
> ! 	/* If have a month, set the day */
> ! 	else if ((fmask & DTK_M(MONTH)))
>   	{
>   		*tmask = DTK_M(DAY);
>   		tm->tm_mday = val;
>   	}
> ! 	/* If using EuroDates, this must be the day, otherwise month */
> ! 	else if (EuroDates)
>   	{
> ! 		*tmask = DTK_M(DAY);
> ! 		tm->tm_mday = val;
>   	}
>   	else
> ! 	{
> ! 		/* Do not allow month to roll over */
> ! 		if (val > 12)
> ! 			return -1;
> ! 		*tmask = DTK_M(MONTH);
> ! 		tm->tm_mon = val;
> ! 	}
>   
>   	return 0;
>   }	/* DecodeNumber() */
> 
> 
> 
> 
> -----BEGIN PGP SIGNATURE-----
> Comment: http://www.turnstep.com/pgp.html
> 
> iD8DBQE/AHNDvJuQZxSWSsgRApuiAKDB5CcBTxwQBnOdRkzPpLCOKHMmNgCeLJ//
> Nz5sB+KyQUWv+MEVLXztBJw=
> =kXb4
> -----END PGP SIGNATURE-----
> 
> 
> 
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 8: explain analyze is your friend
> 
[ Decrypting message... End of raw data. ]

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Tue, 29 Jul 2003 21:21:33 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Datetime patch