LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - dt_common.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 57.1 % 1251 714
Test Date: 2026-03-03 04:14:52 Functions: 91.3 % 23 21
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* src/interfaces/ecpg/pgtypeslib/dt_common.c */
       2              : 
       3              : #include "postgres_fe.h"
       4              : 
       5              : #include <time.h>
       6              : #include <ctype.h>
       7              : #include <math.h>
       8              : 
       9              : #include "common/string.h"
      10              : #include "dt.h"
      11              : #include "pgtypes_timestamp.h"
      12              : #include "pgtypeslib_extern.h"
      13              : 
      14              : const int   day_tab[2][13] = {
      15              :     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
      16              : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};
      17              : 
      18              : typedef long AbsoluteTime;
      19              : 
      20              : static const datetkn datetktbl[] = {
      21              : /*  text, token, lexval */
      22              :     {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
      23              :     {"acsst", DTZ, 37800},        /* Cent. Australia */
      24              :     {"acst", DTZ, -14400},        /* Atlantic/Porto Acre */
      25              :     {"act", TZ, -18000},      /* Atlantic/Porto Acre */
      26              :     {DA_D, ADBC, AD},           /* "ad" for years >= 0 */
      27              :     {"adt", DTZ, -10800},     /* Atlantic Daylight Time */
      28              :     {"aesst", DTZ, 39600},        /* E. Australia */
      29              :     {"aest", TZ, 36000},      /* Australia Eastern Std Time */
      30              :     {"aft", TZ, 16200},           /* Kabul */
      31              :     {"ahst", TZ, -36000},     /* Alaska-Hawaii Std Time */
      32              :     {"akdt", DTZ, -28800},        /* Alaska Daylight Time */
      33              :     {"akst", DTZ, -32400},        /* Alaska Standard Time */
      34              :     {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
      35              :     {"almst", TZ, 25200},     /* Almaty Savings Time */
      36              :     {"almt", TZ, 21600},      /* Almaty Time */
      37              :     {"am", AMPM, AM},
      38              :     {"amst", DTZ, 18000},     /* Armenia Summer Time (Yerevan) */
      39              : #if 0
      40              :     {"amst", DTZ, -10800},        /* Porto Velho */
      41              : #endif
      42              :     {"amt", TZ, 14400},           /* Armenia Time (Yerevan) */
      43              :     {"anast", DTZ, 46800},        /* Anadyr Summer Time (Russia) */
      44              :     {"anat", TZ, 43200},      /* Anadyr Time (Russia) */
      45              :     {"apr", MONTH, 4},
      46              :     {"april", MONTH, 4},
      47              : #if 0
      48              :     aqtst
      49              :     aqtt
      50              :     arst
      51              : #endif
      52              :     {"art", TZ, -10800},      /* Argentina Time */
      53              : #if 0
      54              :     ashst
      55              :     ast                         /* Atlantic Standard Time, Arabia Standard
      56              :                                  * Time, Acre Standard Time */
      57              : #endif
      58              :     {"ast", TZ, -14400},      /* Atlantic Std Time (Canada) */
      59              :     {"at", IGNORE_DTF, 0},        /* "at" (throwaway) */
      60              :     {"aug", MONTH, 8},
      61              :     {"august", MONTH, 8},
      62              :     {"awsst", DTZ, 32400},        /* W. Australia */
      63              :     {"awst", TZ, 28800},      /* W. Australia */
      64              :     {"awt", DTZ, -10800},
      65              :     {"azost", DTZ, 0},            /* Azores Summer Time */
      66              :     {"azot", TZ, -3600},      /* Azores Time */
      67              :     {"azst", DTZ, 18000},     /* Azerbaijan Summer Time */
      68              :     {"azt", TZ, 14400},           /* Azerbaijan Time */
      69              :     {DB_C, ADBC, BC},           /* "bc" for years < 0 */
      70              :     {"bdst", TZ, 7200},           /* British Double Summer Time */
      71              :     {"bdt", TZ, 21600},           /* Dacca */
      72              :     {"bnt", TZ, 28800},           /* Brunei Darussalam Time */
      73              :     {"bort", TZ, 28800},      /* Borneo Time (Indonesia) */
      74              : #if 0
      75              :     bortst
      76              :     bost
      77              : #endif
      78              :     {"bot", TZ, -14400},      /* Bolivia Time */
      79              :     {"bra", TZ, -10800},      /* Brazil Time */
      80              : #if 0
      81              :     brst
      82              :     brt
      83              : #endif
      84              :     {"bst", DTZ, 3600},           /* British Summer Time */
      85              : #if 0
      86              :     {"bst", TZ, -10800},      /* Brazil Standard Time */
      87              :     {"bst", DTZ, -39600},     /* Bering Summer Time */
      88              : #endif
      89              :     {"bt", TZ, 10800},            /* Baghdad Time */
      90              :     {"btt", TZ, 21600},           /* Bhutan Time */
      91              :     {"cadt", DTZ, 37800},     /* Central Australian DST */
      92              :     {"cast", TZ, 34200},      /* Central Australian ST */
      93              :     {"cat", TZ, -36000},      /* Central Alaska Time */
      94              :     {"cct", TZ, 28800},           /* China Coast Time */
      95              : #if 0
      96              :     {"cct", TZ, 23400},           /* Indian Cocos (Island) Time */
      97              : #endif
      98              :     {"cdt", DTZ, -18000},     /* Central Daylight Time */
      99              :     {"cest", DTZ, 7200},      /* Central European Dayl.Time */
     100              :     {"cet", TZ, 3600},            /* Central European Time */
     101              :     {"cetdst", DTZ, 7200},        /* Central European Dayl.Time */
     102              :     {"chadt", DTZ, 49500},        /* Chatham Island Daylight Time (13:45) */
     103              :     {"chast", TZ, 45900},     /* Chatham Island Time (12:45) */
     104              : #if 0
     105              :     ckhst
     106              : #endif
     107              :     {"ckt", TZ, 43200},           /* Cook Islands Time */
     108              :     {"clst", DTZ, -10800},        /* Chile Summer Time */
     109              :     {"clt", TZ, -14400},      /* Chile Time */
     110              : #if 0
     111              :     cost
     112              : #endif
     113              :     {"cot", TZ, -18000},      /* Columbia Time */
     114              :     {"cst", TZ, -21600},      /* Central Standard Time */
     115              : #if 0
     116              :     cvst
     117              : #endif
     118              :     {"cvt", TZ, 25200},           /* Christmas Island Time (Indian Ocean) */
     119              :     {"cxt", TZ, 25200},           /* Christmas Island Time (Indian Ocean) */
     120              :     {"d", UNITS, DTK_DAY},        /* "day of month" for ISO input */
     121              :     {"davt", TZ, 25200},      /* Davis Time (Antarctica) */
     122              :     {"ddut", TZ, 36000},      /* Dumont-d'Urville Time (Antarctica) */
     123              :     {"dec", MONTH, 12},
     124              :     {"december", MONTH, 12},
     125              :     {"dnt", TZ, 3600},            /* Dansk Normal Tid */
     126              :     {"dow", UNITS, DTK_DOW},  /* day of week */
     127              :     {"doy", UNITS, DTK_DOY},  /* day of year */
     128              :     {"dst", DTZMOD, SECS_PER_HOUR},
     129              : #if 0
     130              :     {"dusst", DTZ, 21600},        /* Dushanbe Summer Time */
     131              : #endif
     132              :     {"easst", DTZ, -18000},       /* Easter Island Summer Time */
     133              :     {"east", TZ, -21600},     /* Easter Island Time */
     134              :     {"eat", TZ, 10800},           /* East Africa Time */
     135              : #if 0
     136              :     {"east", DTZ, 14400},     /* Indian Antananarivo Savings Time */
     137              :     {"eat", TZ, 10800},           /* Indian Antananarivo Time */
     138              :     {"ect", TZ, -14400},      /* Eastern Caribbean Time */
     139              :     {"ect", TZ, -18000},      /* Ecuador Time */
     140              : #endif
     141              :     {"edt", DTZ, -14400},     /* Eastern Daylight Time */
     142              :     {"eest", DTZ, 10800},     /* Eastern Europe Summer Time */
     143              :     {"eet", TZ, 7200},            /* East. Europe, USSR Zone 1 */
     144              :     {"eetdst", DTZ, 10800},       /* Eastern Europe Daylight Time */
     145              :     {"egst", DTZ, 0},         /* East Greenland Summer Time */
     146              :     {"egt", TZ, -3600},           /* East Greenland Time */
     147              : #if 0
     148              :     ehdt
     149              : #endif
     150              :     {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
     151              :     {"est", TZ, -18000},      /* Eastern Standard Time */
     152              :     {"feb", MONTH, 2},
     153              :     {"february", MONTH, 2},
     154              :     {"fjst", DTZ, -46800},        /* Fiji Summer Time (13 hour offset!) */
     155              :     {"fjt", TZ, -43200},      /* Fiji Time */
     156              :     {"fkst", DTZ, -10800},        /* Falkland Islands Summer Time */
     157              :     {"fkt", TZ, -7200},           /* Falkland Islands Time */
     158              : #if 0
     159              :     fnst
     160              :     fnt
     161              : #endif
     162              :     {"fri", DOW, 5},
     163              :     {"friday", DOW, 5},
     164              :     {"fst", TZ, 3600},            /* French Summer Time */
     165              :     {"fwt", DTZ, 7200},           /* French Winter Time  */
     166              :     {"galt", TZ, -21600},     /* Galapagos Time */
     167              :     {"gamt", TZ, -32400},     /* Gambier Time */
     168              :     {"gest", DTZ, 18000},     /* Georgia Summer Time */
     169              :     {"get", TZ, 14400},           /* Georgia Time */
     170              :     {"gft", TZ, -10800},      /* French Guiana Time */
     171              : #if 0
     172              :     ghst
     173              : #endif
     174              :     {"gilt", TZ, 43200},      /* Gilbert Islands Time */
     175              :     {"gmt", TZ, 0},               /* Greenwich Mean Time */
     176              :     {"gst", TZ, 36000},           /* Guam Std Time, USSR Zone 9 */
     177              :     {"gyt", TZ, -14400},      /* Guyana Time */
     178              :     {"h", UNITS, DTK_HOUR},       /* "hour" */
     179              : #if 0
     180              :     hadt
     181              :     hast
     182              : #endif
     183              :     {"hdt", DTZ, -32400},     /* Hawaii/Alaska Daylight Time */
     184              : #if 0
     185              :     hkst
     186              : #endif
     187              :     {"hkt", TZ, 28800},           /* Hong Kong Time */
     188              : #if 0
     189              :     {"hmt", TZ, 10800},           /* Hellas ? ? */
     190              :     hovst
     191              :     hovt
     192              : #endif
     193              :     {"hst", TZ, -36000},      /* Hawaii Std Time */
     194              : #if 0
     195              :     hwt
     196              : #endif
     197              :     {"ict", TZ, 25200},           /* Indochina Time */
     198              :     {"idle", TZ, 43200},      /* Intl. Date Line, East */
     199              :     {"idlw", TZ, -43200},     /* Intl. Date Line, West */
     200              : #if 0
     201              :     idt                         /* Israeli, Iran, Indian Daylight Time */
     202              : #endif
     203              :     {LATE, RESERV, DTK_LATE},   /* "infinity" reserved for "late time" */
     204              :     {"iot", TZ, 18000},           /* Indian Chagos Time */
     205              :     {"irkst", DTZ, 32400},        /* Irkutsk Summer Time */
     206              :     {"irkt", TZ, 28800},      /* Irkutsk Time */
     207              :     {"irt", TZ, 12600},           /* Iran Time */
     208              :     {"isodow", UNITS, DTK_ISODOW},    /* ISO day of week, Sunday == 7 */
     209              : #if 0
     210              :     isst
     211              : #endif
     212              :     {"ist", TZ, 7200},            /* Israel */
     213              :     {"it", TZ, 12600},            /* Iran Time */
     214              :     {"j", UNITS, DTK_JULIAN},
     215              :     {"jan", MONTH, 1},
     216              :     {"january", MONTH, 1},
     217              :     {"javt", TZ, 25200},      /* Java Time (07:00? see JT) */
     218              :     {"jayt", TZ, 32400},      /* Jayapura Time (Indonesia) */
     219              :     {"jd", UNITS, DTK_JULIAN},
     220              :     {"jst", TZ, 32400},           /* Japan Std Time,USSR Zone 8 */
     221              :     {"jt", TZ, 27000},            /* Java Time (07:30? see JAVT) */
     222              :     {"jul", MONTH, 7},
     223              :     {"julian", UNITS, DTK_JULIAN},
     224              :     {"july", MONTH, 7},
     225              :     {"jun", MONTH, 6},
     226              :     {"june", MONTH, 6},
     227              :     {"kdt", DTZ, 36000},      /* Korea Daylight Time */
     228              :     {"kgst", DTZ, 21600},     /* Kyrgyzstan Summer Time */
     229              :     {"kgt", TZ, 18000},           /* Kyrgyzstan Time */
     230              :     {"kost", TZ, 43200},      /* Kosrae Time */
     231              :     {"krast", DTZ, 25200},        /* Krasnoyarsk Summer Time */
     232              :     {"krat", TZ, 28800},      /* Krasnoyarsk Standard Time */
     233              :     {"kst", TZ, 32400},           /* Korea Standard Time */
     234              :     {"lhdt", DTZ, 39600},     /* Lord Howe Daylight Time, Australia */
     235              :     {"lhst", TZ, 37800},      /* Lord Howe Standard Time, Australia */
     236              :     {"ligt", TZ, 36000},      /* From Melbourne, Australia */
     237              :     {"lint", TZ, 50400},      /* Line Islands Time (Kiribati; +14 hours!) */
     238              :     {"lkt", TZ, 21600},           /* Lanka Time */
     239              :     {"m", UNITS, DTK_MONTH},  /* "month" for ISO input */
     240              :     {"magst", DTZ, 43200},        /* Magadan Summer Time */
     241              :     {"magt", TZ, 39600},      /* Magadan Time */
     242              :     {"mar", MONTH, 3},
     243              :     {"march", MONTH, 3},
     244              :     {"mart", TZ, -34200},     /* Marquesas Time */
     245              :     {"mawt", TZ, 21600},      /* Mawson, Antarctica */
     246              :     {"may", MONTH, 5},
     247              :     {"mdt", DTZ, -21600},     /* Mountain Daylight Time */
     248              :     {"mest", DTZ, 7200},      /* Middle Europe Summer Time */
     249              :     {"met", TZ, 3600},            /* Middle Europe Time */
     250              :     {"metdst", DTZ, 7200},        /* Middle Europe Daylight Time */
     251              :     {"mewt", TZ, 3600},           /* Middle Europe Winter Time */
     252              :     {"mez", TZ, 3600},            /* Middle Europe Zone */
     253              :     {"mht", TZ, 43200},           /* Kwajalein */
     254              :     {"mm", UNITS, DTK_MINUTE},    /* "minute" for ISO input */
     255              :     {"mmt", TZ, 23400},           /* Myannar Time */
     256              :     {"mon", DOW, 1},
     257              :     {"monday", DOW, 1},
     258              : #if 0
     259              :     most
     260              : #endif
     261              :     {"mpt", TZ, 36000},           /* North Mariana Islands Time */
     262              :     {"msd", DTZ, 14400},      /* Moscow Summer Time */
     263              :     {"msk", TZ, 10800},           /* Moscow Time */
     264              :     {"mst", TZ, -25200},      /* Mountain Standard Time */
     265              :     {"mt", TZ, 30600},            /* Moluccas Time */
     266              :     {"mut", TZ, 14400},           /* Mauritius Island Time */
     267              :     {"mvt", TZ, 18000},           /* Maldives Island Time */
     268              :     {"myt", TZ, 28800},           /* Malaysia Time */
     269              : #if 0
     270              :     ncst
     271              : #endif
     272              :     {"nct", TZ, 39600},           /* New Caledonia Time */
     273              :     {"ndt", DTZ, -9000},      /* Nfld. Daylight Time */
     274              :     {"nft", TZ, -12600},      /* Newfoundland Standard Time */
     275              :     {"nor", TZ, 3600},            /* Norway Standard Time */
     276              :     {"nov", MONTH, 11},
     277              :     {"november", MONTH, 11},
     278              :     {"novst", DTZ, 25200},        /* Novosibirsk Summer Time */
     279              :     {"novt", TZ, 21600},      /* Novosibirsk Standard Time */
     280              :     {NOW, RESERV, DTK_NOW},     /* current transaction time */
     281              :     {"npt", TZ, 20700},           /* Nepal Standard Time (GMT-5:45) */
     282              :     {"nst", TZ, -12600},      /* Nfld. Standard Time */
     283              :     {"nt", TZ, -39600},           /* Nome Time */
     284              :     {"nut", TZ, -39600},      /* Niue Time */
     285              :     {"nzdt", DTZ, 46800},     /* New Zealand Daylight Time */
     286              :     {"nzst", TZ, 43200},      /* New Zealand Standard Time */
     287              :     {"nzt", TZ, 43200},           /* New Zealand Time */
     288              :     {"oct", MONTH, 10},
     289              :     {"october", MONTH, 10},
     290              :     {"omsst", DTZ, 25200},        /* Omsk Summer Time */
     291              :     {"omst", TZ, 21600},      /* Omsk Time */
     292              :     {"on", IGNORE_DTF, 0},        /* "on" (throwaway) */
     293              :     {"pdt", DTZ, -25200},     /* Pacific Daylight Time */
     294              : #if 0
     295              :     pest
     296              : #endif
     297              :     {"pet", TZ, -18000},      /* Peru Time */
     298              :     {"petst", DTZ, 46800},        /* Petropavlovsk-Kamchatski Summer Time */
     299              :     {"pett", TZ, 43200},      /* Petropavlovsk-Kamchatski Time */
     300              :     {"pgt", TZ, 36000},           /* Papua New Guinea Time */
     301              :     {"phot", TZ, 46800},      /* Phoenix Islands (Kiribati) Time */
     302              : #if 0
     303              :     phst
     304              : #endif
     305              :     {"pht", TZ, 28800},           /* Philippine Time */
     306              :     {"pkt", TZ, 18000},           /* Pakistan Time */
     307              :     {"pm", AMPM, PM},
     308              :     {"pmdt", DTZ, -7200},     /* Pierre & Miquelon Daylight Time */
     309              : #if 0
     310              :     pmst
     311              : #endif
     312              :     {"pont", TZ, 39600},      /* Ponape Time (Micronesia) */
     313              :     {"pst", TZ, -28800},      /* Pacific Standard Time */
     314              :     {"pwt", TZ, 32400},           /* Palau Time */
     315              :     {"pyst", DTZ, -10800},        /* Paraguay Summer Time */
     316              :     {"pyt", TZ, -14400},      /* Paraguay Time */
     317              :     {"ret", DTZ, 14400},      /* Reunion Island Time */
     318              :     {"s", UNITS, DTK_SECOND}, /* "seconds" for ISO input */
     319              :     {"sadt", DTZ, 37800},     /* S. Australian Dayl. Time */
     320              : #if 0
     321              :     samst
     322              :     samt
     323              : #endif
     324              :     {"sast", TZ, 34200},      /* South Australian Std Time */
     325              :     {"sat", DOW, 6},
     326              :     {"saturday", DOW, 6},
     327              : #if 0
     328              :     sbt
     329              : #endif
     330              :     {"sct", DTZ, 14400},      /* Mahe Island Time */
     331              :     {"sep", MONTH, 9},
     332              :     {"sept", MONTH, 9},
     333              :     {"september", MONTH, 9},
     334              :     {"set", TZ, -3600},           /* Seychelles Time ?? */
     335              : #if 0
     336              :     sgt
     337              : #endif
     338              :     {"sst", DTZ, 7200},           /* Swedish Summer Time */
     339              :     {"sun", DOW, 0},
     340              :     {"sunday", DOW, 0},
     341              :     {"swt", TZ, 3600},            /* Swedish Winter Time */
     342              : #if 0
     343              :     syot
     344              : #endif
     345              :     {"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
     346              :     {"tft", TZ, 18000},           /* Kerguelen Time */
     347              :     {"that", TZ, -36000},     /* Tahiti Time */
     348              :     {"thu", DOW, 4},
     349              :     {"thur", DOW, 4},
     350              :     {"thurs", DOW, 4},
     351              :     {"thursday", DOW, 4},
     352              :     {"tjt", TZ, 18000},           /* Tajikistan Time */
     353              :     {"tkt", TZ, -36000},      /* Tokelau Time */
     354              :     {"tmt", TZ, 18000},           /* Turkmenistan Time */
     355              :     {TODAY, RESERV, DTK_TODAY}, /* midnight */
     356              :     {TOMORROW, RESERV, DTK_TOMORROW},   /* tomorrow midnight */
     357              : #if 0
     358              :     tost
     359              : #endif
     360              :     {"tot", TZ, 46800},           /* Tonga Time */
     361              : #if 0
     362              :     tpt
     363              : #endif
     364              :     {"truk", TZ, 36000},      /* Truk Time */
     365              :     {"tue", DOW, 2},
     366              :     {"tues", DOW, 2},
     367              :     {"tuesday", DOW, 2},
     368              :     {"tvt", TZ, 43200},           /* Tuvalu Time */
     369              : #if 0
     370              :     uct
     371              : #endif
     372              :     {"ulast", DTZ, 32400},        /* Ulan Bator Summer Time */
     373              :     {"ulat", TZ, 28800},      /* Ulan Bator Time */
     374              :     {"ut", TZ, 0},
     375              :     {"utc", TZ, 0},
     376              :     {"uyst", DTZ, -7200},     /* Uruguay Summer Time */
     377              :     {"uyt", TZ, -10800},      /* Uruguay Time */
     378              :     {"uzst", DTZ, 21600},     /* Uzbekistan Summer Time */
     379              :     {"uzt", TZ, 18000},           /* Uzbekistan Time */
     380              :     {"vet", TZ, -14400},      /* Venezuela Time */
     381              :     {"vlast", DTZ, 39600},        /* Vladivostok Summer Time */
     382              :     {"vlat", TZ, 36000},      /* Vladivostok Time */
     383              : #if 0
     384              :     vust
     385              : #endif
     386              :     {"vut", TZ, 39600},           /* Vanuata Time */
     387              :     {"wadt", DTZ, 28800},     /* West Australian DST */
     388              :     {"wakt", TZ, 43200},      /* Wake Time */
     389              : #if 0
     390              :     warst
     391              : #endif
     392              :     {"wast", TZ, 25200},      /* West Australian Std Time */
     393              :     {"wat", TZ, -3600},           /* West Africa Time */
     394              :     {"wdt", DTZ, 32400},      /* West Australian DST */
     395              :     {"wed", DOW, 3},
     396              :     {"wednesday", DOW, 3},
     397              :     {"weds", DOW, 3},
     398              :     {"west", DTZ, 3600},      /* Western Europe Summer Time */
     399              :     {"wet", TZ, 0},               /* Western Europe */
     400              :     {"wetdst", DTZ, 3600},        /* Western Europe Daylight Savings Time */
     401              :     {"wft", TZ, 43200},           /* Wallis and Futuna Time */
     402              :     {"wgst", DTZ, -7200},     /* West Greenland Summer Time */
     403              :     {"wgt", TZ, -10800},      /* West Greenland Time */
     404              :     {"wst", TZ, 28800},           /* West Australian Standard Time */
     405              :     {"y", UNITS, DTK_YEAR},       /* "year" for ISO input */
     406              :     {"yakst", DTZ, 36000},        /* Yakutsk Summer Time */
     407              :     {"yakt", TZ, 32400},      /* Yakutsk Time */
     408              :     {"yapt", TZ, 36000},      /* Yap Time (Micronesia) */
     409              :     {"ydt", DTZ, -28800},     /* Yukon Daylight Time */
     410              :     {"yekst", DTZ, 21600},        /* Yekaterinburg Summer Time */
     411              :     {"yekt", TZ, 18000},      /* Yekaterinburg Time */
     412              :     {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
     413              :     {"yst", TZ, -32400},      /* Yukon Standard Time */
     414              :     {"z", TZ, 0},             /* time zone tag per ISO-8601 */
     415              :     {"zp4", TZ, -14400},      /* UTC +4  hours. */
     416              :     {"zp5", TZ, -18000},      /* UTC +5  hours. */
     417              :     {"zp6", TZ, -21600},      /* UTC +6  hours. */
     418              :     {ZULU, TZ, 0},              /* UTC */
     419              : };
     420              : 
     421              : static const datetkn deltatktbl[] = {
     422              :     /* text, token, lexval */
     423              :     {"@", IGNORE_DTF, 0},     /* postgres relative prefix */
     424              :     {DAGO, AGO, 0},             /* "ago" indicates negative time offset */
     425              :     {"c", UNITS, DTK_CENTURY},    /* "century" relative */
     426              :     {"cent", UNITS, DTK_CENTURY}, /* "century" relative */
     427              :     {"centuries", UNITS, DTK_CENTURY},    /* "centuries" relative */
     428              :     {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */
     429              :     {"d", UNITS, DTK_DAY},        /* "day" relative */
     430              :     {DDAY, UNITS, DTK_DAY},     /* "day" relative */
     431              :     {"days", UNITS, DTK_DAY}, /* "days" relative */
     432              :     {"dec", UNITS, DTK_DECADE}, /* "decade" relative */
     433              :     {DDECADE, UNITS, DTK_DECADE},   /* "decade" relative */
     434              :     {"decades", UNITS, DTK_DECADE}, /* "decades" relative */
     435              :     {"decs", UNITS, DTK_DECADE},  /* "decades" relative */
     436              :     {"h", UNITS, DTK_HOUR},       /* "hour" relative */
     437              :     {DHOUR, UNITS, DTK_HOUR},   /* "hour" relative */
     438              :     {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
     439              :     {"hr", UNITS, DTK_HOUR},  /* "hour" relative */
     440              :     {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */
     441              :     {"m", UNITS, DTK_MINUTE}, /* "minute" relative */
     442              :     {"microsecon", UNITS, DTK_MICROSEC},  /* "microsecond" relative */
     443              :     {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
     444              :     {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
     445              :     {DMILLENNIUM, UNITS, DTK_MILLENNIUM},   /* "millennium" relative */
     446              :     {"millisecon", UNITS, DTK_MILLISEC},  /* relative */
     447              :     {"mils", UNITS, DTK_MILLENNIUM},  /* "millennia" relative */
     448              :     {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
     449              :     {"mins", UNITS, DTK_MINUTE},  /* "minutes" relative */
     450              :     {DMINUTE, UNITS, DTK_MINUTE},   /* "minute" relative */
     451              :     {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
     452              :     {"mon", UNITS, DTK_MONTH},    /* "months" relative */
     453              :     {"mons", UNITS, DTK_MONTH}, /* "months" relative */
     454              :     {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
     455              :     {"months", UNITS, DTK_MONTH},
     456              :     {"ms", UNITS, DTK_MILLISEC},
     457              :     {"msec", UNITS, DTK_MILLISEC},
     458              :     {DMILLISEC, UNITS, DTK_MILLISEC},
     459              :     {"mseconds", UNITS, DTK_MILLISEC},
     460              :     {"msecs", UNITS, DTK_MILLISEC},
     461              :     {"qtr", UNITS, DTK_QUARTER},  /* "quarter" relative */
     462              :     {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
     463              :     {"s", UNITS, DTK_SECOND},
     464              :     {"sec", UNITS, DTK_SECOND},
     465              :     {DSECOND, UNITS, DTK_SECOND},
     466              :     {"seconds", UNITS, DTK_SECOND},
     467              :     {"secs", UNITS, DTK_SECOND},
     468              :     {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
     469              :     {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
     470              :     {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
     471              :     {"us", UNITS, DTK_MICROSEC},  /* "microsecond" relative */
     472              :     {"usec", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
     473              :     {DMICROSEC, UNITS, DTK_MICROSEC},   /* "microsecond" relative */
     474              :     {"useconds", UNITS, DTK_MICROSEC},    /* "microseconds" relative */
     475              :     {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
     476              :     {"w", UNITS, DTK_WEEK},       /* "week" relative */
     477              :     {DWEEK, UNITS, DTK_WEEK},   /* "week" relative */
     478              :     {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
     479              :     {"y", UNITS, DTK_YEAR},       /* "year" relative */
     480              :     {DYEAR, UNITS, DTK_YEAR},   /* "year" relative */
     481              :     {"years", UNITS, DTK_YEAR}, /* "years" relative */
     482              :     {"yr", UNITS, DTK_YEAR},  /* "year" relative */
     483              :     {"yrs", UNITS, DTK_YEAR}, /* "years" relative */
     484              : };
     485              : 
     486              : static const unsigned int szdatetktbl = lengthof(datetktbl);
     487              : static const unsigned int szdeltatktbl = lengthof(deltatktbl);
     488              : 
     489              : static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
     490              : 
     491              : static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
     492              : 
     493              : char       *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
     494              : 
     495              : char       *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL};
     496              : 
     497              : char       *pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL};
     498              : 
     499              : char       *pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL};
     500              : 
     501              : static const datetkn *
     502           90 : datebsearch(const char *key, const datetkn *base, unsigned int nel)
     503              : {
     504           90 :     if (nel > 0)
     505              :     {
     506           90 :         const datetkn *last = base + nel - 1,
     507              :                    *position;
     508              :         int         result;
     509              : 
     510          586 :         while (last >= base)
     511              :         {
     512          576 :             position = base + ((last - base) >> 1);
     513              :             /* precheck the first character for a bit of extra speed */
     514          576 :             result = (int) key[0] - (int) position->token[0];
     515          576 :             if (result == 0)
     516              :             {
     517              :                 /* use strncmp so that we match truncated tokens */
     518          282 :                 result = strncmp(key, position->token, TOKMAXLEN);
     519          282 :                 if (result == 0)
     520           80 :                     return position;
     521              :             }
     522          496 :             if (result < 0)
     523          232 :                 last = position - 1;
     524              :             else
     525          264 :                 base = position + 1;
     526              :         }
     527              :     }
     528           10 :     return NULL;
     529              : }
     530              : 
     531              : /* DecodeUnits()
     532              :  * Decode text string using lookup table.
     533              :  * This routine supports time interval decoding.
     534              :  */
     535              : int
     536           88 : DecodeUnits(int field, char *lowtoken, int *val)
     537              : {
     538              :     int         type;
     539              :     const datetkn *tp;
     540              : 
     541              :     /* use strncmp so that we match truncated tokens */
     542           88 :     if (deltacache[field] != NULL &&
     543           60 :         strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)
     544           40 :         tp = deltacache[field];
     545              :     else
     546           48 :         tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
     547           88 :     deltacache[field] = tp;
     548           88 :     if (tp == NULL)
     549              :     {
     550            2 :         type = UNKNOWN_FIELD;
     551            2 :         *val = 0;
     552              :     }
     553              :     else
     554              :     {
     555           86 :         type = tp->type;
     556           86 :         *val = tp->value;
     557              :     }
     558              : 
     559           88 :     return type;
     560              : }                               /* DecodeUnits() */
     561              : 
     562              : /*
     563              :  * Calendar time to Julian date conversions.
     564              :  * Julian date is commonly used in astronomical applications,
     565              :  *  since it is numerically accurate and computationally simple.
     566              :  * The algorithms here will accurately convert between Julian day
     567              :  *  and calendar date for all non-negative Julian days
     568              :  *  (i.e. from Nov 24, -4713 on).
     569              :  *
     570              :  * These routines will be used by other date/time packages
     571              :  * - thomas 97/02/25
     572              :  *
     573              :  * Rewritten to eliminate overflow problems. This now allows the
     574              :  * routines to work correctly for all Julian day counts from
     575              :  * 0 to 2147483647  (Nov 24, -4713 to Jun 3, 5874898) assuming
     576              :  * a 32-bit integer. Longer types should also work to the limits
     577              :  * of their precision.
     578              :  */
     579              : 
     580              : int
     581         1826 : date2j(int y, int m, int d)
     582              : {
     583              :     int         julian;
     584              :     int         century;
     585              : 
     586         1826 :     if (m > 2)
     587              :     {
     588          104 :         m += 1;
     589          104 :         y += 4800;
     590              :     }
     591              :     else
     592              :     {
     593         1722 :         m += 13;
     594         1722 :         y += 4799;
     595              :     }
     596              : 
     597         1826 :     century = y / 100;
     598         1826 :     julian = y * 365 - 32167;
     599         1826 :     julian += y / 4 - century + century / 4;
     600         1826 :     julian += 7834 * m / 256 + d;
     601              : 
     602         1826 :     return julian;
     603              : }                               /* date2j() */
     604              : 
     605              : void
     606          570 : j2date(int jd, int *year, int *month, int *day)
     607              : {
     608              :     unsigned int julian;
     609              :     unsigned int quad;
     610              :     unsigned int extra;
     611              :     int         y;
     612              : 
     613          570 :     julian = jd;
     614          570 :     julian += 32044;
     615          570 :     quad = julian / 146097;
     616          570 :     extra = (julian - quad * 146097) * 4 + 3;
     617          570 :     julian += 60 + quad * 3 + extra / 146097;
     618          570 :     quad = julian / 1461;
     619          570 :     julian -= quad * 1461;
     620          570 :     y = julian * 4 / 1461;
     621          570 :     julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123;
     622          570 :     y += quad * 4;
     623          570 :     *year = y - 4800;
     624          570 :     quad = julian * 2141 / 65536;
     625          570 :     *day = julian - 7834 * quad / 256;
     626          570 :     *month = (quad + 10) % 12 + 1;
     627          570 : }                               /* j2date() */
     628              : 
     629              : /* DecodeSpecial()
     630              :  * Decode text string using lookup table.
     631              :  * Implement a cache lookup since it is likely that dates
     632              :  *  will be related in format.
     633              :  */
     634              : static int
     635          228 : DecodeSpecial(int field, char *lowtoken, int *val)
     636              : {
     637              :     int         type;
     638              :     const datetkn *tp;
     639              : 
     640              :     /* use strncmp so that we match truncated tokens */
     641          228 :     if (datecache[field] != NULL &&
     642          198 :         strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)
     643          186 :         tp = datecache[field];
     644              :     else
     645              :     {
     646           42 :         tp = NULL;
     647           42 :         if (!tp)
     648           42 :             tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
     649              :     }
     650          228 :     datecache[field] = tp;
     651          228 :     if (tp == NULL)
     652              :     {
     653            8 :         type = UNKNOWN_FIELD;
     654            8 :         *val = 0;
     655              :     }
     656              :     else
     657              :     {
     658          220 :         type = tp->type;
     659          220 :         *val = tp->value;
     660              :     }
     661              : 
     662          228 :     return type;
     663              : }                               /* DecodeSpecial() */
     664              : 
     665              : /* EncodeDateOnly()
     666              :  * Encode date as local time.
     667              :  */
     668              : void
     669          190 : EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates)
     670              : {
     671              :     Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
     672              : 
     673          190 :     switch (style)
     674              :     {
     675          190 :         case USE_ISO_DATES:
     676              :             /* compatible with ISO date formats */
     677          190 :             if (tm->tm_year > 0)
     678          188 :                 sprintf(str, "%04d-%02d-%02d",
     679              :                         tm->tm_year, tm->tm_mon, tm->tm_mday);
     680              :             else
     681            2 :                 sprintf(str, "%04d-%02d-%02d %s",
     682            2 :                         -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
     683          190 :             break;
     684              : 
     685            0 :         case USE_SQL_DATES:
     686              :             /* compatible with Oracle/Ingres date formats */
     687            0 :             if (EuroDates)
     688            0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     689              :             else
     690            0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     691            0 :             if (tm->tm_year > 0)
     692            0 :                 sprintf(str + 5, "/%04d", tm->tm_year);
     693              :             else
     694            0 :                 sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
     695            0 :             break;
     696              : 
     697            0 :         case USE_GERMAN_DATES:
     698              :             /* German-style date format */
     699            0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     700            0 :             if (tm->tm_year > 0)
     701            0 :                 sprintf(str + 5, ".%04d", tm->tm_year);
     702              :             else
     703            0 :                 sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
     704            0 :             break;
     705              : 
     706            0 :         case USE_POSTGRES_DATES:
     707              :         default:
     708              :             /* traditional date-only style for Postgres */
     709            0 :             if (EuroDates)
     710            0 :                 sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
     711              :             else
     712            0 :                 sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
     713            0 :             if (tm->tm_year > 0)
     714            0 :                 sprintf(str + 5, "-%04d", tm->tm_year);
     715              :             else
     716            0 :                 sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
     717            0 :             break;
     718              :     }
     719          190 : }
     720              : 
     721              : void
     722           68 : TrimTrailingZeros(char *str)
     723              : {
     724           68 :     int         len = strlen(str);
     725              : 
     726              :     /* chop off trailing zeros... but leave at least 2 fractional digits */
     727          170 :     while (*(str + len - 1) == '0' && *(str + len - 3) != '.')
     728              :     {
     729          102 :         len--;
     730          102 :         *(str + len) = '\0';
     731              :     }
     732           68 : }
     733              : 
     734              : /* EncodeDateTime()
     735              :  * Encode date and time interpreted as local time.
     736              :  *
     737              :  * tm and fsec are the value to encode, print_tz determines whether to include
     738              :  * a time zone (the difference between timestamp and timestamptz types), tz is
     739              :  * the numeric time zone offset, tzn is the textual time zone, which if
     740              :  * specified will be used instead of tz by some styles, style is the date
     741              :  * style, str is where to write the output.
     742              :  *
     743              :  * Supported date styles:
     744              :  *  Postgres - day mon hh:mm:ss yyyy tz
     745              :  *  SQL - mm/dd/yyyy hh:mm:ss.ss tz
     746              :  *  ISO - yyyy-mm-dd hh:mm:ss+/-tz
     747              :  *  German - dd.mm.yyyy hh:mm:ss tz
     748              :  * Variants (affects order of month and day for Postgres and SQL styles):
     749              :  *  US - mm/dd/yyyy
     750              :  *  European - dd/mm/yyyy
     751              :  */
     752              : void
     753          318 : EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
     754              : {
     755              :     int         day,
     756              :                 hour,
     757              :                 min;
     758              : 
     759              :     /*
     760              :      * Negative tm_isdst means we have no valid time zone translation.
     761              :      */
     762          318 :     if (tm->tm_isdst < 0)
     763          318 :         print_tz = false;
     764              : 
     765          318 :     switch (style)
     766              :     {
     767          318 :         case USE_ISO_DATES:
     768              :             /* Compatible with ISO-8601 date formats */
     769              : 
     770          318 :             sprintf(str, "%04d-%02d-%02d %02d:%02d",
     771          318 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     772              :                     tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
     773              : 
     774              :             /*
     775              :              * Print fractional seconds if any.  The field widths here should
     776              :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     777              :              */
     778          318 :             if (fsec != 0)
     779              :             {
     780           68 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     781           68 :                 TrimTrailingZeros(str);
     782              :             }
     783              :             else
     784          250 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     785              : 
     786          318 :             if (tm->tm_year <= 0)
     787           10 :                 sprintf(str + strlen(str), " BC");
     788              : 
     789          318 :             if (print_tz)
     790              :             {
     791            0 :                 hour = -(tz / SECS_PER_HOUR);
     792            0 :                 min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     793            0 :                 if (min != 0)
     794            0 :                     sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     795              :                 else
     796            0 :                     sprintf(str + strlen(str), "%+03d", hour);
     797              :             }
     798          318 :             break;
     799              : 
     800            0 :         case USE_SQL_DATES:
     801              :             /* Compatible with Oracle/Ingres date formats */
     802              : 
     803            0 :             if (EuroDates)
     804            0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     805              :             else
     806            0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     807              : 
     808            0 :             sprintf(str + 5, "/%04d %02d:%02d",
     809            0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     810              :                     tm->tm_hour, tm->tm_min);
     811              : 
     812              :             /*
     813              :              * Print fractional seconds if any.  The field widths here should
     814              :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     815              :              */
     816            0 :             if (fsec != 0)
     817              :             {
     818            0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     819            0 :                 TrimTrailingZeros(str);
     820              :             }
     821              :             else
     822            0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     823              : 
     824            0 :             if (tm->tm_year <= 0)
     825            0 :                 sprintf(str + strlen(str), " BC");
     826              : 
     827              :             /*
     828              :              * Note: the uses of %.*s in this function would be risky if the
     829              :              * timezone names ever contain non-ASCII characters, since we are
     830              :              * not being careful to do encoding-aware clipping.  However, all
     831              :              * TZ abbreviations in the IANA database are plain ASCII.
     832              :              */
     833              : 
     834            0 :             if (print_tz)
     835              :             {
     836            0 :                 if (tzn)
     837            0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     838              :                 else
     839              :                 {
     840            0 :                     hour = -(tz / SECS_PER_HOUR);
     841            0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     842            0 :                     if (min != 0)
     843            0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     844              :                     else
     845            0 :                         sprintf(str + strlen(str), "%+03d", hour);
     846              :                 }
     847              :             }
     848            0 :             break;
     849              : 
     850            0 :         case USE_GERMAN_DATES:
     851              :             /* German variant on European style */
     852              : 
     853            0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     854              : 
     855            0 :             sprintf(str + 5, ".%04d %02d:%02d",
     856            0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     857              :                     tm->tm_hour, tm->tm_min);
     858              : 
     859              :             /*
     860              :              * Print fractional seconds if any.  The field widths here should
     861              :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     862              :              */
     863            0 :             if (fsec != 0)
     864              :             {
     865            0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     866            0 :                 TrimTrailingZeros(str);
     867              :             }
     868              :             else
     869            0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     870              : 
     871            0 :             if (tm->tm_year <= 0)
     872            0 :                 sprintf(str + strlen(str), " BC");
     873              : 
     874            0 :             if (print_tz)
     875              :             {
     876            0 :                 if (tzn)
     877            0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     878              :                 else
     879              :                 {
     880            0 :                     hour = -(tz / SECS_PER_HOUR);
     881            0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     882            0 :                     if (min != 0)
     883            0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     884              :                     else
     885            0 :                         sprintf(str + strlen(str), "%+03d", hour);
     886              :                 }
     887              :             }
     888            0 :             break;
     889              : 
     890            0 :         case USE_POSTGRES_DATES:
     891              :         default:
     892              :             /* Backward-compatible with traditional Postgres abstime dates */
     893              : 
     894            0 :             day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
     895            0 :             tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
     896              : 
     897            0 :             memcpy(str, days[tm->tm_wday], 3);
     898            0 :             strcpy(str + 3, " ");
     899              : 
     900            0 :             if (EuroDates)
     901            0 :                 sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
     902              :             else
     903            0 :                 sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
     904              : 
     905            0 :             sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min);
     906              : 
     907              :             /*
     908              :              * Print fractional seconds if any.  The field widths here should
     909              :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     910              :              */
     911            0 :             if (fsec != 0)
     912              :             {
     913            0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     914            0 :                 TrimTrailingZeros(str);
     915              :             }
     916              :             else
     917            0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     918              : 
     919            0 :             sprintf(str + strlen(str), " %04d",
     920            0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
     921            0 :             if (tm->tm_year <= 0)
     922            0 :                 sprintf(str + strlen(str), " BC");
     923              : 
     924            0 :             if (print_tz)
     925              :             {
     926            0 :                 if (tzn)
     927            0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     928              :                 else
     929              :                 {
     930              :                     /*
     931              :                      * We have a time zone, but no string version. Use the
     932              :                      * numeric form, but be sure to include a leading space to
     933              :                      * avoid formatting something which would be rejected by
     934              :                      * the date/time parser later. - thomas 2001-10-19
     935              :                      */
     936            0 :                     hour = -(tz / SECS_PER_HOUR);
     937            0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     938            0 :                     if (min != 0)
     939            0 :                         sprintf(str + strlen(str), " %+03d:%02d", hour, min);
     940              :                     else
     941            0 :                         sprintf(str + strlen(str), " %+03d", hour);
     942              :                 }
     943              :             }
     944            0 :             break;
     945              :     }
     946          318 : }
     947              : 
     948              : int
     949            0 : GetEpochTime(struct tm *tm)
     950              : {
     951              :     struct tm  *t0;
     952              :     struct tm   tmbuf;
     953            0 :     time_t      epoch = 0;
     954              : 
     955            0 :     t0 = gmtime_r(&epoch, &tmbuf);
     956              : 
     957            0 :     if (t0)
     958              :     {
     959            0 :         tm->tm_year = t0->tm_year + 1900;
     960            0 :         tm->tm_mon = t0->tm_mon + 1;
     961            0 :         tm->tm_mday = t0->tm_mday;
     962            0 :         tm->tm_hour = t0->tm_hour;
     963            0 :         tm->tm_min = t0->tm_min;
     964            0 :         tm->tm_sec = t0->tm_sec;
     965              : 
     966            0 :         return 0;
     967              :     }
     968              : 
     969            0 :     return -1;
     970              : }                               /* GetEpochTime() */
     971              : 
     972              : static void
     973            2 : abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
     974              : {
     975            2 :     time_t      time = (time_t) _time;
     976              :     struct tm  *tx;
     977              :     struct tm   tmbuf;
     978              : 
     979            2 :     errno = 0;
     980            2 :     if (tzp != NULL)
     981            2 :         tx = localtime_r(&time, &tmbuf);
     982              :     else
     983            0 :         tx = gmtime_r(&time, &tmbuf);
     984              : 
     985            2 :     if (!tx)
     986              :     {
     987            0 :         errno = PGTYPES_TS_BAD_TIMESTAMP;
     988            0 :         return;
     989              :     }
     990              : 
     991            2 :     tm->tm_year = tx->tm_year + 1900;
     992            2 :     tm->tm_mon = tx->tm_mon + 1;
     993            2 :     tm->tm_mday = tx->tm_mday;
     994            2 :     tm->tm_hour = tx->tm_hour;
     995            2 :     tm->tm_min = tx->tm_min;
     996            2 :     tm->tm_sec = tx->tm_sec;
     997            2 :     tm->tm_isdst = tx->tm_isdst;
     998              : 
     999              : #if defined(HAVE_STRUCT_TM_TM_ZONE)
    1000            2 :     tm->tm_gmtoff = tx->tm_gmtoff;
    1001            2 :     tm->tm_zone = tx->tm_zone;
    1002              : 
    1003            2 :     if (tzp != NULL)
    1004              :     {
    1005              :         /*
    1006              :          * We have a brute force time zone per SQL99? Then use it without
    1007              :          * change since we have already rotated to the time zone.
    1008              :          */
    1009            2 :         *tzp = -tm->tm_gmtoff;   /* tm_gmtoff is Sun/DEC-ism */
    1010              : 
    1011              :         /*
    1012              :          * FreeBSD man pages indicate that this should work - tgl 97/04/23
    1013              :          */
    1014            2 :         if (tzn != NULL)
    1015              :         {
    1016              :             /*
    1017              :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1018              :              * contains an error message, which doesn't fit in the buffer
    1019              :              */
    1020            0 :             strlcpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
    1021            0 :             if (strlen(tm->tm_zone) > MAXTZLEN)
    1022            0 :                 tm->tm_isdst = -1;
    1023              :         }
    1024              :     }
    1025              :     else
    1026            0 :         tm->tm_isdst = -1;
    1027              : #elif defined(HAVE_INT_TIMEZONE)
    1028              :     if (tzp != NULL)
    1029              :     {
    1030              :         *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
    1031              : 
    1032              :         if (tzn != NULL)
    1033              :         {
    1034              :             /*
    1035              :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1036              :              * contains an error message, which doesn't fit in the buffer
    1037              :              */
    1038              :             strlcpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1);
    1039              :             if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
    1040              :                 tm->tm_isdst = -1;
    1041              :         }
    1042              :     }
    1043              :     else
    1044              :         tm->tm_isdst = -1;
    1045              : #else                           /* not (HAVE_STRUCT_TM_TM_ZONE ||
    1046              :                                  * HAVE_INT_TIMEZONE) */
    1047              :     if (tzp != NULL)
    1048              :     {
    1049              :         /* default to UTC */
    1050              :         *tzp = 0;
    1051              :         if (tzn != NULL)
    1052              :             *tzn = NULL;
    1053              :     }
    1054              :     else
    1055              :         tm->tm_isdst = -1;
    1056              : #endif
    1057              : }
    1058              : 
    1059              : void
    1060            2 : GetCurrentDateTime(struct tm *tm)
    1061              : {
    1062              :     int         tz;
    1063              : 
    1064            2 :     abstime2tm(time(NULL), &tz, tm, NULL);
    1065            2 : }
    1066              : 
    1067              : void
    1068          328 : dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
    1069              : {
    1070              :     int64       time;
    1071              : 
    1072          328 :     time = jd;
    1073          328 :     *hour = time / USECS_PER_HOUR;
    1074          328 :     time -= (*hour) * USECS_PER_HOUR;
    1075          328 :     *min = time / USECS_PER_MINUTE;
    1076          328 :     time -= (*min) * USECS_PER_MINUTE;
    1077          328 :     *sec = time / USECS_PER_SEC;
    1078          328 :     *fsec = time - (*sec * USECS_PER_SEC);
    1079          328 : }                               /* dt2time() */
    1080              : 
    1081              : 
    1082              : 
    1083              : /* DecodeNumberField()
    1084              :  * Interpret numeric string as a concatenated date or time field.
    1085              :  * Use the context of previously decoded fields to help with
    1086              :  * the interpretation.
    1087              :  */
    1088              : static int
    1089           30 : DecodeNumberField(int len, char *str, int fmask,
    1090              :                   int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits)
    1091              : {
    1092              :     char       *cp;
    1093              : 
    1094              :     /*
    1095              :      * Have a decimal point? Then this is a date or something with a seconds
    1096              :      * field...
    1097              :      */
    1098           30 :     if ((cp = strchr(str, '.')) != NULL)
    1099              :     {
    1100              :         char        fstr[7];
    1101              :         int         i;
    1102              : 
    1103            0 :         cp++;
    1104              : 
    1105              :         /*
    1106              :          * OK, we have at most six digits to care about. Let's construct a
    1107              :          * string with those digits, zero-padded on the right, and then do the
    1108              :          * conversion to an integer.
    1109              :          *
    1110              :          * XXX This truncates the seventh digit, unlike rounding it as the
    1111              :          * backend does.
    1112              :          */
    1113            0 :         for (i = 0; i < 6; i++)
    1114            0 :             fstr[i] = *cp != '\0' ? *cp++ : '0';
    1115            0 :         fstr[i] = '\0';
    1116            0 :         *fsec = strtoint(fstr, NULL, 10);
    1117            0 :         *cp = '\0';
    1118            0 :         len = strlen(str);
    1119              :     }
    1120              :     /* No decimal point and no complete date yet? */
    1121           30 :     else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    1122              :     {
    1123              :         /* yyyymmdd? */
    1124           30 :         if (len == 8)
    1125              :         {
    1126           18 :             *tmask = DTK_DATE_M;
    1127              : 
    1128           18 :             tm->tm_mday = atoi(str + 6);
    1129           18 :             *(str + 6) = '\0';
    1130           18 :             tm->tm_mon = atoi(str + 4);
    1131           18 :             *(str + 4) = '\0';
    1132           18 :             tm->tm_year = atoi(str + 0);
    1133              : 
    1134           18 :             return DTK_DATE;
    1135              :         }
    1136              :         /* yymmdd? */
    1137           12 :         else if (len == 6)
    1138              :         {
    1139           12 :             *tmask = DTK_DATE_M;
    1140           12 :             tm->tm_mday = atoi(str + 4);
    1141           12 :             *(str + 4) = '\0';
    1142           12 :             tm->tm_mon = atoi(str + 2);
    1143           12 :             *(str + 2) = '\0';
    1144           12 :             tm->tm_year = atoi(str + 0);
    1145           12 :             *is2digits = true;
    1146              : 
    1147           12 :             return DTK_DATE;
    1148              :         }
    1149              :         /* yyddd? */
    1150            0 :         else if (len == 5)
    1151              :         {
    1152            0 :             *tmask = DTK_DATE_M;
    1153            0 :             tm->tm_mday = atoi(str + 2);
    1154            0 :             *(str + 2) = '\0';
    1155            0 :             tm->tm_mon = 1;
    1156            0 :             tm->tm_year = atoi(str + 0);
    1157            0 :             *is2digits = true;
    1158              : 
    1159            0 :             return DTK_DATE;
    1160              :         }
    1161              :     }
    1162              : 
    1163              :     /* not all time fields are specified? */
    1164            0 :     if ((fmask & DTK_TIME_M) != DTK_TIME_M)
    1165              :     {
    1166              :         /* hhmmss */
    1167            0 :         if (len == 6)
    1168              :         {
    1169            0 :             *tmask = DTK_TIME_M;
    1170            0 :             tm->tm_sec = atoi(str + 4);
    1171            0 :             *(str + 4) = '\0';
    1172            0 :             tm->tm_min = atoi(str + 2);
    1173            0 :             *(str + 2) = '\0';
    1174            0 :             tm->tm_hour = atoi(str + 0);
    1175              : 
    1176            0 :             return DTK_TIME;
    1177              :         }
    1178              :         /* hhmm? */
    1179            0 :         else if (len == 4)
    1180              :         {
    1181            0 :             *tmask = DTK_TIME_M;
    1182            0 :             tm->tm_sec = 0;
    1183            0 :             tm->tm_min = atoi(str + 2);
    1184            0 :             *(str + 2) = '\0';
    1185            0 :             tm->tm_hour = atoi(str + 0);
    1186              : 
    1187            0 :             return DTK_TIME;
    1188              :         }
    1189              :     }
    1190              : 
    1191            0 :     return -1;
    1192              : }                               /* DecodeNumberField() */
    1193              : 
    1194              : 
    1195              : /* DecodeNumber()
    1196              :  * Interpret plain numeric field as a date value in context.
    1197              :  */
    1198              : static int
    1199          796 : DecodeNumber(int flen, char *str, int fmask,
    1200              :              int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits, bool EuroDates)
    1201              : {
    1202              :     int         val;
    1203              :     char       *cp;
    1204              : 
    1205          796 :     *tmask = 0;
    1206              : 
    1207          796 :     val = strtoint(str, &cp, 10);
    1208          796 :     if (cp == str)
    1209            0 :         return -1;
    1210              : 
    1211          796 :     if (*cp == '.')
    1212              :     {
    1213              :         /*
    1214              :          * More than two digits? Then could be a date or a run-together time:
    1215              :          * 2001.360 20011225 040506.789
    1216              :          */
    1217            0 :         if (cp - str > 2)
    1218            0 :             return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
    1219              :                                      tmask, tm, fsec, is2digits);
    1220              : 
    1221            0 :         *fsec = strtod(cp, &cp);
    1222            0 :         if (*cp != '\0')
    1223            0 :             return -1;
    1224              :     }
    1225          796 :     else if (*cp != '\0')
    1226            0 :         return -1;
    1227              : 
    1228              :     /* Special case day of year? */
    1229          796 :     if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366)
    1230              :     {
    1231           12 :         *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
    1232           12 :         tm->tm_yday = val;
    1233           12 :         j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
    1234              :                &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1235              :     }
    1236              : 
    1237              :     /***
    1238              :      * Enough digits to be unequivocal year? Used to test for 4 digits or
    1239              :      * more, but we now test first for a three-digit doy so anything
    1240              :      * bigger than two digits had better be an explicit year.
    1241              :      * - thomas 1999-01-09
    1242              :      * Back to requiring a 4 digit year. We accept a two digit
    1243              :      * year farther down. - thomas 2000-03-28
    1244              :      ***/
    1245          784 :     else if (flen >= 4)
    1246              :     {
    1247          240 :         *tmask = DTK_M(YEAR);
    1248              : 
    1249              :         /* already have a year? then see if we can substitute... */
    1250          240 :         if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1251            0 :             tm->tm_year >= 1 && tm->tm_year <= 31)
    1252              :         {
    1253            0 :             tm->tm_mday = tm->tm_year;
    1254            0 :             *tmask = DTK_M(DAY);
    1255              :         }
    1256              : 
    1257          240 :         tm->tm_year = val;
    1258              :     }
    1259              : 
    1260              :     /* already have year? then could be month */
    1261          544 :     else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1262              :     {
    1263          112 :         *tmask = DTK_M(MONTH);
    1264          112 :         tm->tm_mon = val;
    1265              :     }
    1266              :     /* no year and EuroDates enabled? then could be day */
    1267          432 :     else if ((EuroDates || (fmask & DTK_M(MONTH))) &&
    1268          370 :              !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1269          174 :              val >= 1 && val <= 31)
    1270              :     {
    1271          162 :         *tmask = DTK_M(DAY);
    1272          162 :         tm->tm_mday = val;
    1273              :     }
    1274          270 :     else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1275              :     {
    1276           60 :         *tmask = DTK_M(MONTH);
    1277           60 :         tm->tm_mon = val;
    1278              :     }
    1279          210 :     else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31)
    1280              :     {
    1281          136 :         *tmask = DTK_M(DAY);
    1282          136 :         tm->tm_mday = val;
    1283              :     }
    1284              : 
    1285              :     /*
    1286              :      * Check for 2 or 4 or more digits, but currently we reach here only if
    1287              :      * two digits. - thomas 2000-03-28
    1288              :      */
    1289           74 :     else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2))
    1290              :     {
    1291           74 :         *tmask = DTK_M(YEAR);
    1292           74 :         tm->tm_year = val;
    1293              : 
    1294              :         /* adjust ONLY if exactly two digits... */
    1295           74 :         *is2digits = (flen == 2);
    1296              :     }
    1297              :     else
    1298            0 :         return -1;
    1299              : 
    1300          796 :     return 0;
    1301              : }                               /* DecodeNumber() */
    1302              : 
    1303              : /* DecodeDate()
    1304              :  * Decode date string which includes delimiters.
    1305              :  * Insist on a complete set of fields.
    1306              :  */
    1307              : static int
    1308          266 : DecodeDate(char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates)
    1309              : {
    1310              :     fsec_t      fsec;
    1311              : 
    1312          266 :     int         nf = 0;
    1313              :     int         i,
    1314              :                 len;
    1315          266 :     bool        bc = false;
    1316          266 :     bool        is2digits = false;
    1317              :     int         type,
    1318              :                 val,
    1319          266 :                 dmask = 0;
    1320              :     char       *field[MAXDATEFIELDS];
    1321              : 
    1322              :     /* parse this string... */
    1323         1048 :     while (*str != '\0' && nf < MAXDATEFIELDS)
    1324              :     {
    1325              :         /* skip field separators */
    1326          878 :         while (!isalnum((unsigned char) *str))
    1327           96 :             str++;
    1328              : 
    1329          782 :         field[nf] = str;
    1330          782 :         if (isdigit((unsigned char) *str))
    1331              :         {
    1332         2406 :             while (isdigit((unsigned char) *str))
    1333         1710 :                 str++;
    1334              :         }
    1335           86 :         else if (isalpha((unsigned char) *str))
    1336              :         {
    1337          546 :             while (isalpha((unsigned char) *str))
    1338          460 :                 str++;
    1339              :         }
    1340              : 
    1341              :         /* Just get rid of any non-digit, non-alpha characters... */
    1342          782 :         if (*str != '\0')
    1343          516 :             *str++ = '\0';
    1344          782 :         nf++;
    1345              :     }
    1346              : 
    1347              : #if 0
    1348              :     /* don't allow too many fields */
    1349              :     if (nf > 3)
    1350              :         return -1;
    1351              : #endif
    1352              : 
    1353          266 :     *tmask = 0;
    1354              : 
    1355              :     /* look first for text fields, since that will be unambiguous month */
    1356         1046 :     for (i = 0; i < nf; i++)
    1357              :     {
    1358          782 :         if (isalpha((unsigned char) *field[i]))
    1359              :         {
    1360           86 :             type = DecodeSpecial(i, field[i], &val);
    1361           86 :             if (type == IGNORE_DTF)
    1362            0 :                 continue;
    1363              : 
    1364           86 :             dmask = DTK_M(type);
    1365           86 :             switch (type)
    1366              :             {
    1367           84 :                 case MONTH:
    1368           84 :                     tm->tm_mon = val;
    1369           84 :                     break;
    1370              : 
    1371            0 :                 case ADBC:
    1372            0 :                     bc = (val == BC);
    1373            0 :                     break;
    1374              : 
    1375            2 :                 default:
    1376            2 :                     return -1;
    1377              :             }
    1378           84 :             if (fmask & dmask)
    1379            0 :                 return -1;
    1380              : 
    1381           84 :             fmask |= dmask;
    1382           84 :             *tmask |= dmask;
    1383              : 
    1384              :             /* mark this field as being completed */
    1385           84 :             field[i] = NULL;
    1386              :         }
    1387              :     }
    1388              : 
    1389              :     /* now pick up remaining numeric fields */
    1390         1044 :     for (i = 0; i < nf; i++)
    1391              :     {
    1392          780 :         if (field[i] == NULL)
    1393           84 :             continue;
    1394              : 
    1395          696 :         if ((len = strlen(field[i])) <= 0)
    1396            0 :             return -1;
    1397              : 
    1398          696 :         if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0)
    1399            0 :             return -1;
    1400              : 
    1401          696 :         if (fmask & dmask)
    1402            0 :             return -1;
    1403              : 
    1404          696 :         fmask |= dmask;
    1405          696 :         *tmask |= dmask;
    1406              :     }
    1407              : 
    1408          264 :     if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
    1409            0 :         return -1;
    1410              : 
    1411              :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    1412          264 :     if (bc)
    1413              :     {
    1414            0 :         if (tm->tm_year > 0)
    1415            0 :             tm->tm_year = -(tm->tm_year - 1);
    1416              :         else
    1417            0 :             return -1;
    1418              :     }
    1419          264 :     else if (is2digits)
    1420              :     {
    1421           62 :         if (tm->tm_year < 70)
    1422           24 :             tm->tm_year += 2000;
    1423           38 :         else if (tm->tm_year < 100)
    1424           38 :             tm->tm_year += 1900;
    1425              :     }
    1426              : 
    1427          264 :     return 0;
    1428              : }                               /* DecodeDate() */
    1429              : 
    1430              : 
    1431              : /* DecodeTime()
    1432              :  * Decode time string which includes delimiters.
    1433              :  * Only check the lower limit on hours, since this same code
    1434              :  *  can be used to represent time spans.
    1435              :  */
    1436              : int
    1437          250 : DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec)
    1438              : {
    1439              :     char       *cp;
    1440              : 
    1441          250 :     *tmask = DTK_TIME_M;
    1442              : 
    1443          250 :     tm->tm_hour = strtoint(str, &cp, 10);
    1444          250 :     if (*cp != ':')
    1445            0 :         return -1;
    1446          250 :     str = cp + 1;
    1447          250 :     tm->tm_min = strtoint(str, &cp, 10);
    1448          250 :     if (*cp == '\0')
    1449              :     {
    1450           68 :         tm->tm_sec = 0;
    1451           68 :         *fsec = 0;
    1452              :     }
    1453          182 :     else if (*cp != ':')
    1454            0 :         return -1;
    1455              :     else
    1456              :     {
    1457          182 :         str = cp + 1;
    1458          182 :         tm->tm_sec = strtoint(str, &cp, 10);
    1459          182 :         if (*cp == '\0')
    1460          114 :             *fsec = 0;
    1461           68 :         else if (*cp == '.')
    1462              :         {
    1463              :             char        fstr[7];
    1464              :             int         i;
    1465              : 
    1466           68 :             cp++;
    1467              : 
    1468              :             /*
    1469              :              * OK, we have at most six digits to care about. Let's construct a
    1470              :              * string with those digits, zero-padded on the right, and then do
    1471              :              * the conversion to an integer.
    1472              :              *
    1473              :              * XXX This truncates the seventh digit, unlike rounding it as the
    1474              :              * backend does.
    1475              :              */
    1476          476 :             for (i = 0; i < 6; i++)
    1477          408 :                 fstr[i] = *cp != '\0' ? *cp++ : '0';
    1478           68 :             fstr[i] = '\0';
    1479           68 :             *fsec = strtoint(fstr, &cp, 10);
    1480           68 :             if (*cp != '\0')
    1481            0 :                 return -1;
    1482              :         }
    1483              :         else
    1484            0 :             return -1;
    1485              :     }
    1486              : 
    1487              :     /* do a sanity check */
    1488          250 :     if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
    1489          250 :         tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC)
    1490            0 :         return -1;
    1491              : 
    1492          250 :     return 0;
    1493              : }                               /* DecodeTime() */
    1494              : 
    1495              : /* DecodeTimezone()
    1496              :  * Interpret string as a numeric timezone.
    1497              :  *
    1498              :  * Note: we allow timezone offsets up to 13:59.  There are places that
    1499              :  * use +1300 summer time.
    1500              :  */
    1501              : static int
    1502          118 : DecodeTimezone(char *str, int *tzp)
    1503              : {
    1504              :     int         tz;
    1505              :     int         hr,
    1506              :                 min;
    1507              :     char       *cp;
    1508              :     int         len;
    1509              : 
    1510              :     /* assume leading character is "+" or "-" */
    1511          118 :     hr = strtoint(str + 1, &cp, 10);
    1512              : 
    1513              :     /* explicit delimiter? */
    1514          118 :     if (*cp == ':')
    1515           34 :         min = strtoint(cp + 1, &cp, 10);
    1516              :     /* otherwise, might have run things together... */
    1517           84 :     else if (*cp == '\0' && (len = strlen(str)) > 3)
    1518              :     {
    1519           16 :         min = strtoint(str + len - 2, &cp, 10);
    1520           16 :         if (min < 0 || min >= 60)
    1521            0 :             return -1;
    1522              : 
    1523           16 :         *(str + len - 2) = '\0';
    1524           16 :         hr = strtoint(str + 1, &cp, 10);
    1525           16 :         if (hr < 0 || hr > 13)
    1526            0 :             return -1;
    1527              :     }
    1528              :     else
    1529           68 :         min = 0;
    1530              : 
    1531          118 :     tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
    1532          118 :     if (*str == '-')
    1533           34 :         tz = -tz;
    1534              : 
    1535          118 :     *tzp = -tz;
    1536          118 :     return *cp != '\0';
    1537              : }                               /* DecodeTimezone() */
    1538              : 
    1539              : 
    1540              : /* DecodePosixTimezone()
    1541              :  * Interpret string as a POSIX-compatible timezone:
    1542              :  *  PST-hh:mm
    1543              :  *  PST+h
    1544              :  * - thomas 2000-03-15
    1545              :  */
    1546              : static int
    1547            0 : DecodePosixTimezone(char *str, int *tzp)
    1548              : {
    1549              :     int         val,
    1550              :                 tz;
    1551              :     int         type;
    1552              :     char       *cp;
    1553              :     char        delim;
    1554              : 
    1555            0 :     cp = str;
    1556            0 :     while (*cp != '\0' && isalpha((unsigned char) *cp))
    1557            0 :         cp++;
    1558              : 
    1559            0 :     if (DecodeTimezone(cp, &tz) != 0)
    1560            0 :         return -1;
    1561              : 
    1562            0 :     delim = *cp;
    1563            0 :     *cp = '\0';
    1564            0 :     type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
    1565            0 :     *cp = delim;
    1566              : 
    1567            0 :     switch (type)
    1568              :     {
    1569            0 :         case DTZ:
    1570              :         case TZ:
    1571            0 :             *tzp = -(val + tz);
    1572            0 :             break;
    1573              : 
    1574            0 :         default:
    1575            0 :             return -1;
    1576              :     }
    1577              : 
    1578            0 :     return 0;
    1579              : }                               /* DecodePosixTimezone() */
    1580              : 
    1581              : /* ParseDateTime()
    1582              :  * Break string into tokens based on a date/time context.
    1583              :  * Several field types are assigned:
    1584              :  *  DTK_NUMBER - digits and (possibly) a decimal point
    1585              :  *  DTK_DATE - digits and two delimiters, or digits and text
    1586              :  *  DTK_TIME - digits, colon delimiters, and possibly a decimal point
    1587              :  *  DTK_STRING - text (no digits)
    1588              :  *  DTK_SPECIAL - leading "+" or "-" followed by text
    1589              :  *  DTK_TZ - leading "+" or "-" followed by digits
    1590              :  * Note that some field types can hold unexpected items:
    1591              :  *  DTK_NUMBER can hold date fields (yy.ddd)
    1592              :  *  DTK_STRING can hold months (January) and time zones (PST)
    1593              :  *  DTK_DATE can hold Posix time zones (GMT-8)
    1594              :  *
    1595              :  * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
    1596              :  * bytes of space.  On output, field[] entries will point into it.
    1597              :  * The field[] and ftype[] arrays must have at least MAXDATEFIELDS entries.
    1598              :  */
    1599              : int
    1600          418 : ParseDateTime(char *timestr, char *lowstr,
    1601              :               char **field, int *ftype, int *numfields, char **endstr)
    1602              : {
    1603          418 :     int         nf = 0;
    1604          418 :     char       *lp = lowstr;
    1605              : 
    1606          418 :     *endstr = timestr;
    1607              :     /* outer loop through fields */
    1608         2274 :     while (*(*endstr) != '\0')
    1609              :     {
    1610              :         /* Record start of current field */
    1611         1858 :         if (nf >= MAXDATEFIELDS)
    1612            2 :             return -1;
    1613         1856 :         field[nf] = lp;
    1614              : 
    1615              :         /* leading digit? then date or time */
    1616         1856 :         if (isdigit((unsigned char) *(*endstr)))
    1617              :         {
    1618          724 :             *lp++ = *(*endstr)++;
    1619         1872 :             while (isdigit((unsigned char) *(*endstr)))
    1620         1148 :                 *lp++ = *(*endstr)++;
    1621              : 
    1622              :             /* time field? */
    1623          724 :             if (*(*endstr) == ':')
    1624              :             {
    1625          250 :                 ftype[nf] = DTK_TIME;
    1626          250 :                 *lp++ = *(*endstr)++;
    1627          250 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1628         1772 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1629         1522 :                     *lp++ = *(*endstr)++;
    1630              :             }
    1631              :             /* date field? allow embedded text month */
    1632          474 :             else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1633          240 :             {
    1634              :                 /* save delimiting character to use later */
    1635          240 :                 char       *dp = (*endstr);
    1636              : 
    1637          240 :                 *lp++ = *(*endstr)++;
    1638              :                 /* second field is all digits? then no embedded text month */
    1639          240 :                 if (isdigit((unsigned char) *(*endstr)))
    1640              :                 {
    1641          180 :                     ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE;
    1642          498 :                     while (isdigit((unsigned char) *(*endstr)))
    1643          318 :                         *lp++ = *(*endstr)++;
    1644              : 
    1645              :                     /*
    1646              :                      * insist that the delimiters match to get a three-field
    1647              :                      * date.
    1648              :                      */
    1649          180 :                     if (*(*endstr) == *dp)
    1650              :                     {
    1651          168 :                         ftype[nf] = DTK_DATE;
    1652          168 :                         *lp++ = *(*endstr)++;
    1653          572 :                         while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1654          404 :                             *lp++ = *(*endstr)++;
    1655              :                     }
    1656              :                 }
    1657              :                 else
    1658              :                 {
    1659           60 :                     ftype[nf] = DTK_DATE;
    1660          444 :                     while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1661          384 :                         *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1662              :                 }
    1663              :             }
    1664              : 
    1665              :             /*
    1666              :              * otherwise, number only and will determine year, month, day, or
    1667              :              * concatenated fields later...
    1668              :              */
    1669              :             else
    1670          234 :                 ftype[nf] = DTK_NUMBER;
    1671              :         }
    1672              :         /* Leading decimal point? Then fractional seconds... */
    1673         1132 :         else if (*(*endstr) == '.')
    1674              :         {
    1675           98 :             *lp++ = *(*endstr)++;
    1676           98 :             while (isdigit((unsigned char) *(*endstr)))
    1677            0 :                 *lp++ = *(*endstr)++;
    1678              : 
    1679           98 :             ftype[nf] = DTK_NUMBER;
    1680              :         }
    1681              : 
    1682              :         /*
    1683              :          * text? then date string, month, day of week, special, or timezone
    1684              :          */
    1685         1034 :         else if (isalpha((unsigned char) *(*endstr)))
    1686              :         {
    1687          260 :             ftype[nf] = DTK_STRING;
    1688          260 :             *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1689         1242 :             while (isalpha((unsigned char) *(*endstr)))
    1690          982 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1691              : 
    1692              :             /*
    1693              :              * Full date string with leading text month? Could also be a POSIX
    1694              :              * time zone...
    1695              :              */
    1696          260 :             if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1697              :             {
    1698           24 :                 char       *dp = (*endstr);
    1699              : 
    1700           24 :                 ftype[nf] = DTK_DATE;
    1701           24 :                 *lp++ = *(*endstr)++;
    1702          168 :                 while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp)
    1703          144 :                     *lp++ = *(*endstr)++;
    1704              :             }
    1705              :         }
    1706              :         /* skip leading spaces */
    1707          774 :         else if (isspace((unsigned char) *(*endstr)))
    1708              :         {
    1709          628 :             (*endstr)++;
    1710          628 :             continue;
    1711              :         }
    1712              :         /* sign? then special or numeric timezone */
    1713          146 :         else if (*(*endstr) == '+' || *(*endstr) == '-')
    1714              :         {
    1715          102 :             *lp++ = *(*endstr)++;
    1716              :             /* soak up leading whitespace */
    1717          102 :             while (isspace((unsigned char) *(*endstr)))
    1718            0 :                 (*endstr)++;
    1719              :             /* numeric timezone? */
    1720          204 :             if (isdigit((unsigned char) *(*endstr)))
    1721              :             {
    1722          102 :                 ftype[nf] = DTK_TZ;
    1723          102 :                 *lp++ = *(*endstr)++;
    1724          102 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1725          204 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1726          102 :                     *lp++ = *(*endstr)++;
    1727              :             }
    1728              :             /* special? */
    1729            0 :             else if (isalpha((unsigned char) *(*endstr)))
    1730              :             {
    1731            0 :                 ftype[nf] = DTK_SPECIAL;
    1732            0 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1733            0 :                 while (isalpha((unsigned char) *(*endstr)))
    1734            0 :                     *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1735              :             }
    1736              :             /* otherwise something wrong... */
    1737              :             else
    1738            0 :                 return -1;
    1739              :         }
    1740              :         /* ignore punctuation but use as delimiter */
    1741           44 :         else if (ispunct((unsigned char) *(*endstr)))
    1742              :         {
    1743           44 :             (*endstr)++;
    1744           44 :             continue;
    1745              :         }
    1746              :         /* otherwise, something is not right... */
    1747              :         else
    1748            0 :             return -1;
    1749              : 
    1750              :         /* force in a delimiter after each field */
    1751         1184 :         *lp++ = '\0';
    1752         1184 :         nf++;
    1753              :     }
    1754              : 
    1755          416 :     *numfields = nf;
    1756              : 
    1757          416 :     return 0;
    1758              : }                               /* ParseDateTime() */
    1759              : 
    1760              : 
    1761              : /* DecodeDateTime()
    1762              :  * Interpret previously parsed fields for general date and time.
    1763              :  * Return 0 if full date, 1 if only time, and -1 if problems.
    1764              :  *      External format(s):
    1765              :  *              "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
    1766              :  *              "Fri Feb-7-1997 15:23:27"
    1767              :  *              "Feb-7-1997 15:23:27"
    1768              :  *              "2-7-1997 15:23:27"
    1769              :  *              "1997-2-7 15:23:27"
    1770              :  *              "1997.038 15:23:27"       (day of year 1-366)
    1771              :  *      Also supports input in compact time:
    1772              :  *              "970207 152327"
    1773              :  *              "97038 152327"
    1774              :  *              "20011225T040506.789-07"
    1775              :  *
    1776              :  * Use the system-provided functions to get the current time zone
    1777              :  *  if not specified in the input string.
    1778              :  * If the date is outside the time_t system-supported time range,
    1779              :  *  then assume UTC time zone. - thomas 1997-05-27
    1780              :  */
    1781              : int
    1782          358 : DecodeDateTime(char **field, int *ftype, int nf,
    1783              :                int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates)
    1784              : {
    1785          358 :     int         fmask = 0,
    1786              :                 tmask,
    1787              :                 type;
    1788          358 :     int         ptype = 0;      /* "prefix type" for ISO y2001m02d04 format */
    1789              :     int         i;
    1790              :     int         val;
    1791          358 :     int         mer = HR24;
    1792          358 :     bool        haveTextMonth = false;
    1793          358 :     bool        is2digits = false;
    1794          358 :     bool        bc = false;
    1795          358 :     int         t = 0;
    1796          358 :     int        *tzp = &t;
    1797              : 
    1798              :     /***
    1799              :      * We'll insist on at least all of the date fields, but initialize the
    1800              :      * remaining fields in case they are not set later...
    1801              :      ***/
    1802          358 :     *dtype = DTK_DATE;
    1803          358 :     tm->tm_hour = 0;
    1804          358 :     tm->tm_min = 0;
    1805          358 :     tm->tm_sec = 0;
    1806          358 :     *fsec = 0;
    1807              :     /* don't know daylight savings time status apriori */
    1808          358 :     tm->tm_isdst = -1;
    1809          358 :     if (tzp != NULL)
    1810          358 :         *tzp = 0;
    1811              : 
    1812         1248 :     for (i = 0; i < nf; i++)
    1813              :     {
    1814          900 :         switch (ftype[i])
    1815              :         {
    1816          252 :             case DTK_DATE:
    1817              :                 /***
    1818              :                  * Integral julian day with attached time zone?
    1819              :                  * All other forms with JD will be separated into
    1820              :                  * distinct fields, so we handle just this case here.
    1821              :                  ***/
    1822          252 :                 if (ptype == DTK_JULIAN)
    1823              :                 {
    1824              :                     char       *cp;
    1825              :                     int         jday;
    1826              : 
    1827            0 :                     if (tzp == NULL)
    1828            0 :                         return -1;
    1829              : 
    1830            0 :                     jday = strtoint(field[i], &cp, 10);
    1831            0 :                     if (*cp != '-')
    1832            0 :                         return -1;
    1833              : 
    1834            0 :                     j2date(jday, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1835              :                     /* Get the time zone from the end of the string */
    1836            0 :                     if (DecodeTimezone(cp, tzp) != 0)
    1837            0 :                         return -1;
    1838              : 
    1839            0 :                     tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
    1840            0 :                     ptype = 0;
    1841            0 :                     break;
    1842              :                 }
    1843              :                 /***
    1844              :                  * Already have a date? Then this might be a POSIX time
    1845              :                  * zone with an embedded dash (e.g. "PST-3" == "EST") or
    1846              :                  * a run-together time with trailing time zone (e.g. hhmmss-zz).
    1847              :                  * - thomas 2001-12-25
    1848              :                  ***/
    1849          252 :                 else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
    1850          252 :                          || (ptype != 0))
    1851              :                 {
    1852              :                     /* No time zone accepted? Then quit... */
    1853            0 :                     if (tzp == NULL)
    1854            0 :                         return -1;
    1855              : 
    1856            0 :                     if (isdigit((unsigned char) *field[i]) || ptype != 0)
    1857            0 :                     {
    1858              :                         char       *cp;
    1859              : 
    1860            0 :                         if (ptype != 0)
    1861              :                         {
    1862              :                             /* Sanity check; should not fail this test */
    1863            0 :                             if (ptype != DTK_TIME)
    1864            0 :                                 return -1;
    1865            0 :                             ptype = 0;
    1866              :                         }
    1867              : 
    1868              :                         /*
    1869              :                          * Starts with a digit but we already have a time
    1870              :                          * field? Then we are in trouble with a date and time
    1871              :                          * already...
    1872              :                          */
    1873            0 :                         if ((fmask & DTK_TIME_M) == DTK_TIME_M)
    1874            0 :                             return -1;
    1875              : 
    1876            0 :                         if ((cp = strchr(field[i], '-')) == NULL)
    1877            0 :                             return -1;
    1878              : 
    1879              :                         /* Get the time zone from the end of the string */
    1880            0 :                         if (DecodeTimezone(cp, tzp) != 0)
    1881            0 :                             return -1;
    1882            0 :                         *cp = '\0';
    1883              : 
    1884              :                         /*
    1885              :                          * Then read the rest of the field as a concatenated
    1886              :                          * time
    1887              :                          */
    1888            0 :                         if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask,
    1889              :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    1890            0 :                             return -1;
    1891              : 
    1892              :                         /*
    1893              :                          * modify tmask after returning from
    1894              :                          * DecodeNumberField()
    1895              :                          */
    1896            0 :                         tmask |= DTK_M(TZ);
    1897              :                     }
    1898              :                     else
    1899              :                     {
    1900            0 :                         if (DecodePosixTimezone(field[i], tzp) != 0)
    1901            0 :                             return -1;
    1902              : 
    1903            0 :                         ftype[i] = DTK_TZ;
    1904            0 :                         tmask = DTK_M(TZ);
    1905              :                     }
    1906              :                 }
    1907          252 :                 else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    1908            0 :                     return -1;
    1909          252 :                 break;
    1910              : 
    1911          248 :             case DTK_TIME:
    1912          248 :                 if (DecodeTime(field[i], &tmask, tm, fsec) != 0)
    1913            0 :                     return -1;
    1914              : 
    1915              :                 /*
    1916              :                  * Check upper limit on hours; other limits checked in
    1917              :                  * DecodeTime()
    1918              :                  */
    1919              :                 /* test for > 24:00:00 */
    1920          248 :                 if (tm->tm_hour > 24 ||
    1921          246 :                     (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
    1922            2 :                     return -1;
    1923          246 :                 break;
    1924              : 
    1925          102 :             case DTK_TZ:
    1926              :                 {
    1927              :                     int         tz;
    1928              : 
    1929          102 :                     if (tzp == NULL)
    1930            0 :                         return -1;
    1931              : 
    1932          102 :                     if (DecodeTimezone(field[i], &tz) != 0)
    1933            0 :                         return -1;
    1934              : 
    1935              :                     /*
    1936              :                      * Already have a time zone? Then maybe this is the second
    1937              :                      * field of a POSIX time: EST+3 (equivalent to PST)
    1938              :                      */
    1939          102 :                     if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
    1940            0 :                         ftype[i - 1] == DTK_TZ &&
    1941            0 :                         isalpha((unsigned char) *field[i - 1]))
    1942              :                     {
    1943            0 :                         *tzp -= tz;
    1944            0 :                         tmask = 0;
    1945              :                     }
    1946              :                     else
    1947              :                     {
    1948          102 :                         *tzp = tz;
    1949          102 :                         tmask = DTK_M(TZ);
    1950              :                     }
    1951              :                 }
    1952          102 :                 break;
    1953              : 
    1954          156 :             case DTK_NUMBER:
    1955              : 
    1956              :                 /*
    1957              :                  * Was this an "ISO date" with embedded field labels? An
    1958              :                  * example is "y2001m02d04" - thomas 2001-02-04
    1959              :                  */
    1960          156 :                 if (ptype != 0)
    1961              :                 {
    1962              :                     char       *cp;
    1963              :                     int         value;
    1964              : 
    1965           12 :                     value = strtoint(field[i], &cp, 10);
    1966              : 
    1967              :                     /*
    1968              :                      * only a few kinds are allowed to have an embedded
    1969              :                      * decimal
    1970              :                      */
    1971           12 :                     if (*cp == '.')
    1972            0 :                         switch (ptype)
    1973              :                         {
    1974            0 :                             case DTK_JULIAN:
    1975              :                             case DTK_TIME:
    1976              :                             case DTK_SECOND:
    1977            0 :                                 break;
    1978            0 :                             default:
    1979            0 :                                 return 1;
    1980              :                                 break;
    1981              :                         }
    1982           12 :                     else if (*cp != '\0')
    1983            0 :                         return -1;
    1984              : 
    1985           12 :                     switch (ptype)
    1986              :                     {
    1987            0 :                         case DTK_YEAR:
    1988            0 :                             tm->tm_year = value;
    1989            0 :                             tmask = DTK_M(YEAR);
    1990            0 :                             break;
    1991              : 
    1992            0 :                         case DTK_MONTH:
    1993              : 
    1994              :                             /*
    1995              :                              * already have a month and hour? then assume
    1996              :                              * minutes
    1997              :                              */
    1998            0 :                             if ((fmask & DTK_M(MONTH)) != 0 &&
    1999            0 :                                 (fmask & DTK_M(HOUR)) != 0)
    2000              :                             {
    2001            0 :                                 tm->tm_min = value;
    2002            0 :                                 tmask = DTK_M(MINUTE);
    2003              :                             }
    2004              :                             else
    2005              :                             {
    2006            0 :                                 tm->tm_mon = value;
    2007            0 :                                 tmask = DTK_M(MONTH);
    2008              :                             }
    2009            0 :                             break;
    2010              : 
    2011            0 :                         case DTK_DAY:
    2012            0 :                             tm->tm_mday = value;
    2013            0 :                             tmask = DTK_M(DAY);
    2014            0 :                             break;
    2015              : 
    2016            0 :                         case DTK_HOUR:
    2017            0 :                             tm->tm_hour = value;
    2018            0 :                             tmask = DTK_M(HOUR);
    2019            0 :                             break;
    2020              : 
    2021            0 :                         case DTK_MINUTE:
    2022            0 :                             tm->tm_min = value;
    2023            0 :                             tmask = DTK_M(MINUTE);
    2024            0 :                             break;
    2025              : 
    2026            0 :                         case DTK_SECOND:
    2027            0 :                             tm->tm_sec = value;
    2028            0 :                             tmask = DTK_M(SECOND);
    2029            0 :                             if (*cp == '.')
    2030              :                             {
    2031              :                                 double      frac;
    2032              : 
    2033            0 :                                 frac = strtod(cp, &cp);
    2034            0 :                                 if (*cp != '\0')
    2035            0 :                                     return -1;
    2036            0 :                                 *fsec = frac * 1000000;
    2037              :                             }
    2038            0 :                             break;
    2039              : 
    2040            0 :                         case DTK_TZ:
    2041            0 :                             tmask = DTK_M(TZ);
    2042            0 :                             if (DecodeTimezone(field[i], tzp) != 0)
    2043            0 :                                 return -1;
    2044            0 :                             break;
    2045              : 
    2046           12 :                         case DTK_JULIAN:
    2047              :                             /***
    2048              :                              * previous field was a label for "julian date"?
    2049              :                              ***/
    2050           12 :                             tmask = DTK_DATE_M;
    2051           12 :                             j2date(value, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2052              :                             /* fractional Julian Day? */
    2053           12 :                             if (*cp == '.')
    2054              :                             {
    2055              :                                 double      time;
    2056              : 
    2057            0 :                                 time = strtod(cp, &cp);
    2058            0 :                                 if (*cp != '\0')
    2059            0 :                                     return -1;
    2060              : 
    2061            0 :                                 tmask |= DTK_TIME_M;
    2062            0 :                                 dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
    2063              :                             }
    2064           12 :                             break;
    2065              : 
    2066            0 :                         case DTK_TIME:
    2067              :                             /* previous field was "t" for ISO time */
    2068            0 :                             if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M),
    2069              :                                                               &tmask, tm, fsec, &is2digits)) < 0)
    2070            0 :                                 return -1;
    2071              : 
    2072            0 :                             if (tmask != DTK_TIME_M)
    2073            0 :                                 return -1;
    2074            0 :                             break;
    2075              : 
    2076            0 :                         default:
    2077            0 :                             return -1;
    2078              :                             break;
    2079              :                     }
    2080              : 
    2081           12 :                     ptype = 0;
    2082           12 :                     *dtype = DTK_DATE;
    2083              :                 }
    2084              :                 else
    2085              :                 {
    2086              :                     char       *cp;
    2087              :                     int         flen;
    2088              : 
    2089          144 :                     flen = strlen(field[i]);
    2090          144 :                     cp = strchr(field[i], '.');
    2091              : 
    2092              :                     /* Embedded decimal and no date yet? */
    2093          144 :                     if (cp != NULL && !(fmask & DTK_DATE_M))
    2094              :                     {
    2095           14 :                         if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    2096            2 :                             return -1;
    2097              :                     }
    2098              :                     /* embedded decimal and several digits before? */
    2099          130 :                     else if (cp != NULL && flen - strlen(cp) > 2)
    2100              :                     {
    2101              :                         /*
    2102              :                          * Interpret as a concatenated date or time Set the
    2103              :                          * type field to allow decoding other fields later.
    2104              :                          * Example: 20011223 or 040506
    2105              :                          */
    2106            0 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2107              :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2108            0 :                             return -1;
    2109              :                     }
    2110          130 :                     else if (flen > 4)
    2111              :                     {
    2112           30 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2113              :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2114            0 :                             return -1;
    2115              :                     }
    2116              :                     /* otherwise it is a single date/time field... */
    2117          100 :                     else if (DecodeNumber(flen, field[i], fmask,
    2118              :                                           &tmask, tm, fsec, &is2digits, EuroDates) != 0)
    2119            0 :                         return -1;
    2120              :                 }
    2121          154 :                 break;
    2122              : 
    2123          142 :             case DTK_STRING:
    2124              :             case DTK_SPECIAL:
    2125          142 :                 type = DecodeSpecial(i, field[i], &val);
    2126          142 :                 if (type == IGNORE_DTF)
    2127            0 :                     continue;
    2128              : 
    2129          142 :                 tmask = DTK_M(type);
    2130          142 :                 switch (type)
    2131              :                 {
    2132            0 :                     case RESERV:
    2133            0 :                         switch (val)
    2134              :                         {
    2135            0 :                             case DTK_NOW:
    2136            0 :                                 tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
    2137            0 :                                 *dtype = DTK_DATE;
    2138            0 :                                 GetCurrentDateTime(tm);
    2139            0 :                                 break;
    2140              : 
    2141            0 :                             case DTK_YESTERDAY:
    2142            0 :                                 tmask = DTK_DATE_M;
    2143            0 :                                 *dtype = DTK_DATE;
    2144            0 :                                 GetCurrentDateTime(tm);
    2145            0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,
    2146              :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2147            0 :                                 tm->tm_hour = 0;
    2148            0 :                                 tm->tm_min = 0;
    2149            0 :                                 tm->tm_sec = 0;
    2150            0 :                                 break;
    2151              : 
    2152            0 :                             case DTK_TODAY:
    2153            0 :                                 tmask = DTK_DATE_M;
    2154            0 :                                 *dtype = DTK_DATE;
    2155            0 :                                 GetCurrentDateTime(tm);
    2156            0 :                                 tm->tm_hour = 0;
    2157            0 :                                 tm->tm_min = 0;
    2158            0 :                                 tm->tm_sec = 0;
    2159            0 :                                 break;
    2160              : 
    2161            0 :                             case DTK_TOMORROW:
    2162            0 :                                 tmask = DTK_DATE_M;
    2163            0 :                                 *dtype = DTK_DATE;
    2164            0 :                                 GetCurrentDateTime(tm);
    2165            0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,
    2166              :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2167            0 :                                 tm->tm_hour = 0;
    2168            0 :                                 tm->tm_min = 0;
    2169            0 :                                 tm->tm_sec = 0;
    2170            0 :                                 break;
    2171              : 
    2172            0 :                             case DTK_ZULU:
    2173            0 :                                 tmask = (DTK_TIME_M | DTK_M(TZ));
    2174            0 :                                 *dtype = DTK_DATE;
    2175            0 :                                 tm->tm_hour = 0;
    2176            0 :                                 tm->tm_min = 0;
    2177            0 :                                 tm->tm_sec = 0;
    2178            0 :                                 if (tzp != NULL)
    2179            0 :                                     *tzp = 0;
    2180            0 :                                 break;
    2181              : 
    2182            0 :                             default:
    2183            0 :                                 *dtype = val;
    2184              :                         }
    2185              : 
    2186            0 :                         break;
    2187              : 
    2188           50 :                     case MONTH:
    2189              : 
    2190              :                         /*
    2191              :                          * already have a (numeric) month? then see if we can
    2192              :                          * substitute...
    2193              :                          */
    2194           50 :                         if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
    2195            4 :                             !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31)
    2196              :                         {
    2197            4 :                             tm->tm_mday = tm->tm_mon;
    2198            4 :                             tmask = DTK_M(DAY);
    2199              :                         }
    2200           50 :                         haveTextMonth = true;
    2201           50 :                         tm->tm_mon = val;
    2202           50 :                         break;
    2203              : 
    2204            0 :                     case DTZMOD:
    2205              : 
    2206              :                         /*
    2207              :                          * daylight savings time modifier (solves "MET DST"
    2208              :                          * syntax)
    2209              :                          */
    2210            0 :                         tmask |= DTK_M(DTZ);
    2211            0 :                         tm->tm_isdst = 1;
    2212            0 :                         if (tzp == NULL)
    2213            0 :                             return -1;
    2214            0 :                         *tzp -= val;
    2215            0 :                         break;
    2216              : 
    2217           34 :                     case DTZ:
    2218              : 
    2219              :                         /*
    2220              :                          * set mask for TZ here _or_ check for DTZ later when
    2221              :                          * getting default timezone
    2222              :                          */
    2223           34 :                         tmask |= DTK_M(TZ);
    2224           34 :                         tm->tm_isdst = 1;
    2225           34 :                         if (tzp == NULL)
    2226            0 :                             return -1;
    2227           34 :                         *tzp = -val;
    2228           34 :                         ftype[i] = DTK_TZ;
    2229           34 :                         break;
    2230              : 
    2231            0 :                     case TZ:
    2232            0 :                         tm->tm_isdst = 0;
    2233            0 :                         if (tzp == NULL)
    2234            0 :                             return -1;
    2235            0 :                         *tzp = -val;
    2236            0 :                         ftype[i] = DTK_TZ;
    2237            0 :                         break;
    2238              : 
    2239            0 :                     case IGNORE_DTF:
    2240            0 :                         break;
    2241              : 
    2242            2 :                     case AMPM:
    2243            2 :                         mer = val;
    2244            2 :                         break;
    2245              : 
    2246           12 :                     case ADBC:
    2247           12 :                         bc = (val == BC);
    2248           12 :                         break;
    2249              : 
    2250           26 :                     case DOW:
    2251           26 :                         tm->tm_wday = val;
    2252           26 :                         break;
    2253              : 
    2254           12 :                     case UNITS:
    2255           12 :                         tmask = 0;
    2256           12 :                         ptype = val;
    2257           12 :                         break;
    2258              : 
    2259            0 :                     case ISOTIME:
    2260              : 
    2261              :                         /*
    2262              :                          * This is a filler field "t" indicating that the next
    2263              :                          * field is time. Try to verify that this is sensible.
    2264              :                          */
    2265            0 :                         tmask = 0;
    2266              : 
    2267              :                         /* No preceding date? Then quit... */
    2268            0 :                         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2269            0 :                             return -1;
    2270              : 
    2271              :                         /***
    2272              :                          * We will need one of the following fields:
    2273              :                          *  DTK_NUMBER should be hhmmss.fff
    2274              :                          *  DTK_TIME should be hh:mm:ss.fff
    2275              :                          *  DTK_DATE should be hhmmss-zz
    2276              :                          ***/
    2277            0 :                         if (i >= nf - 1 ||
    2278            0 :                             (ftype[i + 1] != DTK_NUMBER &&
    2279            0 :                              ftype[i + 1] != DTK_TIME &&
    2280            0 :                              ftype[i + 1] != DTK_DATE))
    2281            0 :                             return -1;
    2282              : 
    2283            0 :                         ptype = val;
    2284            0 :                         break;
    2285              : 
    2286            6 :                     default:
    2287            6 :                         return -1;
    2288              :                 }
    2289          136 :                 break;
    2290              : 
    2291            0 :             default:
    2292            0 :                 return -1;
    2293              :         }
    2294              : 
    2295          890 :         if (tmask & fmask)
    2296            0 :             return -1;
    2297          890 :         fmask |= tmask;
    2298              :     }
    2299              : 
    2300              :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    2301          348 :     if (bc)
    2302              :     {
    2303           12 :         if (tm->tm_year > 0)
    2304           12 :             tm->tm_year = -(tm->tm_year - 1);
    2305              :         else
    2306            0 :             return -1;
    2307              :     }
    2308          336 :     else if (is2digits)
    2309              :     {
    2310           12 :         if (tm->tm_year < 70)
    2311            0 :             tm->tm_year += 2000;
    2312           12 :         else if (tm->tm_year < 100)
    2313           12 :             tm->tm_year += 1900;
    2314              :     }
    2315              : 
    2316          348 :     if (mer != HR24 && tm->tm_hour > 12)
    2317            0 :         return -1;
    2318          348 :     if (mer == AM && tm->tm_hour == 12)
    2319            0 :         tm->tm_hour = 0;
    2320          348 :     else if (mer == PM && tm->tm_hour != 12)
    2321            0 :         tm->tm_hour += 12;
    2322              : 
    2323              :     /* do additional checking for full date specs... */
    2324          348 :     if (*dtype == DTK_DATE)
    2325              :     {
    2326          348 :         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2327            0 :             return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
    2328              : 
    2329              :         /*
    2330              :          * check for valid day of month and month, now that we know for sure
    2331              :          * the month and year...
    2332              :          */
    2333          348 :         if (tm->tm_mon < 1 || tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    2334            2 :             return -1;
    2335              : 
    2336              :         /*
    2337              :          * backend tried to find local timezone here but we don't use the
    2338              :          * result afterwards anyway so we only check for this error: daylight
    2339              :          * savings time modifier but no standard timezone?
    2340              :          */
    2341          346 :         if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD)))
    2342            0 :             return -1;
    2343              :     }
    2344              : 
    2345          346 :     return 0;
    2346              : }                               /* DecodeDateTime() */
    2347              : 
    2348              : /* Function works as follows:
    2349              :  *
    2350              :  *
    2351              :  * */
    2352              : 
    2353              : static char *
    2354          228 : find_end_token(char *str, char *fmt)
    2355              : {
    2356              :     /*
    2357              :      * str: here is28the day12the hour fmt: here is%dthe day%hthe hour
    2358              :      *
    2359              :      * we extract the 28, we read the percent sign and the type "d" then this
    2360              :      * functions gets called as find_end_token("28the day12the hour", "the
    2361              :      * day%hthehour")
    2362              :      *
    2363              :      * fmt points to "the day%hthehour", next_percent points to %hthehour and
    2364              :      * we have to find a match for everything between these positions ("the
    2365              :      * day"). We look for "the day" in str and know that the pattern we are
    2366              :      * about to scan ends where this string starts (right after the "28")
    2367              :      *
    2368              :      * At the end, *fmt is '\0' and *str isn't. end_position then is
    2369              :      * unchanged.
    2370              :      */
    2371          228 :     char       *end_position = NULL;
    2372              :     char       *next_percent,
    2373          228 :                *subst_location = NULL;
    2374          228 :     int         scan_offset = 0;
    2375              :     char        last_char;
    2376              : 
    2377              :     /* are we at the end? */
    2378          228 :     if (!*fmt)
    2379              :     {
    2380           34 :         end_position = fmt;
    2381           34 :         return end_position;
    2382              :     }
    2383              : 
    2384              :     /* not at the end */
    2385          198 :     while (fmt[scan_offset] == '%' && fmt[scan_offset + 1])
    2386              :     {
    2387              :         /*
    2388              :          * there is no delimiter, skip to the next delimiter if we're reading
    2389              :          * a number and then something that is not a number "9:15pm", we might
    2390              :          * be able to recover with the strtol end pointer. Go for the next
    2391              :          * percent sign
    2392              :          */
    2393            4 :         scan_offset += 2;
    2394              :     }
    2395          194 :     next_percent = strchr(fmt + scan_offset, '%');
    2396          194 :     if (next_percent)
    2397              :     {
    2398              :         /*
    2399              :          * we don't want to allocate extra memory, so we temporarily set the
    2400              :          * '%' sign to '\0' and call strstr However since we allow whitespace
    2401              :          * to float around everything, we have to shorten the pattern until we
    2402              :          * reach a non-whitespace character
    2403              :          */
    2404              : 
    2405          188 :         subst_location = next_percent;
    2406          214 :         while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset)
    2407           26 :             subst_location--;
    2408          188 :         last_char = *subst_location;
    2409          188 :         *subst_location = '\0';
    2410              : 
    2411              :         /*
    2412              :          * the haystack is the str and the needle is the original fmt but it
    2413              :          * ends at the position where the next percent sign would be
    2414              :          */
    2415              : 
    2416              :         /*
    2417              :          * There is one special case. Imagine: str = " 2", fmt = "%d %...",
    2418              :          * since we want to allow blanks as "dynamic" padding we have to
    2419              :          * accept this. Now, we are called with a fmt of " %..." and look for
    2420              :          * " " in str. We find it at the first position and never read the
    2421              :          * 2...
    2422              :          */
    2423          188 :         while (*str == ' ')
    2424            0 :             str++;
    2425          188 :         end_position = strstr(str, fmt + scan_offset);
    2426          188 :         *subst_location = last_char;
    2427              :     }
    2428              :     else
    2429              :     {
    2430              :         /*
    2431              :          * there is no other percent sign. So everything up to the end has to
    2432              :          * match.
    2433              :          */
    2434            6 :         end_position = str + strlen(str);
    2435              :     }
    2436          194 :     if (!end_position)
    2437              :     {
    2438              :         /*
    2439              :          * maybe we have the following case:
    2440              :          *
    2441              :          * str = "4:15am" fmt = "%M:%S %p"
    2442              :          *
    2443              :          * at this place we could have
    2444              :          *
    2445              :          * str = "15am" fmt = " %p"
    2446              :          *
    2447              :          * and have set fmt to " " because overwrote the % sign with a NULL
    2448              :          *
    2449              :          * In this case where we would have to match a space but can't find
    2450              :          * it, set end_position to the end of the string
    2451              :          */
    2452            2 :         if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location)
    2453            2 :             end_position = str + strlen(str);
    2454              :     }
    2455          194 :     return end_position;
    2456              : }
    2457              : 
    2458              : static int
    2459          228 : pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt)
    2460              : {
    2461              :     /*
    2462              :      * scan everything between pstr and pstr_end. This is not including the
    2463              :      * last character so we might set it to '\0' for the parsing
    2464              :      */
    2465              : 
    2466              :     char        last_char;
    2467          228 :     int         err = 0;
    2468              :     char       *pstr_end;
    2469          228 :     char       *strtol_end = NULL;
    2470              : 
    2471          228 :     while (**pstr == ' ')
    2472            0 :         pstr++;
    2473          228 :     pstr_end = find_end_token(*pstr, pfmt);
    2474          228 :     if (!pstr_end)
    2475              :     {
    2476              :         /* there was an error, no match */
    2477            0 :         return 1;
    2478              :     }
    2479          228 :     last_char = *pstr_end;
    2480          228 :     *pstr_end = '\0';
    2481              : 
    2482          228 :     switch (scan_type)
    2483              :     {
    2484          202 :         case PGTYPES_TYPE_UINT:
    2485              : 
    2486              :             /*
    2487              :              * numbers may be blank-padded, this is the only deviation from
    2488              :              * the fmt-string we accept
    2489              :              */
    2490          202 :             while (**pstr == ' ')
    2491            0 :                 (*pstr)++;
    2492          202 :             errno = 0;
    2493          202 :             scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
    2494          202 :             if (errno)
    2495            0 :                 err = 1;
    2496          202 :             break;
    2497            2 :         case PGTYPES_TYPE_UINT_LONG:
    2498            2 :             while (**pstr == ' ')
    2499            0 :                 (*pstr)++;
    2500            2 :             errno = 0;
    2501            2 :             scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
    2502            2 :             if (errno)
    2503            0 :                 err = 1;
    2504            2 :             break;
    2505           24 :         case PGTYPES_TYPE_STRING_MALLOCED:
    2506           24 :             scan_val->str_val = pgtypes_strdup(*pstr);
    2507           24 :             if (scan_val->str_val == NULL)
    2508            0 :                 err = 1;
    2509           24 :             break;
    2510              :     }
    2511          228 :     if (strtol_end && *strtol_end)
    2512           18 :         *pstr = strtol_end;
    2513              :     else
    2514          210 :         *pstr = pstr_end;
    2515          228 :     *pstr_end = last_char;
    2516          228 :     return err;
    2517              : }
    2518              : 
    2519              : /* XXX range checking */
    2520              : int
    2521           48 : PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
    2522              :                             int *year, int *month, int *day,
    2523              :                             int *hour, int *minute, int *second,
    2524              :                             int *tz)
    2525              : {
    2526              :     union un_fmt_comb scan_val;
    2527              :     int         scan_type;
    2528              : 
    2529              :     char       *pstr,
    2530              :                *pfmt,
    2531              :                *tmp;
    2532           48 :     int         err = 1;
    2533              :     unsigned int j;
    2534              :     struct tm   tm;
    2535              : 
    2536           48 :     pfmt = fmt;
    2537           48 :     pstr = *str;
    2538              : 
    2539          548 :     while (*pfmt)
    2540              :     {
    2541          504 :         err = 0;
    2542          708 :         while (*pfmt == ' ')
    2543          204 :             pfmt++;
    2544          750 :         while (*pstr == ' ')
    2545          246 :             pstr++;
    2546          504 :         if (*pfmt != '%')
    2547              :         {
    2548          196 :             if (*pfmt == *pstr)
    2549              :             {
    2550          192 :                 pfmt++;
    2551          192 :                 pstr++;
    2552              :             }
    2553              :             else
    2554              :             {
    2555              :                 /* Error: no match */
    2556            4 :                 err = 1;
    2557            4 :                 return err;
    2558              :             }
    2559          192 :             continue;
    2560              :         }
    2561              :         /* here *pfmt equals '%' */
    2562          308 :         pfmt++;
    2563          308 :         switch (*pfmt)
    2564              :         {
    2565           18 :             case 'a':
    2566           18 :                 pfmt++;
    2567              : 
    2568              :                 /*
    2569              :                  * we parse the day and see if it is a week day but we do not
    2570              :                  * check if the week day really matches the date
    2571              :                  */
    2572           18 :                 err = 1;
    2573           18 :                 j = 0;
    2574           50 :                 while (pgtypes_date_weekdays_short[j])
    2575              :                 {
    2576           50 :                     if (strncmp(pgtypes_date_weekdays_short[j], pstr,
    2577           50 :                                 strlen(pgtypes_date_weekdays_short[j])) == 0)
    2578              :                     {
    2579              :                         /* found it */
    2580           18 :                         err = 0;
    2581           18 :                         pstr += strlen(pgtypes_date_weekdays_short[j]);
    2582           18 :                         break;
    2583              :                     }
    2584           32 :                     j++;
    2585              :                 }
    2586           18 :                 break;
    2587            0 :             case 'A':
    2588              :                 /* see note above */
    2589            0 :                 pfmt++;
    2590            0 :                 err = 1;
    2591            0 :                 j = 0;
    2592            0 :                 while (days[j])
    2593              :                 {
    2594            0 :                     if (strncmp(days[j], pstr, strlen(days[j])) == 0)
    2595              :                     {
    2596              :                         /* found it */
    2597            0 :                         err = 0;
    2598            0 :                         pstr += strlen(days[j]);
    2599            0 :                         break;
    2600              :                     }
    2601            0 :                     j++;
    2602              :                 }
    2603            0 :                 break;
    2604           24 :             case 'b':
    2605              :             case 'h':
    2606           24 :                 pfmt++;
    2607           24 :                 err = 1;
    2608           24 :                 j = 0;
    2609          148 :                 while (months[j])
    2610              :                 {
    2611          148 :                     if (strncmp(months[j], pstr, strlen(months[j])) == 0)
    2612              :                     {
    2613              :                         /* found it */
    2614           24 :                         err = 0;
    2615           24 :                         pstr += strlen(months[j]);
    2616           24 :                         *month = j + 1;
    2617           24 :                         break;
    2618              :                     }
    2619          124 :                     j++;
    2620              :                 }
    2621           24 :                 break;
    2622           14 :             case 'B':
    2623              :                 /* see note above */
    2624           14 :                 pfmt++;
    2625           14 :                 err = 1;
    2626           14 :                 j = 0;
    2627          114 :                 while (pgtypes_date_months[j])
    2628              :                 {
    2629          114 :                     if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0)
    2630              :                     {
    2631              :                         /* found it */
    2632           14 :                         err = 0;
    2633           14 :                         pstr += strlen(pgtypes_date_months[j]);
    2634           14 :                         *month = j + 1;
    2635           14 :                         break;
    2636              :                     }
    2637          100 :                     j++;
    2638              :                 }
    2639           14 :                 break;
    2640            0 :             case 'c':
    2641              :                 /* XXX */
    2642            0 :                 break;
    2643            4 :             case 'C':
    2644            4 :                 pfmt++;
    2645            4 :                 scan_type = PGTYPES_TYPE_UINT;
    2646            4 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2647            4 :                 *year = scan_val.uint_val * 100;
    2648            4 :                 break;
    2649           42 :             case 'd':
    2650              :             case 'e':
    2651           42 :                 pfmt++;
    2652           42 :                 scan_type = PGTYPES_TYPE_UINT;
    2653           42 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2654           42 :                 *day = scan_val.uint_val;
    2655           42 :                 break;
    2656            0 :             case 'D':
    2657              : 
    2658              :                 /*
    2659              :                  * we have to concatenate the strings in order to be able to
    2660              :                  * find the end of the substitution
    2661              :                  */
    2662            0 :                 pfmt++;
    2663            0 :                 tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1);
    2664            0 :                 if (!tmp)
    2665            0 :                     return 1;
    2666            0 :                 strcpy(tmp, "%m/%d/%y");
    2667            0 :                 strcat(tmp, pfmt);
    2668            0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2669            0 :                 free(tmp);
    2670            0 :                 return err;
    2671            4 :             case 'm':
    2672            4 :                 pfmt++;
    2673            4 :                 scan_type = PGTYPES_TYPE_UINT;
    2674            4 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2675            4 :                 *month = scan_val.uint_val;
    2676            4 :                 break;
    2677            4 :             case 'y':
    2678              :             case 'g':           /* XXX difference to y (ISO) */
    2679            4 :                 pfmt++;
    2680            4 :                 scan_type = PGTYPES_TYPE_UINT;
    2681            4 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2682            4 :                 if (*year < 0)
    2683              :                 {
    2684              :                     /* not yet set */
    2685            2 :                     *year = scan_val.uint_val;
    2686              :                 }
    2687              :                 else
    2688            2 :                     *year += scan_val.uint_val;
    2689            4 :                 if (*year < 100)
    2690            2 :                     *year += 1900;
    2691            4 :                 break;
    2692            0 :             case 'G':
    2693              :                 /* XXX difference to %V (ISO) */
    2694            0 :                 pfmt++;
    2695            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2696            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2697            0 :                 *year = scan_val.uint_val;
    2698            0 :                 break;
    2699           42 :             case 'H':
    2700              :             case 'I':
    2701              :             case 'k':
    2702              :             case 'l':
    2703           42 :                 pfmt++;
    2704           42 :                 scan_type = PGTYPES_TYPE_UINT;
    2705           42 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2706           42 :                 *hour += scan_val.uint_val;
    2707           42 :                 break;
    2708            0 :             case 'j':
    2709            0 :                 pfmt++;
    2710            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2711            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2712              : 
    2713              :                 /*
    2714              :                  * XXX what should we do with that? We could say that it's
    2715              :                  * sufficient if we have the year and the day within the year
    2716              :                  * to get at least a specific day.
    2717              :                  */
    2718            0 :                 break;
    2719           40 :             case 'M':
    2720           40 :                 pfmt++;
    2721           40 :                 scan_type = PGTYPES_TYPE_UINT;
    2722           40 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2723           40 :                 *minute = scan_val.uint_val;
    2724           40 :                 break;
    2725            4 :             case 'n':
    2726            4 :                 pfmt++;
    2727            4 :                 if (*pstr == '\n')
    2728            4 :                     pstr++;
    2729              :                 else
    2730            0 :                     err = 1;
    2731            4 :                 break;
    2732            8 :             case 'p':
    2733            8 :                 err = 1;
    2734            8 :                 pfmt++;
    2735            8 :                 if (strncmp(pstr, "am", 2) == 0)
    2736              :                 {
    2737            6 :                     *hour += 0;
    2738            6 :                     err = 0;
    2739            6 :                     pstr += 2;
    2740              :                 }
    2741            8 :                 if (strncmp(pstr, "a.m.", 4) == 0)
    2742              :                 {
    2743            0 :                     *hour += 0;
    2744            0 :                     err = 0;
    2745            0 :                     pstr += 4;
    2746              :                 }
    2747            8 :                 if (strncmp(pstr, "pm", 2) == 0)
    2748              :                 {
    2749            2 :                     *hour += 12;
    2750            2 :                     err = 0;
    2751            2 :                     pstr += 2;
    2752              :                 }
    2753            8 :                 if (strncmp(pstr, "p.m.", 4) == 0)
    2754              :                 {
    2755            0 :                     *hour += 12;
    2756            0 :                     err = 0;
    2757            0 :                     pstr += 4;
    2758              :                 }
    2759            8 :                 break;
    2760            2 :             case 'P':
    2761            2 :                 err = 1;
    2762            2 :                 pfmt++;
    2763            2 :                 if (strncmp(pstr, "AM", 2) == 0)
    2764              :                 {
    2765            0 :                     *hour += 0;
    2766            0 :                     err = 0;
    2767            0 :                     pstr += 2;
    2768              :                 }
    2769            2 :                 if (strncmp(pstr, "A.M.", 4) == 0)
    2770              :                 {
    2771            0 :                     *hour += 0;
    2772            0 :                     err = 0;
    2773            0 :                     pstr += 4;
    2774              :                 }
    2775            2 :                 if (strncmp(pstr, "PM", 2) == 0)
    2776              :                 {
    2777            0 :                     *hour += 12;
    2778            0 :                     err = 0;
    2779            0 :                     pstr += 2;
    2780              :                 }
    2781            2 :                 if (strncmp(pstr, "P.M.", 4) == 0)
    2782              :                 {
    2783            2 :                     *hour += 12;
    2784            2 :                     err = 0;
    2785            2 :                     pstr += 4;
    2786              :                 }
    2787            2 :                 break;
    2788            0 :             case 'r':
    2789            0 :                 pfmt++;
    2790            0 :                 tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1);
    2791            0 :                 if (!tmp)
    2792            0 :                     return 1;
    2793            0 :                 strcpy(tmp, "%I:%M:%S %p");
    2794            0 :                 strcat(tmp, pfmt);
    2795            0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2796            0 :                 free(tmp);
    2797            0 :                 return err;
    2798            0 :             case 'R':
    2799            0 :                 pfmt++;
    2800            0 :                 tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1);
    2801            0 :                 if (!tmp)
    2802            0 :                     return 1;
    2803            0 :                 strcpy(tmp, "%H:%M");
    2804            0 :                 strcat(tmp, pfmt);
    2805            0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2806            0 :                 free(tmp);
    2807            0 :                 return err;
    2808            2 :             case 's':
    2809            2 :                 pfmt++;
    2810            2 :                 scan_type = PGTYPES_TYPE_UINT_LONG;
    2811            2 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2812              :                 /* number of seconds in scan_val.luint_val */
    2813              :                 {
    2814              :                     struct tm  *tms;
    2815              :                     struct tm   tmbuf;
    2816            2 :                     time_t      et = (time_t) scan_val.luint_val;
    2817              : 
    2818            2 :                     tms = gmtime_r(&et, &tmbuf);
    2819              : 
    2820            2 :                     if (tms)
    2821              :                     {
    2822            2 :                         *year = tms->tm_year + 1900;
    2823            2 :                         *month = tms->tm_mon + 1;
    2824            2 :                         *day = tms->tm_mday;
    2825            2 :                         *hour = tms->tm_hour;
    2826            2 :                         *minute = tms->tm_min;
    2827            2 :                         *second = tms->tm_sec;
    2828              :                     }
    2829              :                     else
    2830            0 :                         err = 1;
    2831              :                 }
    2832            2 :                 break;
    2833           30 :             case 'S':
    2834           30 :                 pfmt++;
    2835           30 :                 scan_type = PGTYPES_TYPE_UINT;
    2836           30 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2837           30 :                 *second = scan_val.uint_val;
    2838           30 :                 break;
    2839            0 :             case 't':
    2840            0 :                 pfmt++;
    2841            0 :                 if (*pstr == '\t')
    2842            0 :                     pstr++;
    2843              :                 else
    2844            0 :                     err = 1;
    2845            0 :                 break;
    2846            0 :             case 'T':
    2847            0 :                 pfmt++;
    2848            0 :                 tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1);
    2849            0 :                 if (!tmp)
    2850            0 :                     return 1;
    2851            0 :                 strcpy(tmp, "%H:%M:%S");
    2852            0 :                 strcat(tmp, pfmt);
    2853            0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2854            0 :                 free(tmp);
    2855            0 :                 return err;
    2856            0 :             case 'u':
    2857            0 :                 pfmt++;
    2858            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2859            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2860            0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 7)
    2861            0 :                     err = 1;
    2862            0 :                 break;
    2863            0 :             case 'U':
    2864            0 :                 pfmt++;
    2865            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2866            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2867            0 :                 if (scan_val.uint_val > 53)
    2868            0 :                     err = 1;
    2869            0 :                 break;
    2870            0 :             case 'V':
    2871            0 :                 pfmt++;
    2872            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2873            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2874            0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 53)
    2875            0 :                     err = 1;
    2876            0 :                 break;
    2877            0 :             case 'w':
    2878            0 :                 pfmt++;
    2879            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2880            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2881            0 :                 if (scan_val.uint_val > 6)
    2882            0 :                     err = 1;
    2883            0 :                 break;
    2884            0 :             case 'W':
    2885            0 :                 pfmt++;
    2886            0 :                 scan_type = PGTYPES_TYPE_UINT;
    2887            0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2888            0 :                 if (scan_val.uint_val > 53)
    2889            0 :                     err = 1;
    2890            0 :                 break;
    2891            0 :             case 'x':
    2892              :             case 'X':
    2893              :                 /* XXX */
    2894            0 :                 break;
    2895           36 :             case 'Y':
    2896           36 :                 pfmt++;
    2897           36 :                 scan_type = PGTYPES_TYPE_UINT;
    2898           36 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2899           36 :                 *year = scan_val.uint_val;
    2900           36 :                 break;
    2901           16 :             case 'z':
    2902           16 :                 pfmt++;
    2903           16 :                 scan_type = PGTYPES_TYPE_STRING_MALLOCED;
    2904           16 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2905           16 :                 if (!err)
    2906              :                 {
    2907           16 :                     err = DecodeTimezone(scan_val.str_val, tz);
    2908           16 :                     free(scan_val.str_val);
    2909              :                 }
    2910           16 :                 break;
    2911            8 :             case 'Z':
    2912            8 :                 pfmt++;
    2913            8 :                 scan_type = PGTYPES_TYPE_STRING_MALLOCED;
    2914            8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2915            8 :                 if (!err)
    2916              :                 {
    2917              :                     /*
    2918              :                      * XXX use DecodeSpecial instead?  Do we need strcasecmp
    2919              :                      * here?
    2920              :                      */
    2921            8 :                     err = 1;
    2922          400 :                     for (j = 0; j < szdatetktbl; j++)
    2923              :                     {
    2924          720 :                         if ((datetktbl[j].type == TZ || datetktbl[j].type == DTZ) &&
    2925          320 :                             pg_strcasecmp(datetktbl[j].token,
    2926          320 :                                           scan_val.str_val) == 0)
    2927              :                         {
    2928            8 :                             *tz = -datetktbl[j].value;
    2929            8 :                             err = 0;
    2930            8 :                             break;
    2931              :                         }
    2932              :                     }
    2933            8 :                     free(scan_val.str_val);
    2934              :                 }
    2935            8 :                 break;
    2936            0 :             case '+':
    2937              :                 /* XXX */
    2938            0 :                 break;
    2939            8 :             case '%':
    2940            8 :                 pfmt++;
    2941            8 :                 if (*pstr == '%')
    2942            8 :                     pstr++;
    2943              :                 else
    2944            0 :                     err = 1;
    2945            8 :                 break;
    2946            2 :             default:
    2947            2 :                 err = 1;
    2948              :         }
    2949              :     }
    2950           44 :     if (!err)
    2951              :     {
    2952           42 :         if (*second < 0)
    2953           10 :             *second = 0;
    2954           42 :         if (*minute < 0)
    2955            0 :             *minute = 0;
    2956           42 :         if (*hour < 0)
    2957            0 :             *hour = 0;
    2958           42 :         if (*day < 0)
    2959              :         {
    2960            0 :             err = 1;
    2961            0 :             *day = 1;
    2962              :         }
    2963           42 :         if (*month < 0)
    2964              :         {
    2965            0 :             err = 1;
    2966            0 :             *month = 1;
    2967              :         }
    2968           42 :         if (*year < 0)
    2969              :         {
    2970            0 :             err = 1;
    2971            0 :             *year = 1970;
    2972              :         }
    2973              : 
    2974           42 :         if (*second > 59)
    2975              :         {
    2976            0 :             err = 1;
    2977            0 :             *second = 0;
    2978              :         }
    2979           42 :         if (*minute > 59)
    2980              :         {
    2981            0 :             err = 1;
    2982            0 :             *minute = 0;
    2983              :         }
    2984           42 :         if (*hour > 24 ||        /* test for > 24:00:00 */
    2985           42 :             (*hour == 24 && (*minute > 0 || *second > 0)))
    2986              :         {
    2987            0 :             err = 1;
    2988            0 :             *hour = 0;
    2989              :         }
    2990           42 :         if (*month > MONTHS_PER_YEAR)
    2991              :         {
    2992            0 :             err = 1;
    2993            0 :             *month = 1;
    2994              :         }
    2995           42 :         if (*day > day_tab[isleap(*year)][*month - 1])
    2996              :         {
    2997            8 :             *day = day_tab[isleap(*year)][*month - 1];
    2998            8 :             err = 1;
    2999              :         }
    3000              : 
    3001           42 :         tm.tm_sec = *second;
    3002           42 :         tm.tm_min = *minute;
    3003           42 :         tm.tm_hour = *hour;
    3004           42 :         tm.tm_mday = *day;
    3005           42 :         tm.tm_mon = *month;
    3006           42 :         tm.tm_year = *year;
    3007              : 
    3008           42 :         tm2timestamp(&tm, 0, tz, d);
    3009              :     }
    3010           44 :     return err;
    3011              : }
    3012              : 
    3013              : /* XXX: 1900 is compiled in as the base for years */
        

Generated by: LCOV version 2.0-1