datetime.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,681 行 · 第 1/5 页

C
2,681
字号
						return DTERR_FIELD_OVERFLOW;					/*					 * only a few kinds are allowed to have an embedded					 * decimal					 */					if (*cp == '.')						switch (ptype)						{							case DTK_JULIAN:							case DTK_TIME:							case DTK_SECOND:								break;							default:								return DTERR_BAD_FORMAT;								break;						}					else if (*cp != '\0')						return DTERR_BAD_FORMAT;					switch (ptype)					{						case DTK_YEAR:							tm->tm_year = val;							tmask = DTK_M(YEAR);							break;						case DTK_MONTH:							/*							 * already have a month and hour? then assume							 * minutes							 */							if ((fmask & DTK_M(MONTH)) != 0 &&								(fmask & DTK_M(HOUR)) != 0)							{								tm->tm_min = val;								tmask = DTK_M(MINUTE);							}							else							{								tm->tm_mon = val;								tmask = DTK_M(MONTH);							}							break;						case DTK_DAY:							tm->tm_mday = val;							tmask = DTK_M(DAY);							break;						case DTK_HOUR:							tm->tm_hour = val;							tmask = DTK_M(HOUR);							break;						case DTK_MINUTE:							tm->tm_min = val;							tmask = DTK_M(MINUTE);							break;						case DTK_SECOND:							tm->tm_sec = val;							tmask = DTK_M(SECOND);							if (*cp == '.')							{								double		frac;								frac = strtod(cp, &cp);								if (*cp != '\0')									return DTERR_BAD_FORMAT;#ifdef HAVE_INT64_TIMESTAMP								*fsec = rint(frac * 1000000);#else								*fsec = frac;#endif								tmask = DTK_ALL_SECS_M;							}							break;						case DTK_TZ:							tmask = DTK_M(TZ);							dterr = DecodeTimezone(field[i], tzp);							if (dterr)								return dterr;							break;						case DTK_JULIAN:							/***							 * previous field was a label for "julian date"?							 ***/							tmask = DTK_DATE_M;							j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);							if (*cp == '.')							{								double		time;								time = strtod(cp, &cp);								if (*cp != '\0')									return DTERR_BAD_FORMAT;								tmask |= DTK_TIME_M;#ifdef HAVE_INT64_TIMESTAMP								dt2time(time * USECS_PER_DAY,								&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);#else								dt2time(time * SECS_PER_DAY,								&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);#endif							}							break;						case DTK_TIME:							/* previous field was "t" for ISO time */							dterr = DecodeNumberField(strlen(field[i]), field[i],													  (fmask | DTK_DATE_M),													  &tmask, tm,													  fsec, &is2digits);							if (dterr < 0)								return dterr;							ftype[i] = dterr;							if (tmask != DTK_TIME_M)								return DTERR_BAD_FORMAT;							break;						default:							return DTERR_BAD_FORMAT;							break;					}					ptype = 0;					*dtype = DTK_DATE;				}				else				{					char	   *cp;					int			flen;					flen = strlen(field[i]);					cp = strchr(field[i], '.');					/* Embedded decimal? */					if (cp != NULL)					{						/*						 * Under limited circumstances, we will accept a						 * date...						 */						if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)						{							dterr = DecodeDate(field[i], fmask,											   &tmask, &is2digits, tm);							if (dterr)								return dterr;						}						/* embedded decimal and several digits before? */						else if (flen - strlen(cp) > 2)						{							/*							 * Interpret as a concatenated date or time Set							 * the type field to allow decoding other fields							 * later. Example: 20011223 or 040506							 */							dterr = DecodeNumberField(flen, field[i],													  (fmask | DTK_DATE_M),													  &tmask, tm,													  fsec, &is2digits);							if (dterr < 0)								return dterr;							ftype[i] = dterr;						}						else							return DTERR_BAD_FORMAT;					}					else if (flen > 4)					{						dterr = DecodeNumberField(flen, field[i],												  (fmask | DTK_DATE_M),												  &tmask, tm,												  fsec, &is2digits);						if (dterr < 0)							return dterr;						ftype[i] = dterr;					}					/* otherwise it is a single date/time field... */					else					{						dterr = DecodeNumber(flen, field[i],											 FALSE,											 (fmask | DTK_DATE_M),											 &tmask, tm,											 fsec, &is2digits);						if (dterr)							return dterr;					}				}				break;			case DTK_STRING:			case DTK_SPECIAL:				type = DecodeSpecial(i, field[i], &val);				if (type == IGNORE_DTF)					continue;				tmask = DTK_M(type);				switch (type)				{					case RESERV:						switch (val)						{							case DTK_CURRENT:								ereport(ERROR,									 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),									  errmsg("date/time value \"current\" is no longer supported")));								return DTERR_BAD_FORMAT;								break;							case DTK_NOW:								tmask = DTK_TIME_M;								*dtype = DTK_TIME;								GetCurrentTimeUsec(tm, fsec, NULL);								break;							case DTK_ZULU:								tmask = (DTK_TIME_M | DTK_M(TZ));								*dtype = DTK_TIME;								tm->tm_hour = 0;								tm->tm_min = 0;								tm->tm_sec = 0;								tm->tm_isdst = 0;								break;							default:								return DTERR_BAD_FORMAT;						}						break;					case DTZMOD:						/*						 * daylight savings time modifier (solves "MET DST"						 * syntax)						 */						tmask |= DTK_M(DTZ);						tm->tm_isdst = 1;						if (tzp == NULL)							return DTERR_BAD_FORMAT;						*tzp += val * MINS_PER_HOUR;						break;					case DTZ:						/*						 * set mask for TZ here _or_ check for DTZ later when						 * getting default timezone						 */						tmask |= DTK_M(TZ);						tm->tm_isdst = 1;						if (tzp == NULL)							return DTERR_BAD_FORMAT;						*tzp = val * MINS_PER_HOUR;						ftype[i] = DTK_TZ;						break;					case TZ:						tm->tm_isdst = 0;						if (tzp == NULL)							return DTERR_BAD_FORMAT;						*tzp = val * MINS_PER_HOUR;						ftype[i] = DTK_TZ;						break;					case IGNORE_DTF:						break;					case AMPM:						mer = val;						break;					case ADBC:						bc = (val == BC);						break;					case UNITS:						tmask = 0;						ptype = val;						break;					case ISOTIME:						tmask = 0;						/***						 * We will need one of the following fields:						 *	DTK_NUMBER should be hhmmss.fff						 *	DTK_TIME should be hh:mm:ss.fff						 *	DTK_DATE should be hhmmss-zz						 ***/						if (i >= nf - 1 ||							(ftype[i + 1] != DTK_NUMBER &&							 ftype[i + 1] != DTK_TIME &&							 ftype[i + 1] != DTK_DATE))							return DTERR_BAD_FORMAT;						ptype = val;						break;					case UNKNOWN_FIELD:						/*						 * Before giving up and declaring error, check to see						 * if it is an all-alpha timezone name.						 */						namedTz = pg_tzset(field[i]);						if (!namedTz)							return DTERR_BAD_FORMAT;						/* we'll apply the zone setting below */						tmask = DTK_M(TZ);						break;					default:						return DTERR_BAD_FORMAT;				}				break;			default:				return DTERR_BAD_FORMAT;		}		if (tmask & fmask)			return DTERR_BAD_FORMAT;		fmask |= tmask;	}				/* end loop over fields */	/* do final checking/adjustment of Y/M/D fields */	dterr = ValidateDate(fmask, is2digits, bc, tm);	if (dterr)		return dterr;	/* handle AM/PM */	if (mer != HR24 && tm->tm_hour > 12)		return DTERR_FIELD_OVERFLOW;	if (mer == AM && tm->tm_hour == 12)		tm->tm_hour = 0;	else if (mer == PM && tm->tm_hour != 12)		tm->tm_hour += 12;	if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||		tm->tm_sec < 0 || tm->tm_sec > 60 || tm->tm_hour > 24 ||	/* test for > 24:00:00 */#ifdef HAVE_INT64_TIMESTAMP		(tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||							   *fsec > INT64CONST(0))) ||		*fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC#else		(tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||							   *fsec > 0)) ||		*fsec < 0 || *fsec >= 1#endif		)		return DTERR_FIELD_OVERFLOW;	if ((fmask & DTK_TIME_M) != DTK_TIME_M)		return DTERR_BAD_FORMAT;	/*	 * If we had a full timezone spec, compute the offset (we could not do it	 * before, because we may need the date to resolve DST status).	 */	if (namedTz != NULL)	{		long int	gmtoff;		/* daylight savings time modifier disallowed with full TZ */		if (fmask & DTK_M(DTZMOD))			return DTERR_BAD_FORMAT;		/* if non-DST zone, we do not need to know the date */		if (pg_get_timezone_offset(namedTz, &gmtoff))		{			*tzp = -(int) gmtoff;		}		else		{			/* a date has to be specified */			if ((fmask & DTK_DATE_M) != DTK_DATE_M)				return DTERR_BAD_FORMAT;			*tzp = DetermineTimeZoneOffset(tm, namedTz);		}	}	/* timezone not specified? then find local timezone if possible */	if (tzp != NULL && !(fmask & DTK_M(TZ)))	{		struct pg_tm tt,				   *tmp = &tt;		/*		 * daylight savings time modifier but no standard timezone? then error		 */		if (fmask & DTK_M(DTZMOD))			return DTERR_BAD_FORMAT;		if ((fmask & DTK_DATE_M) == 0)			GetCurrentDateTime(tmp);		else		{			tmp->tm_year = tm->tm_year;			tmp->tm_mon = tm->tm_mon;			tmp->tm_mday = tm->tm_mday;		}		tmp->tm_hour = tm->tm_hour;		tmp->tm_min = tm->tm_min;		tmp->tm_sec = tm->tm_sec;		*tzp = DetermineTimeZoneOffset(tmp, session_timezone);		tm->tm_isdst = tmp->tm_isdst;	}	return 0;}/* DecodeDate() * Decode date string which includes delimiters. * Return 0 if okay, a DTERR code if not. * *	str: field to be parsed *	fmask: bitmask for field types already seen *	*tmask: receives bitmask for fields found here *	*is2digits: set to TRUE if we find 2-digit year *	*tm: field values are stored into appropriate members of this struct */static intDecodeDate(char *str, int fmask, int *tmask, bool *is2digits,		   struct pg_tm * tm){	fsec_t		fsec;	int			nf = 0;	int			i,				len;	int			dterr;	bool		haveTextMonth = FALSE;	int			type,				val,				dmask = 0;	char	   *field[MAXDATEFIELDS];	*tmask = 0;	/* parse this string... */	while (*str != '\0' && nf < MAXDATEFIELDS)	{		/* skip field separators */		while (!isalnum((unsigned char) *str))			str++;		field[nf] = str;		if (isdigit((unsigned char) *str))		{			while (isdigit((unsigned char) *str))				str++;		}		else if (isalpha((unsigned char) *str))		{			while (isalpha((unsigned char) *str))				str++;		}		/* Just get rid of any non-digit, non-alpha characters... */		if (*str != '\0')			*str++ = '\0';		nf++;	}	/* look first for text fields, since that will be unambiguous month */	for (i = 0; i < nf; i++)	{		if (isalpha((unsigned char) *field[i]))		{			type = DecodeSpecial(i, field[i], &val);			if (type == IGNORE_DTF)				continue;			dmask = DTK_M(type);			switch (type)			{				case MONTH:					tm->tm_mon = val;					haveTextMonth = TRUE;					break;				default:					return DTERR_BAD_FORMAT;			}			if (fmask & dmask)				return DTERR_BAD_FORMAT;			fmask |= dmask;			*tmask |= dmask;			/* mark this field as being completed */			field[i] = NULL;		}	}	/* now pick up remaining numeric fields */	for (i = 0; i < nf; i++)	{		if (field[i] == NULL)			continue;		if ((len = strlen(field[i])) <= 0)			return DTERR_BAD_FORMAT;		dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,							 &dmask, tm,							 &fsec, is2digits);		if (dterr)			return dterr;		if (fmask & dmask)			return DTERR_BAD_FORMAT;		fmask |= dmask;		*tmask |= dmask;	}	if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)		return DTERR_BAD_FORMAT;	/* validation of the field values must wait until ValidateDate() */	return 0;}/* ValidateDate() * Check valid year/month/day values, handle BC and DOY cases

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?