datetime.c

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

C
2,681
字号
								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_DATE_M | DTK_TIME_M | DTK_M(TZ));								*dtype = DTK_DATE;								GetCurrentTimeUsec(tm, fsec, tzp);								break;							case DTK_YESTERDAY:								tmask = DTK_DATE_M;								*dtype = DTK_DATE;								GetCurrentDateTime(tm);								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,									&tm->tm_year, &tm->tm_mon, &tm->tm_mday);								tm->tm_hour = 0;								tm->tm_min = 0;								tm->tm_sec = 0;								break;							case DTK_TODAY:								tmask = DTK_DATE_M;								*dtype = DTK_DATE;								GetCurrentDateTime(tm);								tm->tm_hour = 0;								tm->tm_min = 0;								tm->tm_sec = 0;								break;							case DTK_TOMORROW:								tmask = DTK_DATE_M;								*dtype = DTK_DATE;								GetCurrentDateTime(tm);								j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,									&tm->tm_year, &tm->tm_mon, &tm->tm_mday);								tm->tm_hour = 0;								tm->tm_min = 0;								tm->tm_sec = 0;								break;							case DTK_ZULU:								tmask = (DTK_TIME_M | DTK_M(TZ));								*dtype = DTK_DATE;								tm->tm_hour = 0;								tm->tm_min = 0;								tm->tm_sec = 0;								if (tzp != NULL)									*tzp = 0;								break;							default:								*dtype = val;						}						break;					case MONTH:						/*						 * already have a (numeric) month? then see if we can						 * substitute...						 */						if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&							!(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&							tm->tm_mon <= 31)						{							tm->tm_mday = tm->tm_mon;							tmask = DTK_M(DAY);						}						haveTextMonth = TRUE;						tm->tm_mon = val;						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;						break;					case TZ:						tm->tm_isdst = 0;						if (tzp == NULL)							return DTERR_BAD_FORMAT;						*tzp = val * MINS_PER_HOUR;						break;					case IGNORE_DTF:						break;					case AMPM:						mer = val;						break;					case ADBC:						bc = (val == BC);						break;					case DOW:						tm->tm_wday = val;						break;					case UNITS:						tmask = 0;						ptype = val;						break;					case ISOTIME:						/*						 * This is a filler field "t" indicating that the next						 * field is time. Try to verify that this is sensible.						 */						tmask = 0;						/* No preceding date? Then quit... */						if ((fmask & DTK_DATE_M) != DTK_DATE_M)							return DTERR_BAD_FORMAT;						/***						 * 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;	/* do additional checking for full date specs... */	if (*dtype == DTK_DATE)	{		if ((fmask & DTK_DATE_M) != DTK_DATE_M)		{			if ((fmask & DTK_TIME_M) == DTK_TIME_M)				return 1;			return DTERR_BAD_FORMAT;		}		/*		 * If we had a full timezone spec, compute the offset (we could not do		 * it before, because we need the date to resolve DST status).		 */		if (namedTz != NULL)		{			/* daylight savings time modifier disallowed with full TZ */			if (fmask & DTK_M(DTZMOD))				return DTERR_BAD_FORMAT;			*tzp = DetermineTimeZoneOffset(tm, namedTz);		}		/* timezone not specified? then find local timezone if possible */		if (tzp != NULL && !(fmask & DTK_M(TZ)))		{			/*			 * daylight savings time modifier but no standard timezone? then			 * error			 */			if (fmask & DTK_M(DTZMOD))				return DTERR_BAD_FORMAT;			*tzp = DetermineTimeZoneOffset(tm, session_timezone);		}	}	return 0;}/* DetermineTimeZoneOffset() * * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and * tm_sec fields are set, attempt to determine the applicable time zone * (ie, regular or daylight-savings time) at that time.  Set the struct pg_tm's * tm_isdst field accordingly, and return the actual timezone offset. * * Note: it might seem that we should use mktime() for this, but bitter * experience teaches otherwise.  This code is much faster than most versions * of mktime(), anyway. */intDetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp){	int			date,				sec;	pg_time_t	day,				mytime,				prevtime,				boundary,				beforetime,				aftertime;	long int	before_gmtoff,				after_gmtoff;	int			before_isdst,				after_isdst;	int			res;	if (tzp == session_timezone && HasCTZSet)	{		tm->tm_isdst = 0;		/* for lack of a better idea */		return CTimeZone;	}	/*	 * First, generate the pg_time_t value corresponding to the given	 * y/m/d/h/m/s taken as GMT time.  If this overflows, punt and decide the	 * timezone is GMT.  (We only need to worry about overflow on machines	 * where pg_time_t is 32 bits.)	 */	if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))		goto overflow;	date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;	day = ((pg_time_t) date) * SECS_PER_DAY;	if (day / SECS_PER_DAY != date)		goto overflow;	sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;	mytime = day + sec;	/* since sec >= 0, overflow could only be from +day to -mytime */	if (mytime < 0 && day > 0)		goto overflow;	/*	 * Find the DST time boundary just before or following the target time. We	 * assume that all zones have GMT offsets less than 24 hours, and that DST	 * boundaries can't be closer together than 48 hours, so backing up 24	 * hours and finding the "next" boundary will work.	 */	prevtime = mytime - SECS_PER_DAY;	if (mytime < 0 && prevtime > 0)		goto overflow;	res = pg_next_dst_boundary(&prevtime,							   &before_gmtoff, &before_isdst,							   &boundary,							   &after_gmtoff, &after_isdst,							   tzp);	if (res < 0)		goto overflow;			/* failure? */	if (res == 0)	{		/* Non-DST zone, life is simple */		tm->tm_isdst = before_isdst;		return -(int) before_gmtoff;	}	/*	 * Form the candidate pg_time_t values with local-time adjustment	 */	beforetime = mytime - before_gmtoff;	if ((before_gmtoff > 0 &&		 mytime < 0 && beforetime > 0) ||		(before_gmtoff <= 0 &&		 mytime > 0 && beforetime < 0))		goto overflow;	aftertime = mytime - after_gmtoff;	if ((after_gmtoff > 0 &&		 mytime < 0 && aftertime > 0) ||		(after_gmtoff <= 0 &&		 mytime > 0 && aftertime < 0))		goto overflow;	/*	 * If both before or both after the boundary time, we know what to do	 */	if (beforetime <= boundary && aftertime < boundary)	{		tm->tm_isdst = before_isdst;		return -(int) before_gmtoff;	}	if (beforetime > boundary && aftertime >= boundary)	{		tm->tm_isdst = after_isdst;		return -(int) after_gmtoff;	}	/*	 * It's an invalid or ambiguous time due to timezone transition. Prefer	 * the standard-time interpretation.	 */	if (after_isdst == 0)	{		tm->tm_isdst = after_isdst;		return -(int) after_gmtoff;	}	tm->tm_isdst = before_isdst;	return -(int) before_gmtoff;overflow:	/* Given date is out of range, so assume UTC */	tm->tm_isdst = 0;	return 0;}/* DecodeTimeOnly() * Interpret parsed string as time fields only. * Returns 0 if successful, DTERR code if bogus input detected. * * Note that support for time zone is here for * SQL92 TIME WITH TIME ZONE, but it reveals * bogosity with SQL92 date/time standards, since * we must infer a time zone from current time. * - thomas 2000-03-10 * Allow specifying date to get a better time zone, * if time zones are allowed. - thomas 2001-12-26 */intDecodeTimeOnly(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 h04mm05s06 format */	int			i;	int			val;	int			dterr;	bool		is2digits = FALSE;	bool		bc = FALSE;	int			mer = HR24;	pg_tz	   *namedTz = NULL;	*dtype = DTK_TIME;	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:				/*				 * Time zone not allowed? Then should not accept dates or time				 * zones no matter what else!				 */				if (tzp == NULL)					return DTERR_BAD_FORMAT;				/* Under limited circumstances, we will accept a date... */				if (i == 0 && nf >= 2 &&					(ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))				{					dterr = DecodeDate(field[i], fmask,									   &tmask, &is2digits, tm);					if (dterr)						return dterr;				}				/* otherwise, this is a time and/or time zone */				else				{					if (isdigit((unsigned char) *field[i]))					{						char	   *cp;						/*						 * Starts with a digit but we already have a time						 * field? Then we are in trouble with time already...						 */						if ((fmask & DTK_TIME_M) == DTK_TIME_M)							return DTERR_BAD_FORMAT;						/*						 * Should not get here and fail. Sanity check only...						 */						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 | DTK_DATE_M),												  &tmask, tm,												  fsec, &is2digits);						if (dterr < 0)							return dterr;						ftype[i] = dterr;						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 */						ftype[i] = DTK_TZ;						tmask = DTK_M(TZ);					}				}				break;			case DTK_TIME:				dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),								   &tmask, tm, fsec);				if (dterr)					return dterr;				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 time" with embedded field labels? An				 * example is "h04m05s06" - thomas 2001-02-04				 */				if (ptype != 0)				{					char	   *cp;					int			val;					/* Only accept a date under limited circumstances */					switch (ptype)					{						case DTK_JULIAN:						case DTK_YEAR:						case DTK_MONTH:						case DTK_DAY:							if (tzp == NULL)								return DTERR_BAD_FORMAT;						default:							break;					}					errno = 0;					val = strtoi(field[i], &cp, 10);					if (errno == ERANGE)

⌨️ 快捷键说明

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