📄 datetime.c
字号:
/*------------------------------------------------------------------------- * * datetime.c * Support functions for date/time types. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.160.2.2 2005/12/01 17:56:43 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <errno.h>#include <float.h>#include <limits.h>#include <math.h>#include "access/xact.h"#include "miscadmin.h"#include "utils/datetime.h"#include "utils/guc.h"static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec, int *is2digits);static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec, int *is2digits);static int DecodeTime(char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec);static int DecodeTimezone(char *str, int *tzp);static int DecodePosixTimezone(char *str, int *tzp);static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);static int DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm);static void TrimTrailingZeros(char *str);const int day_tab[2][13] ={ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday", NULL};/***************************************************************************** * PRIVATE ROUTINES * *****************************************************************************//* * Definitions for squeezing values into "value" * We set aside a high bit for a sign, and scale the timezone offsets * in minutes by a factor of 15 (so can represent quarter-hour increments). */#define ABS_SIGNBIT ((char) 0200)#define VALMASK ((char) 0177)#define POS(n) (n)#define NEG(n) ((n)|ABS_SIGNBIT)#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 15) /* uncompress */#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))/* * datetktbl holds date/time keywords. * * Note that this table must be strictly alphabetically ordered to allow an * O(ln(N)) search algorithm to be used. * * The text field is NOT guaranteed to be NULL-terminated. * * To keep this table reasonably small, we divide the lexval for TZ and DTZ * entries by 15 (so they are on 15 minute boundaries) and truncate the text * field at TOKMAXLEN characters. * Formerly, we divided by 10 rather than 15 but there are a few time zones * which are 30 or 45 minutes away from an even hour, most are on an hour * boundary, and none on other boundaries. * * Let's include all strings from my current zic time zone database. * Not all of them are unique, or even very understandable, so we will * leave some commented out for now. */static datetkn datetktbl[] = {/* text, token, lexval */ {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */ {"abstime", IGNORE_DTF, 0}, /* for pre-v6.1 "Invalid Abstime" */ {"acsst", DTZ, POS(42)}, /* Cent. Australia */ {"acst", DTZ, NEG(16)}, /* Atlantic/Porto Acre Summer Time */ {"act", TZ, NEG(20)}, /* Atlantic/Porto Acre Time */ {DA_D, ADBC, AD}, /* "ad" for years > 0 */ {"adt", DTZ, NEG(12)}, /* Atlantic Daylight Time */ {"aesst", DTZ, POS(44)}, /* E. Australia */ {"aest", TZ, POS(40)}, /* Australia Eastern Std Time */ {"aft", TZ, POS(18)}, /* Kabul */ {"ahst", TZ, NEG(40)}, /* Alaska-Hawaii Std Time */ {"akdt", DTZ, NEG(32)}, /* Alaska Daylight Time */ {"akst", DTZ, NEG(36)}, /* Alaska Standard Time */ {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */ {"almst", TZ, POS(28)}, /* Almaty Savings Time */ {"almt", TZ, POS(24)}, /* Almaty Time */ {"am", AMPM, AM}, {"amst", DTZ, POS(20)}, /* Armenia Summer Time (Yerevan) */#if 0 {"amst", DTZ, NEG(12)}, /* Amazon Summer Time (Porto Velho) */#endif {"amt", TZ, POS(16)}, /* Armenia Time (Yerevan) */#if 0 {"amt", TZ, NEG(16)}, /* Amazon Time (Porto Velho) */#endif {"anast", DTZ, POS(52)}, /* Anadyr Summer Time (Russia) */ {"anat", TZ, POS(48)}, /* Anadyr Time (Russia) */ {"apr", MONTH, 4}, {"april", MONTH, 4},#if 0 aqtst aqtt arst#endif {"art", TZ, NEG(12)}, /* Argentina Time */#if 0 ashst ast /* Atlantic Standard Time, Arabia Standard * Time, Acre Standard Time */#endif {"ast", TZ, NEG(16)}, /* Atlantic Std Time (Canada) */ {"at", IGNORE_DTF, 0}, /* "at" (throwaway) */ {"aug", MONTH, 8}, {"august", MONTH, 8}, {"awsst", DTZ, POS(36)}, /* W. Australia */ {"awst", TZ, POS(32)}, /* W. Australia */ {"awt", DTZ, NEG(12)}, {"azost", DTZ, POS(0)}, /* Azores Summer Time */ {"azot", TZ, NEG(4)}, /* Azores Time */ {"azst", DTZ, POS(20)}, /* Azerbaijan Summer Time */ {"azt", TZ, POS(16)}, /* Azerbaijan Time */ {DB_C, ADBC, BC}, /* "bc" for years <= 0 */ {"bdst", TZ, POS(8)}, /* British Double Summer Time */ {"bdt", TZ, POS(24)}, /* Dacca */ {"bnt", TZ, POS(32)}, /* Brunei Darussalam Time */ {"bort", TZ, POS(32)}, /* Borneo Time (Indonesia) */#if 0 bortst bost#endif {"bot", TZ, NEG(16)}, /* Bolivia Time */ {"bra", TZ, NEG(12)}, /* Brazil Time */ {"brst", DTZ, NEG(8)}, /* Brasilia Summer Time */ {"brt", TZ, NEG(12)}, /* Brasilia Time */ {"bst", DTZ, POS(4)}, /* British Summer Time */#if 0 {"bst", TZ, NEG(12)}, /* Brazil Standard Time */ {"bst", DTZ, NEG(44)}, /* Bering Summer Time */#endif {"bt", TZ, POS(12)}, /* Baghdad Time */ {"btt", TZ, POS(24)}, /* Bhutan Time */ {"cadt", DTZ, POS(42)}, /* Central Australian DST */ {"cast", TZ, POS(38)}, /* Central Australian ST */ {"cat", TZ, NEG(40)}, /* Central Alaska Time */ {"cct", TZ, POS(32)}, /* China Coast Time */#if 0 {"cct", TZ, POS(26)}, /* Indian Cocos (Island) Time */#endif {"cdt", DTZ, NEG(20)}, /* Central Daylight Time */ {"cest", DTZ, POS(8)}, /* Central European Dayl.Time */ {"cet", TZ, POS(4)}, /* Central European Time */ {"cetdst", DTZ, POS(8)}, /* Central European Dayl.Time */ {"chadt", DTZ, POS(55)}, /* Chatham Island Daylight Time (13:45) */ {"chast", TZ, POS(51)}, /* Chatham Island Time (12:45) */#if 0 ckhst#endif {"ckt", TZ, POS(48)}, /* Cook Islands Time */ {"clst", DTZ, NEG(12)}, /* Chile Summer Time */ {"clt", TZ, NEG(16)}, /* Chile Time */#if 0 cost#endif {"cot", TZ, NEG(20)}, /* Columbia Time */ {"cst", TZ, NEG(24)}, /* Central Standard Time */ {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */#if 0 cvst#endif {"cvt", TZ, POS(28)}, /* Christmas Island Time (Indian Ocean) */ {"cxt", TZ, POS(28)}, /* Christmas Island Time (Indian Ocean) */ {"d", UNITS, DTK_DAY}, /* "day of month" for ISO input */ {"davt", TZ, POS(28)}, /* Davis Time (Antarctica) */ {"ddut", TZ, POS(40)}, /* Dumont-d'Urville Time (Antarctica) */ {"dec", MONTH, 12}, {"december", MONTH, 12}, {"dnt", TZ, POS(4)}, /* Dansk Normal Tid */ {"dow", RESERV, DTK_DOW}, /* day of week */ {"doy", RESERV, DTK_DOY}, /* day of year */ {"dst", DTZMOD, 6},#if 0 {"dusst", DTZ, POS(24)}, /* Dushanbe Summer Time */#endif {"easst", DTZ, NEG(20)}, /* Easter Island Summer Time */ {"east", TZ, NEG(24)}, /* Easter Island Time */ {"eat", TZ, POS(12)}, /* East Africa Time */#if 0 {"east", DTZ, POS(16)}, /* Indian Antananarivo Savings Time */ {"eat", TZ, POS(12)}, /* Indian Antananarivo Time */ {"ect", TZ, NEG(16)}, /* Eastern Caribbean Time */ {"ect", TZ, NEG(20)}, /* Ecuador Time */#endif {"edt", DTZ, NEG(16)}, /* Eastern Daylight Time */ {"eest", DTZ, POS(12)}, /* Eastern Europe Summer Time */ {"eet", TZ, POS(8)}, /* East. Europe, USSR Zone 1 */ {"eetdst", DTZ, POS(12)}, /* Eastern Europe Daylight Time */ {"egst", DTZ, POS(0)}, /* East Greenland Summer Time */ {"egt", TZ, NEG(4)}, /* East Greenland Time */#if 0 ehdt#endif {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */ {"est", TZ, NEG(20)}, /* Eastern Standard Time */ {"feb", MONTH, 2}, {"february", MONTH, 2}, {"fjst", DTZ, NEG(52)}, /* Fiji Summer Time (13 hour offset!) */ {"fjt", TZ, NEG(48)}, /* Fiji Time */ {"fkst", DTZ, NEG(12)}, /* Falkland Islands Summer Time */ {"fkt", TZ, NEG(8)}, /* Falkland Islands Time */ {"fnst", DTZ, NEG(4)}, /* Fernando de Noronha Summer Time */ {"fnt", TZ, NEG(8)}, /* Fernando de Noronha Time */ {"fri", DOW, 5}, {"friday", DOW, 5}, {"fst", TZ, POS(4)}, /* French Summer Time */ {"fwt", DTZ, POS(8)}, /* French Winter Time */ {"galt", TZ, NEG(24)}, /* Galapagos Time */ {"gamt", TZ, NEG(36)}, /* Gambier Time */ {"gest", DTZ, POS(20)}, /* Georgia Summer Time */ {"get", TZ, POS(16)}, /* Georgia Time */ {"gft", TZ, NEG(12)}, /* French Guiana Time */#if 0 ghst#endif {"gilt", TZ, POS(48)}, /* Gilbert Islands Time */ {"gmt", TZ, POS(0)}, /* Greenwich Mean Time */ {"gst", TZ, POS(40)}, /* Guam Std Time, USSR Zone 9 */ {"gyt", TZ, NEG(16)}, /* Guyana Time */ {"h", UNITS, DTK_HOUR}, /* "hour" */#if 0 hadt hast#endif {"hdt", DTZ, NEG(36)}, /* Hawaii/Alaska Daylight Time */#if 0 hkst#endif {"hkt", TZ, POS(32)}, /* Hong Kong Time */#if 0 {"hmt", TZ, POS(12)}, /* Hellas ? ? */ hovst hovt#endif {"hst", TZ, NEG(40)}, /* Hawaii Std Time */#if 0 hwt#endif {"ict", TZ, POS(28)}, /* Indochina Time */ {"idle", TZ, POS(48)}, /* Intl. Date Line, East */ {"idlw", TZ, NEG(48)}, /* Intl. Date Line, West */#if 0 idt /* Israeli, Iran, Indian Daylight Time */#endif {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */ {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */ {"iot", TZ, POS(20)}, /* Indian Chagos Time */ {"irkst", DTZ, POS(36)}, /* Irkutsk Summer Time */ {"irkt", TZ, POS(32)}, /* Irkutsk Time */ {"irt", TZ, POS(14)}, /* Iran Time */#if 0 isst#endif {"ist", TZ, POS(8)}, /* Israel */ {"it", TZ, POS(14)}, /* Iran Time */ {"j", UNITS, DTK_JULIAN}, {"jan", MONTH, 1}, {"january", MONTH, 1}, {"javt", TZ, POS(28)}, /* Java Time (07:00? see JT) */ {"jayt", TZ, POS(36)}, /* Jayapura Time (Indonesia) */ {"jd", UNITS, DTK_JULIAN}, {"jst", TZ, POS(36)}, /* Japan Std Time,USSR Zone 8 */ {"jt", TZ, POS(30)}, /* Java Time (07:30? see JAVT) */ {"jul", MONTH, 7}, {"julian", UNITS, DTK_JULIAN}, {"july", MONTH, 7}, {"jun", MONTH, 6}, {"june", MONTH, 6}, {"kdt", DTZ, POS(40)}, /* Korea Daylight Time */ {"kgst", DTZ, POS(24)}, /* Kyrgyzstan Summer Time */ {"kgt", TZ, POS(20)}, /* Kyrgyzstan Time */ {"kost", TZ, POS(48)}, /* Kosrae Time */ {"krast", DTZ, POS(28)}, /* Krasnoyarsk Summer Time */ {"krat", TZ, POS(32)}, /* Krasnoyarsk Standard Time */ {"kst", TZ, POS(36)}, /* Korea Standard Time */ {"lhdt", DTZ, POS(44)}, /* Lord Howe Daylight Time, Australia */ {"lhst", TZ, POS(42)}, /* Lord Howe Standard Time, Australia */ {"ligt", TZ, POS(40)}, /* From Melbourne, Australia */ {"lint", TZ, POS(56)}, /* Line Islands Time (Kiribati; +14 hours!) */ {"lkt", TZ, POS(24)}, /* Lanka Time */ {"m", UNITS, DTK_MONTH}, /* "month" for ISO input */ {"magst", DTZ, POS(48)}, /* Magadan Summer Time */ {"magt", TZ, POS(44)}, /* Magadan Time */ {"mar", MONTH, 3}, {"march", MONTH, 3}, {"mart", TZ, NEG(38)}, /* Marquesas Time */ {"mawt", TZ, POS(24)}, /* Mawson, Antarctica */ {"may", MONTH, 5}, {"mdt", DTZ, NEG(24)}, /* Mountain Daylight Time */ {"mest", DTZ, POS(8)}, /* Middle Europe Summer Time */ {"met", TZ, POS(4)}, /* Middle Europe Time */ {"metdst", DTZ, POS(8)}, /* Middle Europe Daylight Time */ {"mewt", TZ, POS(4)}, /* Middle Europe Winter Time */ {"mez", TZ, POS(4)}, /* Middle Europe Zone */ {"mht", TZ, POS(48)}, /* Kwajalein */ {"mm", UNITS, DTK_MINUTE}, /* "minute" for ISO input */ {"mmt", TZ, POS(26)}, /* Myanmar Time */ {"mon", DOW, 1}, {"monday", DOW, 1},#if 0 most#endif {"mpt", TZ, POS(40)}, /* North Mariana Islands Time */ {"msd", DTZ, POS(16)}, /* Moscow Summer Time */ {"msk", TZ, POS(12)}, /* Moscow Time */ {"mst", TZ, NEG(28)}, /* Mountain Standard Time */ {"mt", TZ, POS(34)}, /* Moluccas Time */ {"mut", TZ, POS(16)}, /* Mauritius Island Time */ {"mvt", TZ, POS(20)}, /* Maldives Island Time */ {"myt", TZ, POS(32)}, /* Malaysia Time */#if 0 ncst#endif {"nct", TZ, POS(44)}, /* New Caledonia Time */ {"ndt", DTZ, NEG(10)}, /* Nfld. Daylight Time */ {"nft", TZ, NEG(14)}, /* Newfoundland Standard Time */ {"nor", TZ, POS(4)}, /* Norway Standard Time */ {"nov", MONTH, 11}, {"november", MONTH, 11}, {"novst", DTZ, POS(28)}, /* Novosibirsk Summer Time */ {"novt", TZ, POS(24)}, /* Novosibirsk Standard Time */ {NOW, RESERV, DTK_NOW}, /* current transaction time */ {"npt", TZ, POS(23)}, /* Nepal Standard Time (GMT-5:45) */ {"nst", TZ, NEG(14)}, /* Nfld. Standard Time */ {"nt", TZ, NEG(44)}, /* Nome Time */ {"nut", TZ, NEG(44)}, /* Niue Time */ {"nzdt", DTZ, POS(52)}, /* New Zealand Daylight Time */ {"nzst", TZ, POS(48)}, /* New Zealand Standard Time */ {"nzt", TZ, POS(48)}, /* New Zealand Time */ {"oct", MONTH, 10}, {"october", MONTH, 10}, {"omsst", DTZ, POS(28)}, /* Omsk Summer Time */ {"omst", TZ, POS(24)}, /* Omsk Time */ {"on", IGNORE_DTF, 0}, /* "on" (throwaway) */ {"pdt", DTZ, NEG(28)}, /* Pacific Daylight Time */#if 0 pest#endif {"pet", TZ, NEG(20)}, /* Peru Time */ {"petst", DTZ, POS(52)}, /* Petropavlovsk-Kamchatski Summer Time */ {"pett", TZ, POS(48)}, /* Petropavlovsk-Kamchatski Time */ {"pgt", TZ, POS(40)}, /* Papua New Guinea Time */ {"phot", TZ, POS(52)}, /* Phoenix Islands (Kiribati) Time */#if 0 phst#endif {"pht", TZ, POS(32)}, /* Phillipine Time */ {"pkt", TZ, POS(20)}, /* Pakistan Time */ {"pm", AMPM, PM}, {"pmdt", DTZ, NEG(8)}, /* Pierre & Miquelon Daylight Time */#if 0 pmst#endif {"pont", TZ, POS(44)}, /* Ponape Time (Micronesia) */ {"pst", TZ, NEG(32)}, /* Pacific Standard Time */ {"pwt", TZ, POS(36)}, /* Palau Time */ {"pyst", DTZ, NEG(12)}, /* Paraguay Summer Time */ {"pyt", TZ, NEG(16)}, /* Paraguay Time */ {"ret", DTZ, POS(16)}, /* Reunion Island Time */ {"s", UNITS, DTK_SECOND}, /* "seconds" for ISO input */ {"sadt", DTZ, POS(42)}, /* S. Australian Dayl. Time */#if 0 samst samt#endif {"sast", TZ, POS(38)}, /* South Australian Std Time */ {"sat", DOW, 6}, {"saturday", DOW, 6},#if 0 sbt#endif {"sct", DTZ, POS(16)}, /* Mahe Island Time */ {"sep", MONTH, 9}, {"sept", MONTH, 9}, {"september", MONTH, 9}, {"set", TZ, NEG(4)}, /* Seychelles Time ?? */#if 0 sgt#endif {"sst", DTZ, POS(8)}, /* Swedish Summer Time */ {"sun", DOW, 0}, {"sunday", DOW, 0}, {"swt", TZ, POS(4)}, /* Swedish Winter Time */#if 0 syot#endif {"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */ {"tft", TZ, POS(20)}, /* Kerguelen Time */ {"that", TZ, NEG(40)}, /* Tahiti Time */ {"thu", DOW, 4}, {"thur", DOW, 4}, {"thurs", DOW, 4}, {"thursday", DOW, 4}, {"tjt", TZ, POS(20)}, /* Tajikistan Time */ {"tkt", TZ, NEG(40)}, /* Tokelau Time */ {"tmt", TZ, POS(20)}, /* Turkmenistan Time */ {TODAY, RESERV, DTK_TODAY}, /* midnight */ {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */#if 0 tost#endif {"tot", TZ, POS(52)}, /* Tonga Time */#if 0 tpt#endif {"truk", TZ, POS(40)}, /* Truk Time */ {"tue", DOW, 2}, {"tues", DOW, 2}, {"tuesday", DOW, 2}, {"tvt", TZ, POS(48)}, /* Tuvalu Time */#if 0 uct#endif {"ulast", DTZ, POS(36)}, /* Ulan Bator Summer Time */ {"ulat", TZ, POS(32)}, /* Ulan Bator Time */ {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */ {"ut", TZ, POS(0)}, {"utc", TZ, POS(0)}, {"uyst", DTZ, NEG(8)}, /* Uruguay Summer Time */ {"uyt", TZ, NEG(12)}, /* Uruguay Time */ {"uzst", DTZ, POS(24)}, /* Uzbekistan Summer Time */ {"uzt", TZ, POS(20)}, /* Uzbekistan Time */ {"vet", TZ, NEG(16)}, /* Venezuela Time */ {"vlast", DTZ, POS(44)}, /* Vladivostok Summer Time */ {"vlat", TZ, POS(40)}, /* Vladivostok Time */#if 0 vust#endif {"vut", TZ, POS(44)}, /* Vanuata Time */ {"wadt", DTZ, POS(32)}, /* West Australian DST */ {"wakt", TZ, POS(48)}, /* Wake Time */#if 0 warst#endif {"wast", TZ, POS(28)}, /* West Australian Std Time */ {"wat", TZ, NEG(4)}, /* West Africa Time */ {"wdt", DTZ, POS(36)}, /* West Australian DST */ {"wed", DOW, 3}, {"wednesday", DOW, 3}, {"weds", DOW, 3}, {"west", DTZ, POS(4)}, /* Western Europe Summer Time */ {"wet", TZ, POS(0)}, /* Western Europe */ {"wetdst", DTZ, POS(4)}, /* Western Europe Daylight Savings Time */ {"wft", TZ, POS(48)}, /* Wallis and Futuna Time */ {"wgst", DTZ, NEG(8)}, /* West Greenland Summer Time */ {"wgt", TZ, NEG(12)}, /* West Greenland Time */ {"wst", TZ, POS(32)}, /* West Australian Standard Time */ {"y", UNITS, DTK_YEAR}, /* "year" for ISO input */ {"yakst", DTZ, POS(40)}, /* Yakutsk Summer Time */ {"yakt", TZ, POS(36)}, /* Yakutsk Time */ {"yapt", TZ, POS(40)}, /* Yap Time (Micronesia) */ {"ydt", DTZ, NEG(32)}, /* Yukon Daylight Time */ {"yekst", DTZ, POS(24)}, /* Yekaterinburg Summer Time */ {"yekt", TZ, POS(20)}, /* Yekaterinburg Time */ {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */ {"yst", TZ, NEG(36)}, /* Yukon Standard Time */ {"z", TZ, POS(0)}, /* time zone tag per ISO-8601 */ {"zp4", TZ, NEG(16)}, /* UTC +4 hours. */ {"zp5", TZ, NEG(20)}, /* UTC +5 hours. */ {"zp6", TZ, NEG(24)}, /* UTC +6 hours. */ {ZULU, TZ, POS(0)}, /* UTC */};static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -