datetime.c

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

C
2,681
字号
				}				else				{					ftype[nf] = DTK_DATE;					while (isalnum((unsigned char) *cp) || *cp == delim)						APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));				}			}			/*			 * otherwise, number only and will determine year, month, day, or			 * concatenated fields later...			 */			else				ftype[nf] = DTK_NUMBER;		}		/* Leading decimal point? Then fractional seconds... */		else if (*cp == '.')		{			APPEND_CHAR(bufp, bufend, *cp++);			while (isdigit((unsigned char) *cp))				APPEND_CHAR(bufp, bufend, *cp++);			ftype[nf] = DTK_NUMBER;		}		/*		 * text? then date string, month, day of week, special, or timezone		 */		else if (isalpha((unsigned char) *cp))		{			bool		is_date;			ftype[nf] = DTK_STRING;			APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));			while (isalpha((unsigned char) *cp))				APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));			/*			 * Dates can have embedded '-', '/', or '.' separators.  It could			 * also be a timezone name containing embedded '/', '+', '-', '_',			 * or ':' (but '_' or ':' can't be the first punctuation). If the			 * next character is a digit or '+', we need to check whether what			 * we have so far is a recognized non-timezone keyword --- if so,			 * don't believe that this is the start of a timezone.			 */			is_date = false;			if (*cp == '-' || *cp == '/' || *cp == '.')				is_date = true;			else if (*cp == '+' || isdigit((unsigned char) *cp))			{				*bufp = '\0';	/* null-terminate current field value */				/* we need search only the core token table, not TZ names */				if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)					is_date = true;			}			if (is_date)			{				ftype[nf] = DTK_DATE;				do				{					APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));				} while (*cp == '+' || *cp == '-' ||						 *cp == '/' || *cp == '_' ||						 *cp == '.' || *cp == ':' ||						 isalnum((unsigned char) *cp));			}		}		/* sign? then special or numeric timezone */		else if (*cp == '+' || *cp == '-')		{			APPEND_CHAR(bufp, bufend, *cp++);			/* soak up leading whitespace */			while (isspace((unsigned char) *cp))				cp++;			/* numeric timezone? */			if (isdigit((unsigned char) *cp))			{				ftype[nf] = DTK_TZ;				APPEND_CHAR(bufp, bufend, *cp++);				while (isdigit((unsigned char) *cp) ||					   *cp == ':' || *cp == '.')					APPEND_CHAR(bufp, bufend, *cp++);			}			/* special? */			else if (isalpha((unsigned char) *cp))			{				ftype[nf] = DTK_SPECIAL;				APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));				while (isalpha((unsigned char) *cp))					APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));			}			/* otherwise something wrong... */			else				return DTERR_BAD_FORMAT;		}		/* ignore other punctuation but use as delimiter */		else if (ispunct((unsigned char) *cp))		{			cp++;			continue;		}		/* otherwise, something is not right... */		else			return DTERR_BAD_FORMAT;		/* force in a delimiter after each field */		*bufp++ = '\0';		nf++;	}	*numfields = nf;	return 0;}/* DecodeDateTime() * Interpret previously parsed fields for general date and time. * Return 0 if full date, 1 if only time, and negative DTERR code if problems. * (Currently, all callers treat 1 as an error return too.) * *		External format(s): *				"<weekday> <month>-<day>-<year> <hour>:<minute>:<second>" *				"Fri Feb-7-1997 15:23:27" *				"Feb-7-1997 15:23:27" *				"2-7-1997 15:23:27" *				"1997-2-7 15:23:27" *				"1997.038 15:23:27"		(day of year 1-366) *		Also supports input in compact time: *				"970207 152327" *				"97038 152327" *				"20011225T040506.789-07" * * Use the system-provided functions to get the current time zone *	if not specified in the input string. * If the date is outside the time_t system-supported time range, *	then assume UTC time zone. - thomas 1997-05-27 */intDecodeDateTime(char **field, int *ftype, int nf,			   int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp){	int			fmask = 0,				tmask,				type;	int			ptype = 0;		/* "prefix type" for ISO y2001m02d04 format */	int			i;	int			val;	int			dterr;	int			mer = HR24;	bool		haveTextMonth = FALSE;	bool		is2digits = FALSE;	bool		bc = FALSE;	pg_tz	   *namedTz = NULL;	/*	 * We'll insist on at least all of the date fields, but initialize the	 * remaining fields in case they are not set later...	 */	*dtype = DTK_DATE;	tm->tm_hour = 0;	tm->tm_min = 0;	tm->tm_sec = 0;	*fsec = 0;	/* don't know daylight savings time status apriori */	tm->tm_isdst = -1;	if (tzp != NULL)		*tzp = 0;	for (i = 0; i < nf; i++)	{		switch (ftype[i])		{			case DTK_DATE:				/***				 * Integral julian day with attached time zone?				 * All other forms with JD will be separated into				 * distinct fields, so we handle just this case here.				 ***/				if (ptype == DTK_JULIAN)				{					char	   *cp;					int			val;					if (tzp == NULL)						return DTERR_BAD_FORMAT;					errno = 0;					val = strtoi(field[i], &cp, 10);					if (errno == ERANGE)						return DTERR_FIELD_OVERFLOW;					j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);					/* Get the time zone from the end of the string */					dterr = DecodeTimezone(cp, tzp);					if (dterr)						return dterr;					tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);					ptype = 0;					break;				}				/***				 * Already have a date? Then this might be a time zone name				 * with embedded punctuation (e.g. "America/New_York") or a				 * run-together time with trailing time zone (e.g. hhmmss-zz).				 * - thomas 2001-12-25				 *				 * We consider it a time zone if we already have month & day.				 * This is to allow the form "mmm dd hhmmss tz year", which				 * we've historically accepted.				 ***/				else if (ptype != 0 ||						 ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==						  (DTK_M(MONTH) | DTK_M(DAY))))				{					/* No time zone accepted? Then quit... */					if (tzp == NULL)						return DTERR_BAD_FORMAT;					if (isdigit((unsigned char) *field[i]) || ptype != 0)					{						char	   *cp;						if (ptype != 0)						{							/* Sanity check; should not fail this test */							if (ptype != DTK_TIME)								return DTERR_BAD_FORMAT;							ptype = 0;						}						/*						 * Starts with a digit but we already have a time						 * field? Then we are in trouble with a date and time						 * already...						 */						if ((fmask & DTK_TIME_M) == DTK_TIME_M)							return DTERR_BAD_FORMAT;						if ((cp = strchr(field[i], '-')) == NULL)							return DTERR_BAD_FORMAT;						/* Get the time zone from the end of the string */						dterr = DecodeTimezone(cp, tzp);						if (dterr)							return dterr;						*cp = '\0';						/*						 * Then read the rest of the field as a concatenated						 * time						 */						dterr = DecodeNumberField(strlen(field[i]), field[i],												  fmask,												  &tmask, tm,												  fsec, &is2digits);						if (dterr < 0)							return dterr;						/*						 * modify tmask after returning from						 * DecodeNumberField()						 */						tmask |= DTK_M(TZ);					}					else					{						namedTz = pg_tzset(field[i]);						if (!namedTz)						{							/*							 * We should return an error code instead of							 * ereport'ing directly, but then there is no way							 * to report the bad time zone name.							 */							ereport(ERROR,									(errcode(ERRCODE_INVALID_PARAMETER_VALUE),									 errmsg("time zone \"%s\" not recognized",											field[i])));						}						/* we'll apply the zone setting below */						tmask = DTK_M(TZ);					}				}				else				{					dterr = DecodeDate(field[i], fmask,									   &tmask, &is2digits, tm);					if (dterr)						return dterr;				}				break;			case DTK_TIME:				dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);				if (dterr)					return dterr;				/*				 * Check upper limit on hours; other limits checked in				 * DecodeTime()				 */				/* test for > 24:00:00 */				if (tm->tm_hour > 24 ||					(tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))					return DTERR_FIELD_OVERFLOW;				break;			case DTK_TZ:				{					int			tz;					if (tzp == NULL)						return DTERR_BAD_FORMAT;					dterr = DecodeTimezone(field[i], &tz);					if (dterr)						return dterr;					*tzp = tz;					tmask = DTK_M(TZ);				}				break;			case DTK_NUMBER:				/*				 * Was this an "ISO date" with embedded field labels? An				 * example is "y2001m02d04" - thomas 2001-02-04				 */				if (ptype != 0)				{					char	   *cp;					int			val;					errno = 0;					val = strtoi(field[i], &cp, 10);					if (errno == ERANGE)						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);							/* fractional Julian Day? */							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;							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 and no date yet? */					if (cp != NULL && !(fmask & DTK_DATE_M))					{						dterr = DecodeDate(field[i], fmask,										   &tmask, &is2digits, tm);						if (dterr)							return dterr;					}					/* embedded decimal and several digits before? */					else if (cp != NULL && 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,												  &tmask, tm,												  fsec, &is2digits);						if (dterr < 0)							return dterr;					}					else if (flen > 4)					{						dterr = DecodeNumberField(flen, field[i], fmask,												  &tmask, tm,												  fsec, &is2digits);						if (dterr < 0)							return dterr;					}					/* otherwise it is a single date/time field... */					else					{						dterr = DecodeNumber(flen, field[i],											 haveTextMonth, fmask,											 &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:

⌨️ 快捷键说明

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