LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - dt_common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 672 1156 58.1 %
Date: 2019-11-13 22:07:24 Functions: 21 23 91.3 %
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         176 : datebsearch(const char *key, const datetkn *base, unsigned int nel)
     503             : {
     504         176 :     if (nel > 0)
     505             :     {
     506         176 :         const datetkn *last = base + nel - 1,
     507             :                    *position;
     508             :         int         result;
     509             : 
     510        1312 :         while (last >= base)
     511             :         {
     512        1116 :             position = base + ((last - base) >> 1);
     513             :             /* precheck the first character for a bit of extra speed */
     514        1116 :             result = (int) key[0] - (int) position->token[0];
     515        1116 :             if (result == 0)
     516             :             {
     517             :                 /* use strncmp so that we match truncated tokens */
     518         536 :                 result = strncmp(key, position->token, TOKMAXLEN);
     519         536 :                 if (result == 0)
     520         156 :                     return position;
     521             :             }
     522         960 :             if (result < 0)
     523         448 :                 last = position - 1;
     524             :             else
     525         512 :                 base = position + 1;
     526             :         }
     527             :     }
     528          20 :     return NULL;
     529             : }
     530             : 
     531             : /* DecodeUnits()
     532             :  * Decode text string using lookup table.
     533             :  * This routine supports time interval decoding.
     534             :  */
     535             : int
     536         176 : 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         296 :     if (deltacache[field] != NULL &&
     543         120 :         strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)
     544          80 :         tp = deltacache[field];
     545             :     else
     546          96 :         tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
     547         176 :     deltacache[field] = tp;
     548         176 :     if (tp == NULL)
     549             :     {
     550           4 :         type = UNKNOWN_FIELD;
     551           4 :         *val = 0;
     552             :     }
     553             :     else
     554             :     {
     555         172 :         type = tp->type;
     556         172 :         *val = tp->value;
     557             :     }
     558             : 
     559         176 :     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        3612 : date2j(int y, int m, int d)
     582             : {
     583             :     int         julian;
     584             :     int         century;
     585             : 
     586        3612 :     if (m > 2)
     587             :     {
     588         204 :         m += 1;
     589         204 :         y += 4800;
     590             :     }
     591             :     else
     592             :     {
     593        3408 :         m += 13;
     594        3408 :         y += 4799;
     595             :     }
     596             : 
     597        3612 :     century = y / 100;
     598        3612 :     julian = y * 365 - 32167;
     599        3612 :     julian += y / 4 - century + century / 4;
     600        3612 :     julian += 7834 * m / 256 + d;
     601             : 
     602        3612 :     return julian;
     603             : }                               /* date2j() */
     604             : 
     605             : void
     606        1128 : 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        1128 :     julian = jd;
     614        1128 :     julian += 32044;
     615        1128 :     quad = julian / 146097;
     616        1128 :     extra = (julian - quad * 146097) * 4 + 3;
     617        1128 :     julian += 60 + quad * 3 + extra / 146097;
     618        1128 :     quad = julian / 1461;
     619        1128 :     julian -= quad * 1461;
     620        1128 :     y = julian * 4 / 1461;
     621        1128 :     julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123;
     622        1128 :     y += quad * 4;
     623        1128 :     *year = y - 4800;
     624        1128 :     quad = julian * 2141 / 65536;
     625        1128 :     *day = julian - 7834 * quad / 256;
     626        1128 :     *month = (quad + 10) % 12 + 1;
     627             : 
     628        1128 :     return;
     629             : }                               /* j2date() */
     630             : 
     631             : /* DecodeSpecial()
     632             :  * Decode text string using lookup table.
     633             :  * Implement a cache lookup since it is likely that dates
     634             :  *  will be related in format.
     635             :  */
     636             : static int
     637         452 : DecodeSpecial(int field, char *lowtoken, int *val)
     638             : {
     639             :     int         type;
     640             :     const datetkn *tp;
     641             : 
     642             :     /* use strncmp so that we match truncated tokens */
     643         844 :     if (datecache[field] != NULL &&
     644         392 :         strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)
     645         372 :         tp = datecache[field];
     646             :     else
     647             :     {
     648          80 :         tp = NULL;
     649          80 :         if (!tp)
     650          80 :             tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
     651             :     }
     652         452 :     datecache[field] = tp;
     653         452 :     if (tp == NULL)
     654             :     {
     655          16 :         type = UNKNOWN_FIELD;
     656          16 :         *val = 0;
     657             :     }
     658             :     else
     659             :     {
     660         436 :         type = tp->type;
     661         436 :         *val = tp->value;
     662             :     }
     663             : 
     664         452 :     return type;
     665             : }                               /* DecodeSpecial() */
     666             : 
     667             : /* EncodeDateOnly()
     668             :  * Encode date as local time.
     669             :  */
     670             : void
     671         380 : EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates)
     672             : {
     673             :     Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
     674             : 
     675         380 :     switch (style)
     676             :     {
     677             :         case USE_ISO_DATES:
     678             :             /* compatible with ISO date formats */
     679         380 :             if (tm->tm_year > 0)
     680         376 :                 sprintf(str, "%04d-%02d-%02d",
     681             :                         tm->tm_year, tm->tm_mon, tm->tm_mday);
     682             :             else
     683           8 :                 sprintf(str, "%04d-%02d-%02d %s",
     684           4 :                         -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
     685         380 :             break;
     686             : 
     687             :         case USE_SQL_DATES:
     688             :             /* compatible with Oracle/Ingres date formats */
     689           0 :             if (EuroDates)
     690           0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     691             :             else
     692           0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     693           0 :             if (tm->tm_year > 0)
     694           0 :                 sprintf(str + 5, "/%04d", tm->tm_year);
     695             :             else
     696           0 :                 sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
     697           0 :             break;
     698             : 
     699             :         case USE_GERMAN_DATES:
     700             :             /* German-style date format */
     701           0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     702           0 :             if (tm->tm_year > 0)
     703           0 :                 sprintf(str + 5, ".%04d", tm->tm_year);
     704             :             else
     705           0 :                 sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
     706           0 :             break;
     707             : 
     708             :         case USE_POSTGRES_DATES:
     709             :         default:
     710             :             /* traditional date-only style for Postgres */
     711           0 :             if (EuroDates)
     712           0 :                 sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
     713             :             else
     714           0 :                 sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
     715           0 :             if (tm->tm_year > 0)
     716           0 :                 sprintf(str + 5, "-%04d", tm->tm_year);
     717             :             else
     718           0 :                 sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
     719           0 :             break;
     720             :     }
     721         380 : }
     722             : 
     723             : void
     724         136 : TrimTrailingZeros(char *str)
     725             : {
     726         136 :     int         len = strlen(str);
     727             : 
     728             :     /* chop off trailing zeros... but leave at least 2 fractional digits */
     729         476 :     while (*(str + len - 1) == '0' && *(str + len - 3) != '.')
     730             :     {
     731         204 :         len--;
     732         204 :         *(str + len) = '\0';
     733             :     }
     734         136 : }
     735             : 
     736             : /* EncodeDateTime()
     737             :  * Encode date and time interpreted as local time.
     738             :  *
     739             :  * tm and fsec are the value to encode, print_tz determines whether to include
     740             :  * a time zone (the difference between timestamp and timestamptz types), tz is
     741             :  * the numeric time zone offset, tzn is the textual time zone, which if
     742             :  * specified will be used instead of tz by some styles, style is the date
     743             :  * style, str is where to write the output.
     744             :  *
     745             :  * Supported date styles:
     746             :  *  Postgres - day mon hh:mm:ss yyyy tz
     747             :  *  SQL - mm/dd/yyyy hh:mm:ss.ss tz
     748             :  *  ISO - yyyy-mm-dd hh:mm:ss+/-tz
     749             :  *  German - dd.mm.yyyy hh:mm:ss tz
     750             :  * Variants (affects order of month and day for Postgres and SQL styles):
     751             :  *  US - mm/dd/yyyy
     752             :  *  European - dd/mm/yyyy
     753             :  */
     754             : void
     755         632 : EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
     756             : {
     757             :     int         day,
     758             :                 hour,
     759             :                 min;
     760             : 
     761             :     /*
     762             :      * Negative tm_isdst means we have no valid time zone translation.
     763             :      */
     764         632 :     if (tm->tm_isdst < 0)
     765         632 :         print_tz = false;
     766             : 
     767         632 :     switch (style)
     768             :     {
     769             :         case USE_ISO_DATES:
     770             :             /* Compatible with ISO-8601 date formats */
     771             : 
     772        1284 :             sprintf(str, "%04d-%02d-%02d %02d:%02d",
     773         652 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     774             :                     tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
     775             : 
     776             :             /*
     777             :              * Print fractional seconds if any.  The field widths here should
     778             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     779             :              */
     780         632 :             if (fsec != 0)
     781             :             {
     782         136 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     783         136 :                 TrimTrailingZeros(str);
     784             :             }
     785             :             else
     786         496 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     787             : 
     788         632 :             if (tm->tm_year <= 0)
     789          20 :                 sprintf(str + strlen(str), " BC");
     790             : 
     791         632 :             if (print_tz)
     792             :             {
     793           0 :                 hour = -(tz / SECS_PER_HOUR);
     794           0 :                 min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     795           0 :                 if (min != 0)
     796           0 :                     sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     797             :                 else
     798           0 :                     sprintf(str + strlen(str), "%+03d", hour);
     799             :             }
     800         632 :             break;
     801             : 
     802             :         case USE_SQL_DATES:
     803             :             /* Compatible with Oracle/Ingres date formats */
     804             : 
     805           0 :             if (EuroDates)
     806           0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     807             :             else
     808           0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     809             : 
     810           0 :             sprintf(str + 5, "/%04d %02d:%02d",
     811           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     812             :                     tm->tm_hour, tm->tm_min);
     813             : 
     814             :             /*
     815             :              * Print fractional seconds if any.  The field widths here should
     816             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     817             :              */
     818           0 :             if (fsec != 0)
     819             :             {
     820           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     821           0 :                 TrimTrailingZeros(str);
     822             :             }
     823             :             else
     824           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     825             : 
     826           0 :             if (tm->tm_year <= 0)
     827           0 :                 sprintf(str + strlen(str), " BC");
     828             : 
     829             :             /*
     830             :              * Note: the uses of %.*s in this function would be risky if the
     831             :              * timezone names ever contain non-ASCII characters.  However, all
     832             :              * TZ abbreviations in the IANA database are plain ASCII.
     833             :              */
     834             : 
     835           0 :             if (print_tz)
     836             :             {
     837           0 :                 if (tzn)
     838           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     839             :                 else
     840             :                 {
     841           0 :                     hour = -(tz / SECS_PER_HOUR);
     842           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     843           0 :                     if (min != 0)
     844           0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     845             :                     else
     846           0 :                         sprintf(str + strlen(str), "%+03d", hour);
     847             :                 }
     848             :             }
     849           0 :             break;
     850             : 
     851             :         case USE_GERMAN_DATES:
     852             :             /* German variant on European style */
     853             : 
     854           0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     855             : 
     856           0 :             sprintf(str + 5, ".%04d %02d:%02d",
     857           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     858             :                     tm->tm_hour, tm->tm_min);
     859             : 
     860             :             /*
     861             :              * Print fractional seconds if any.  The field widths here should
     862             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     863             :              */
     864           0 :             if (fsec != 0)
     865             :             {
     866           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     867           0 :                 TrimTrailingZeros(str);
     868             :             }
     869             :             else
     870           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     871             : 
     872           0 :             if (tm->tm_year <= 0)
     873           0 :                 sprintf(str + strlen(str), " BC");
     874             : 
     875           0 :             if (print_tz)
     876             :             {
     877           0 :                 if (tzn)
     878           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     879             :                 else
     880             :                 {
     881           0 :                     hour = -(tz / SECS_PER_HOUR);
     882           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     883           0 :                     if (min != 0)
     884           0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     885             :                     else
     886           0 :                         sprintf(str + strlen(str), "%+03d", hour);
     887             :                 }
     888             :             }
     889           0 :             break;
     890             : 
     891             :         case USE_POSTGRES_DATES:
     892             :         default:
     893             :             /* Backward-compatible with traditional Postgres abstime dates */
     894             : 
     895           0 :             day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
     896           0 :             tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
     897             : 
     898           0 :             memcpy(str, days[tm->tm_wday], 3);
     899           0 :             strcpy(str + 3, " ");
     900             : 
     901           0 :             if (EuroDates)
     902           0 :                 sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
     903             :             else
     904           0 :                 sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
     905             : 
     906           0 :             sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min);
     907             : 
     908             :             /*
     909             :              * Print fractional seconds if any.  The field widths here should
     910             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     911             :              */
     912           0 :             if (fsec != 0)
     913             :             {
     914           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     915           0 :                 TrimTrailingZeros(str);
     916             :             }
     917             :             else
     918           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     919             : 
     920           0 :             sprintf(str + strlen(str), " %04d",
     921           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
     922           0 :             if (tm->tm_year <= 0)
     923           0 :                 sprintf(str + strlen(str), " BC");
     924             : 
     925           0 :             if (print_tz)
     926             :             {
     927           0 :                 if (tzn)
     928           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     929             :                 else
     930             :                 {
     931             :                     /*
     932             :                      * We have a time zone, but no string version. Use the
     933             :                      * numeric form, but be sure to include a leading space to
     934             :                      * avoid formatting something which would be rejected by
     935             :                      * the date/time parser later. - thomas 2001-10-19
     936             :                      */
     937           0 :                     hour = -(tz / SECS_PER_HOUR);
     938           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     939           0 :                     if (min != 0)
     940           0 :                         sprintf(str + strlen(str), " %+03d:%02d", hour, min);
     941             :                     else
     942           0 :                         sprintf(str + strlen(str), " %+03d", hour);
     943             :                 }
     944             :             }
     945           0 :             break;
     946             :     }
     947         632 : }
     948             : 
     949             : int
     950           0 : GetEpochTime(struct tm *tm)
     951             : {
     952             :     struct tm  *t0;
     953           0 :     time_t      epoch = 0;
     954             : 
     955           0 :     t0 = gmtime(&epoch);
     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           4 : abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
     974             : {
     975           4 :     time_t      time = (time_t) _time;
     976             :     struct tm  *tx;
     977             : 
     978           4 :     errno = 0;
     979           4 :     if (tzp != NULL)
     980           4 :         tx = localtime((time_t *) &time);
     981             :     else
     982           0 :         tx = gmtime((time_t *) &time);
     983             : 
     984           4 :     if (!tx)
     985             :     {
     986           0 :         errno = PGTYPES_TS_BAD_TIMESTAMP;
     987           0 :         return;
     988             :     }
     989             : 
     990           4 :     tm->tm_year = tx->tm_year + 1900;
     991           4 :     tm->tm_mon = tx->tm_mon + 1;
     992           4 :     tm->tm_mday = tx->tm_mday;
     993           4 :     tm->tm_hour = tx->tm_hour;
     994           4 :     tm->tm_min = tx->tm_min;
     995           4 :     tm->tm_sec = tx->tm_sec;
     996           4 :     tm->tm_isdst = tx->tm_isdst;
     997             : 
     998             : #if defined(HAVE_STRUCT_TM_TM_ZONE)
     999           4 :     tm->tm_gmtoff = tx->tm_gmtoff;
    1000           4 :     tm->tm_zone = tx->tm_zone;
    1001             : 
    1002           4 :     if (tzp != NULL)
    1003             :     {
    1004             :         /*
    1005             :          * We have a brute force time zone per SQL99? Then use it without
    1006             :          * change since we have already rotated to the time zone.
    1007             :          */
    1008           4 :         *tzp = -tm->tm_gmtoff;   /* tm_gmtoff is Sun/DEC-ism */
    1009             : 
    1010             :         /*
    1011             :          * FreeBSD man pages indicate that this should work - tgl 97/04/23
    1012             :          */
    1013           4 :         if (tzn != NULL)
    1014             :         {
    1015             :             /*
    1016             :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1017             :              * contains an error message, which doesn't fit in the buffer
    1018             :              */
    1019           0 :             StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
    1020           0 :             if (strlen(tm->tm_zone) > MAXTZLEN)
    1021           0 :                 tm->tm_isdst = -1;
    1022             :         }
    1023             :     }
    1024             :     else
    1025           0 :         tm->tm_isdst = -1;
    1026             : #elif defined(HAVE_INT_TIMEZONE)
    1027             :     if (tzp != NULL)
    1028             :     {
    1029             :         *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
    1030             : 
    1031             :         if (tzn != NULL)
    1032             :         {
    1033             :             /*
    1034             :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1035             :              * contains an error message, which doesn't fit in the buffer
    1036             :              */
    1037             :             StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1);
    1038             :             if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
    1039             :                 tm->tm_isdst = -1;
    1040             :         }
    1041             :     }
    1042             :     else
    1043             :         tm->tm_isdst = -1;
    1044             : #else                           /* not (HAVE_STRUCT_TM_TM_ZONE || HAVE_INT_TIMEZONE) */
    1045             :     if (tzp != NULL)
    1046             :     {
    1047             :         /* default to UTC */
    1048             :         *tzp = 0;
    1049             :         if (tzn != NULL)
    1050             :             *tzn = NULL;
    1051             :     }
    1052             :     else
    1053             :         tm->tm_isdst = -1;
    1054             : #endif
    1055             : }
    1056             : 
    1057             : void
    1058           4 : GetCurrentDateTime(struct tm *tm)
    1059             : {
    1060             :     int         tz;
    1061             : 
    1062           4 :     abstime2tm(time(NULL), &tz, tm, NULL);
    1063           4 : }
    1064             : 
    1065             : void
    1066         644 : dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
    1067             : {
    1068             :     int64       time;
    1069             : 
    1070         644 :     time = jd;
    1071         644 :     *hour = time / USECS_PER_HOUR;
    1072         644 :     time -= (*hour) * USECS_PER_HOUR;
    1073         644 :     *min = time / USECS_PER_MINUTE;
    1074         644 :     time -= (*min) * USECS_PER_MINUTE;
    1075         644 :     *sec = time / USECS_PER_SEC;
    1076         644 :     *fsec = time - (*sec * USECS_PER_SEC);
    1077         644 : }                               /* dt2time() */
    1078             : 
    1079             : 
    1080             : 
    1081             : /* DecodeNumberField()
    1082             :  * Interpret numeric string as a concatenated date or time field.
    1083             :  * Use the context of previously decoded fields to help with
    1084             :  * the interpretation.
    1085             :  */
    1086             : static int
    1087          56 : DecodeNumberField(int len, char *str, int fmask,
    1088             :                   int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits)
    1089             : {
    1090             :     char       *cp;
    1091             : 
    1092             :     /*
    1093             :      * Have a decimal point? Then this is a date or something with a seconds
    1094             :      * field...
    1095             :      */
    1096          56 :     if ((cp = strchr(str, '.')) != NULL)
    1097             :     {
    1098             :         char        fstr[7];
    1099             :         int         i;
    1100             : 
    1101           0 :         cp++;
    1102             : 
    1103             :         /*
    1104             :          * OK, we have at most six digits to care about. Let's construct a
    1105             :          * string with those digits, zero-padded on the right, and then do the
    1106             :          * conversion to an integer.
    1107             :          *
    1108             :          * XXX This truncates the seventh digit, unlike rounding it as the
    1109             :          * backend does.
    1110             :          */
    1111           0 :         for (i = 0; i < 6; i++)
    1112           0 :             fstr[i] = *cp != '\0' ? *cp++ : '0';
    1113           0 :         fstr[i] = '\0';
    1114           0 :         *fsec = strtoint(fstr, NULL, 10);
    1115           0 :         *cp = '\0';
    1116           0 :         len = strlen(str);
    1117             :     }
    1118             :     /* No decimal point and no complete date yet? */
    1119          56 :     else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    1120             :     {
    1121             :         /* yyyymmdd? */
    1122          56 :         if (len == 8)
    1123             :         {
    1124          32 :             *tmask = DTK_DATE_M;
    1125             : 
    1126          32 :             tm->tm_mday = atoi(str + 6);
    1127          32 :             *(str + 6) = '\0';
    1128          32 :             tm->tm_mon = atoi(str + 4);
    1129          32 :             *(str + 4) = '\0';
    1130          32 :             tm->tm_year = atoi(str + 0);
    1131             : 
    1132          32 :             return DTK_DATE;
    1133             :         }
    1134             :         /* yymmdd? */
    1135          24 :         else if (len == 6)
    1136             :         {
    1137          24 :             *tmask = DTK_DATE_M;
    1138          24 :             tm->tm_mday = atoi(str + 4);
    1139          24 :             *(str + 4) = '\0';
    1140          24 :             tm->tm_mon = atoi(str + 2);
    1141          24 :             *(str + 2) = '\0';
    1142          24 :             tm->tm_year = atoi(str + 0);
    1143          24 :             *is2digits = true;
    1144             : 
    1145          24 :             return DTK_DATE;
    1146             :         }
    1147             :         /* yyddd? */
    1148           0 :         else if (len == 5)
    1149             :         {
    1150           0 :             *tmask = DTK_DATE_M;
    1151           0 :             tm->tm_mday = atoi(str + 2);
    1152           0 :             *(str + 2) = '\0';
    1153           0 :             tm->tm_mon = 1;
    1154           0 :             tm->tm_year = atoi(str + 0);
    1155           0 :             *is2digits = true;
    1156             : 
    1157           0 :             return DTK_DATE;
    1158             :         }
    1159             :     }
    1160             : 
    1161             :     /* not all time fields are specified? */
    1162           0 :     if ((fmask & DTK_TIME_M) != DTK_TIME_M)
    1163             :     {
    1164             :         /* hhmmss */
    1165           0 :         if (len == 6)
    1166             :         {
    1167           0 :             *tmask = DTK_TIME_M;
    1168           0 :             tm->tm_sec = atoi(str + 4);
    1169           0 :             *(str + 4) = '\0';
    1170           0 :             tm->tm_min = atoi(str + 2);
    1171           0 :             *(str + 2) = '\0';
    1172           0 :             tm->tm_hour = atoi(str + 0);
    1173             : 
    1174           0 :             return DTK_TIME;
    1175             :         }
    1176             :         /* hhmm? */
    1177           0 :         else if (len == 4)
    1178             :         {
    1179           0 :             *tmask = DTK_TIME_M;
    1180           0 :             tm->tm_sec = 0;
    1181           0 :             tm->tm_min = atoi(str + 2);
    1182           0 :             *(str + 2) = '\0';
    1183           0 :             tm->tm_hour = atoi(str + 0);
    1184             : 
    1185           0 :             return DTK_TIME;
    1186             :         }
    1187             :     }
    1188             : 
    1189           0 :     return -1;
    1190             : }                               /* DecodeNumberField() */
    1191             : 
    1192             : 
    1193             : /* DecodeNumber()
    1194             :  * Interpret plain numeric field as a date value in context.
    1195             :  */
    1196             : static int
    1197        1592 : DecodeNumber(int flen, char *str, int fmask,
    1198             :              int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits, bool EuroDates)
    1199             : {
    1200             :     int         val;
    1201             :     char       *cp;
    1202             : 
    1203        1592 :     *tmask = 0;
    1204             : 
    1205        1592 :     val = strtoint(str, &cp, 10);
    1206        1592 :     if (cp == str)
    1207           0 :         return -1;
    1208             : 
    1209        1592 :     if (*cp == '.')
    1210             :     {
    1211             :         /*
    1212             :          * More than two digits? Then could be a date or a run-together time:
    1213             :          * 2001.360 20011225 040506.789
    1214             :          */
    1215           0 :         if (cp - str > 2)
    1216           0 :             return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
    1217             :                                      tmask, tm, fsec, is2digits);
    1218             : 
    1219           0 :         *fsec = strtod(cp, &cp);
    1220           0 :         if (*cp != '\0')
    1221           0 :             return -1;
    1222             :     }
    1223        1592 :     else if (*cp != '\0')
    1224           0 :         return -1;
    1225             : 
    1226             :     /* Special case day of year? */
    1227        1592 :     if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366)
    1228             :     {
    1229          24 :         *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
    1230          24 :         tm->tm_yday = val;
    1231          24 :         j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
    1232             :                &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1233             :     }
    1234             : 
    1235             :     /***
    1236             :      * Enough digits to be unequivocal year? Used to test for 4 digits or
    1237             :      * more, but we now test first for a three-digit doy so anything
    1238             :      * bigger than two digits had better be an explicit year.
    1239             :      * - thomas 1999-01-09
    1240             :      * Back to requiring a 4 digit year. We accept a two digit
    1241             :      * year farther down. - thomas 2000-03-28
    1242             :      ***/
    1243        1568 :     else if (flen >= 4)
    1244             :     {
    1245         480 :         *tmask = DTK_M(YEAR);
    1246             : 
    1247             :         /* already have a year? then see if we can substitute... */
    1248         480 :         if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1249           0 :             tm->tm_year >= 1 && tm->tm_year <= 31)
    1250             :         {
    1251           0 :             tm->tm_mday = tm->tm_year;
    1252           0 :             *tmask = DTK_M(DAY);
    1253             :         }
    1254             : 
    1255         480 :         tm->tm_year = val;
    1256             :     }
    1257             : 
    1258             :     /* already have year? then could be month */
    1259        1088 :     else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1260             :     {
    1261         224 :         *tmask = DTK_M(MONTH);
    1262         224 :         tm->tm_mon = val;
    1263             :     }
    1264             :     /* no year and EuroDates enabled? then could be day */
    1265        1604 :     else if ((EuroDates || (fmask & DTK_M(MONTH))) &&
    1266        1208 :              !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1267         348 :              val >= 1 && val <= 31)
    1268             :     {
    1269         324 :         *tmask = DTK_M(DAY);
    1270         324 :         tm->tm_mday = val;
    1271             :     }
    1272         540 :     else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1273             :     {
    1274         120 :         *tmask = DTK_M(MONTH);
    1275         120 :         tm->tm_mon = val;
    1276             :     }
    1277         420 :     else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31)
    1278             :     {
    1279         272 :         *tmask = DTK_M(DAY);
    1280         272 :         tm->tm_mday = val;
    1281             :     }
    1282             : 
    1283             :     /*
    1284             :      * Check for 2 or 4 or more digits, but currently we reach here only if
    1285             :      * two digits. - thomas 2000-03-28
    1286             :      */
    1287         148 :     else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2))
    1288             :     {
    1289         148 :         *tmask = DTK_M(YEAR);
    1290         148 :         tm->tm_year = val;
    1291             : 
    1292             :         /* adjust ONLY if exactly two digits... */
    1293         148 :         *is2digits = (flen == 2);
    1294             :     }
    1295             :     else
    1296           0 :         return -1;
    1297             : 
    1298        1592 :     return 0;
    1299             : }                               /* DecodeNumber() */
    1300             : 
    1301             : /* DecodeDate()
    1302             :  * Decode date string which includes delimiters.
    1303             :  * Insist on a complete set of fields.
    1304             :  */
    1305             : static int
    1306         532 : DecodeDate(char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates)
    1307             : {
    1308             :     fsec_t      fsec;
    1309             : 
    1310         532 :     int         nf = 0;
    1311             :     int         i,
    1312             :                 len;
    1313         532 :     bool        bc = false;
    1314         532 :     bool        is2digits = false;
    1315             :     int         type,
    1316             :                 val,
    1317         532 :                 dmask = 0;
    1318             :     char       *field[MAXDATEFIELDS];
    1319             : 
    1320             :     /* parse this string... */
    1321        2628 :     while (*str != '\0' && nf < MAXDATEFIELDS)
    1322             :     {
    1323             :         /* skip field separators */
    1324        3320 :         while (!isalnum((unsigned char) *str))
    1325         192 :             str++;
    1326             : 
    1327        1564 :         field[nf] = str;
    1328        1564 :         if (isdigit((unsigned char) *str))
    1329             :         {
    1330        6204 :             while (isdigit((unsigned char) *str))
    1331        3420 :                 str++;
    1332             :         }
    1333         172 :         else if (isalpha((unsigned char) *str))
    1334             :         {
    1335        1264 :             while (isalpha((unsigned char) *str))
    1336         920 :                 str++;
    1337             :         }
    1338             : 
    1339             :         /* Just get rid of any non-digit, non-alpha characters... */
    1340        1564 :         if (*str != '\0')
    1341        1032 :             *str++ = '\0';
    1342        1564 :         nf++;
    1343             :     }
    1344             : 
    1345             : #if 0
    1346             :     /* don't allow too many fields */
    1347             :     if (nf > 3)
    1348             :         return -1;
    1349             : #endif
    1350             : 
    1351         532 :     *tmask = 0;
    1352             : 
    1353             :     /* look first for text fields, since that will be unambiguous month */
    1354        2092 :     for (i = 0; i < nf; i++)
    1355             :     {
    1356        1564 :         if (isalpha((unsigned char) *field[i]))
    1357             :         {
    1358         172 :             type = DecodeSpecial(i, field[i], &val);
    1359         172 :             if (type == IGNORE_DTF)
    1360           0 :                 continue;
    1361             : 
    1362         172 :             dmask = DTK_M(type);
    1363         172 :             switch (type)
    1364             :             {
    1365             :                 case MONTH:
    1366         168 :                     tm->tm_mon = val;
    1367         168 :                     break;
    1368             : 
    1369             :                 case ADBC:
    1370           0 :                     bc = (val == BC);
    1371           0 :                     break;
    1372             : 
    1373             :                 default:
    1374           4 :                     return -1;
    1375             :             }
    1376         168 :             if (fmask & dmask)
    1377           0 :                 return -1;
    1378             : 
    1379         168 :             fmask |= dmask;
    1380         168 :             *tmask |= dmask;
    1381             : 
    1382             :             /* mark this field as being completed */
    1383         168 :             field[i] = NULL;
    1384             :         }
    1385             :     }
    1386             : 
    1387             :     /* now pick up remaining numeric fields */
    1388        2088 :     for (i = 0; i < nf; i++)
    1389             :     {
    1390        1560 :         if (field[i] == NULL)
    1391         168 :             continue;
    1392             : 
    1393        1392 :         if ((len = strlen(field[i])) <= 0)
    1394           0 :             return -1;
    1395             : 
    1396        1392 :         if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0)
    1397           0 :             return -1;
    1398             : 
    1399        1392 :         if (fmask & dmask)
    1400           0 :             return -1;
    1401             : 
    1402        1392 :         fmask |= dmask;
    1403        1392 :         *tmask |= dmask;
    1404             :     }
    1405             : 
    1406         528 :     if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
    1407           0 :         return -1;
    1408             : 
    1409             :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    1410         528 :     if (bc)
    1411             :     {
    1412           0 :         if (tm->tm_year > 0)
    1413           0 :             tm->tm_year = -(tm->tm_year - 1);
    1414             :         else
    1415           0 :             return -1;
    1416             :     }
    1417         528 :     else if (is2digits)
    1418             :     {
    1419         124 :         if (tm->tm_year < 70)
    1420          48 :             tm->tm_year += 2000;
    1421          76 :         else if (tm->tm_year < 100)
    1422          76 :             tm->tm_year += 1900;
    1423             :     }
    1424             : 
    1425         528 :     return 0;
    1426             : }                               /* DecodeDate() */
    1427             : 
    1428             : 
    1429             : /* DecodeTime()
    1430             :  * Decode time string which includes delimiters.
    1431             :  * Only check the lower limit on hours, since this same code
    1432             :  *  can be used to represent time spans.
    1433             :  */
    1434             : int
    1435         500 : DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec)
    1436             : {
    1437             :     char       *cp;
    1438             : 
    1439         500 :     *tmask = DTK_TIME_M;
    1440             : 
    1441         500 :     tm->tm_hour = strtoint(str, &cp, 10);
    1442         500 :     if (*cp != ':')
    1443           0 :         return -1;
    1444         500 :     str = cp + 1;
    1445         500 :     tm->tm_min = strtoint(str, &cp, 10);
    1446         500 :     if (*cp == '\0')
    1447             :     {
    1448         136 :         tm->tm_sec = 0;
    1449         136 :         *fsec = 0;
    1450             :     }
    1451         364 :     else if (*cp != ':')
    1452           0 :         return -1;
    1453             :     else
    1454             :     {
    1455         364 :         str = cp + 1;
    1456         364 :         tm->tm_sec = strtoint(str, &cp, 10);
    1457         364 :         if (*cp == '\0')
    1458         228 :             *fsec = 0;
    1459         136 :         else if (*cp == '.')
    1460             :         {
    1461             :             char        fstr[7];
    1462             :             int         i;
    1463             : 
    1464         136 :             cp++;
    1465             : 
    1466             :             /*
    1467             :              * OK, we have at most six digits to care about. Let's construct a
    1468             :              * string with those digits, zero-padded on the right, and then do
    1469             :              * the conversion to an integer.
    1470             :              *
    1471             :              * XXX This truncates the seventh digit, unlike rounding it as the
    1472             :              * backend does.
    1473             :              */
    1474         952 :             for (i = 0; i < 6; i++)
    1475         816 :                 fstr[i] = *cp != '\0' ? *cp++ : '0';
    1476         136 :             fstr[i] = '\0';
    1477         136 :             *fsec = strtoint(fstr, &cp, 10);
    1478         136 :             if (*cp != '\0')
    1479           0 :                 return -1;
    1480             :         }
    1481             :         else
    1482           0 :             return -1;
    1483             :     }
    1484             : 
    1485             :     /* do a sanity check */
    1486        1000 :     if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
    1487        1000 :         tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC)
    1488           0 :         return -1;
    1489             : 
    1490         500 :     return 0;
    1491             : }                               /* DecodeTime() */
    1492             : 
    1493             : /* DecodeTimezone()
    1494             :  * Interpret string as a numeric timezone.
    1495             :  *
    1496             :  * Note: we allow timezone offsets up to 13:59.  There are places that
    1497             :  * use +1300 summer time.
    1498             :  */
    1499             : static int
    1500         236 : DecodeTimezone(char *str, int *tzp)
    1501             : {
    1502             :     int         tz;
    1503             :     int         hr,
    1504             :                 min;
    1505             :     char       *cp;
    1506             :     int         len;
    1507             : 
    1508             :     /* assume leading character is "+" or "-" */
    1509         236 :     hr = strtoint(str + 1, &cp, 10);
    1510             : 
    1511             :     /* explicit delimiter? */
    1512         236 :     if (*cp == ':')
    1513          68 :         min = strtoint(cp + 1, &cp, 10);
    1514             :     /* otherwise, might have run things together... */
    1515         168 :     else if (*cp == '\0' && (len = strlen(str)) > 3)
    1516             :     {
    1517          32 :         min = strtoint(str + len - 2, &cp, 10);
    1518          32 :         if (min < 0 || min >= 60)
    1519           0 :             return -1;
    1520             : 
    1521          32 :         *(str + len - 2) = '\0';
    1522          32 :         hr = strtoint(str + 1, &cp, 10);
    1523          64 :         if (hr < 0 || hr > 13)
    1524           0 :             return -1;
    1525             :     }
    1526             :     else
    1527         136 :         min = 0;
    1528             : 
    1529         236 :     tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
    1530         236 :     if (*str == '-')
    1531          68 :         tz = -tz;
    1532             : 
    1533         236 :     *tzp = -tz;
    1534         236 :     return *cp != '\0';
    1535             : }                               /* DecodeTimezone() */
    1536             : 
    1537             : 
    1538             : /* DecodePosixTimezone()
    1539             :  * Interpret string as a POSIX-compatible timezone:
    1540             :  *  PST-hh:mm
    1541             :  *  PST+h
    1542             :  * - thomas 2000-03-15
    1543             :  */
    1544             : static int
    1545           0 : DecodePosixTimezone(char *str, int *tzp)
    1546             : {
    1547             :     int         val,
    1548             :                 tz;
    1549             :     int         type;
    1550             :     char       *cp;
    1551             :     char        delim;
    1552             : 
    1553           0 :     cp = str;
    1554           0 :     while (*cp != '\0' && isalpha((unsigned char) *cp))
    1555           0 :         cp++;
    1556             : 
    1557           0 :     if (DecodeTimezone(cp, &tz) != 0)
    1558           0 :         return -1;
    1559             : 
    1560           0 :     delim = *cp;
    1561           0 :     *cp = '\0';
    1562           0 :     type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
    1563           0 :     *cp = delim;
    1564             : 
    1565           0 :     switch (type)
    1566             :     {
    1567             :         case DTZ:
    1568             :         case TZ:
    1569           0 :             *tzp = -(val + tz);
    1570           0 :             break;
    1571             : 
    1572             :         default:
    1573           0 :             return -1;
    1574             :     }
    1575             : 
    1576           0 :     return 0;
    1577             : }                               /* DecodePosixTimezone() */
    1578             : 
    1579             : /* ParseDateTime()
    1580             :  * Break string into tokens based on a date/time context.
    1581             :  * Several field types are assigned:
    1582             :  *  DTK_NUMBER - digits and (possibly) a decimal point
    1583             :  *  DTK_DATE - digits and two delimiters, or digits and text
    1584             :  *  DTK_TIME - digits, colon delimiters, and possibly a decimal point
    1585             :  *  DTK_STRING - text (no digits)
    1586             :  *  DTK_SPECIAL - leading "+" or "-" followed by text
    1587             :  *  DTK_TZ - leading "+" or "-" followed by digits
    1588             :  * Note that some field types can hold unexpected items:
    1589             :  *  DTK_NUMBER can hold date fields (yy.ddd)
    1590             :  *  DTK_STRING can hold months (January) and time zones (PST)
    1591             :  *  DTK_DATE can hold Posix time zones (GMT-8)
    1592             :  *
    1593             :  * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
    1594             :  * bytes of space.  On output, field[] entries will point into it.
    1595             :  * The field[] and ftype[] arrays must have at least MAXDATEFIELDS entries.
    1596             :  */
    1597             : int
    1598         832 : ParseDateTime(char *timestr, char *lowstr,
    1599             :               char **field, int *ftype, int *numfields, char **endstr)
    1600             : {
    1601         832 :     int         nf = 0;
    1602         832 :     char       *lp = lowstr;
    1603             : 
    1604         832 :     *endstr = timestr;
    1605             :     /* outer loop through fields */
    1606        5368 :     while (*(*endstr) != '\0')
    1607             :     {
    1608             :         /* Record start of current field */
    1609        3708 :         if (nf >= MAXDATEFIELDS)
    1610           4 :             return -1;
    1611        3704 :         field[nf] = lp;
    1612             : 
    1613             :         /* leading digit? then date or time */
    1614        3704 :         if (isdigit((unsigned char) *(*endstr)))
    1615             :         {
    1616        1444 :             *lp++ = *(*endstr)++;
    1617        5156 :             while (isdigit((unsigned char) *(*endstr)))
    1618        2268 :                 *lp++ = *(*endstr)++;
    1619             : 
    1620             :             /* time field? */
    1621        1444 :             if (*(*endstr) == ':')
    1622             :             {
    1623         500 :                 ftype[nf] = DTK_TIME;
    1624         500 :                 *lp++ = *(*endstr)++;
    1625        5044 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1626        1636 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1627        3044 :                     *lp++ = *(*endstr)++;
    1628             :             }
    1629             :             /* date field? allow embedded text month */
    1630         944 :             else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1631         480 :             {
    1632             :                 /* save delimiting character to use later */
    1633         480 :                 char       *dp = (*endstr);
    1634             : 
    1635         480 :                 *lp++ = *(*endstr)++;
    1636             :                 /* second field is all digits? then no embedded text month */
    1637         480 :                 if (isdigit((unsigned char) *(*endstr)))
    1638             :                 {
    1639         360 :                     ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE;
    1640        1356 :                     while (isdigit((unsigned char) *(*endstr)))
    1641         636 :                         *lp++ = *(*endstr)++;
    1642             : 
    1643             :                     /*
    1644             :                      * insist that the delimiters match to get a three-field
    1645             :                      * date.
    1646             :                      */
    1647         360 :                     if (*(*endstr) == *dp)
    1648             :                     {
    1649         336 :                         ftype[nf] = DTK_DATE;
    1650         336 :                         *lp++ = *(*endstr)++;
    1651        1480 :                         while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1652         808 :                             *lp++ = *(*endstr)++;
    1653             :                     }
    1654             :                 }
    1655             :                 else
    1656             :                 {
    1657         120 :                     ftype[nf] = DTK_DATE;
    1658        1008 :                     while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1659         768 :                         *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1660             :                 }
    1661             :             }
    1662             : 
    1663             :             /*
    1664             :              * otherwise, number only and will determine year, month, day, or
    1665             :              * concatenated fields later...
    1666             :              */
    1667             :             else
    1668         464 :                 ftype[nf] = DTK_NUMBER;
    1669             :         }
    1670             :         /* Leading decimal point? Then fractional seconds... */
    1671        2260 :         else if (*(*endstr) == '.')
    1672             :         {
    1673         196 :             *lp++ = *(*endstr)++;
    1674         392 :             while (isdigit((unsigned char) *(*endstr)))
    1675           0 :                 *lp++ = *(*endstr)++;
    1676             : 
    1677         196 :             ftype[nf] = DTK_NUMBER;
    1678             :         }
    1679             : 
    1680             :         /*
    1681             :          * text? then date string, month, day of week, special, or timezone
    1682             :          */
    1683        2064 :         else if (isalpha((unsigned char) *(*endstr)))
    1684             :         {
    1685         516 :             ftype[nf] = DTK_STRING;
    1686         516 :             *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1687        2992 :             while (isalpha((unsigned char) *(*endstr)))
    1688        1960 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1689             : 
    1690             :             /*
    1691             :              * Full date string with leading text month? Could also be a POSIX
    1692             :              * time zone...
    1693             :              */
    1694         516 :             if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1695             :             {
    1696          48 :                 char       *dp = (*endstr);
    1697             : 
    1698          48 :                 ftype[nf] = DTK_DATE;
    1699          48 :                 *lp++ = *(*endstr)++;
    1700         384 :                 while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp)
    1701         288 :                     *lp++ = *(*endstr)++;
    1702             :             }
    1703             :         }
    1704             :         /* skip leading spaces */
    1705        1548 :         else if (isspace((unsigned char) *(*endstr)))
    1706             :         {
    1707        1256 :             (*endstr)++;
    1708        1256 :             continue;
    1709             :         }
    1710             :         /* sign? then special or numeric timezone */
    1711         292 :         else if (*(*endstr) == '+' || *(*endstr) == '-')
    1712             :         {
    1713         204 :             *lp++ = *(*endstr)++;
    1714             :             /* soak up leading whitespace */
    1715         408 :             while (isspace((unsigned char) *(*endstr)))
    1716           0 :                 (*endstr)++;
    1717             :             /* numeric timezone? */
    1718         408 :             if (isdigit((unsigned char) *(*endstr)))
    1719             :             {
    1720         204 :                 ftype[nf] = DTK_TZ;
    1721         204 :                 *lp++ = *(*endstr)++;
    1722         884 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1723         476 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1724         204 :                     *lp++ = *(*endstr)++;
    1725             :             }
    1726             :             /* special? */
    1727           0 :             else if (isalpha((unsigned char) *(*endstr)))
    1728             :             {
    1729           0 :                 ftype[nf] = DTK_SPECIAL;
    1730           0 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1731           0 :                 while (isalpha((unsigned char) *(*endstr)))
    1732           0 :                     *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1733             :             }
    1734             :             /* otherwise something wrong... */
    1735             :             else
    1736           0 :                 return -1;
    1737             :         }
    1738             :         /* ignore punctuation but use as delimiter */
    1739          88 :         else if (ispunct((unsigned char) *(*endstr)))
    1740             :         {
    1741          88 :             (*endstr)++;
    1742          88 :             continue;
    1743             : 
    1744             :         }
    1745             :         /* otherwise, something is not right... */
    1746             :         else
    1747           0 :             return -1;
    1748             : 
    1749             :         /* force in a delimiter after each field */
    1750        2360 :         *lp++ = '\0';
    1751        2360 :         nf++;
    1752             :     }
    1753             : 
    1754         828 :     *numfields = nf;
    1755             : 
    1756         828 :     return 0;
    1757             : }                               /* ParseDateTime() */
    1758             : 
    1759             : 
    1760             : /* DecodeDateTime()
    1761             :  * Interpret previously parsed fields for general date and time.
    1762             :  * Return 0 if full date, 1 if only time, and -1 if problems.
    1763             :  *      External format(s):
    1764             :  *              "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
    1765             :  *              "Fri Feb-7-1997 15:23:27"
    1766             :  *              "Feb-7-1997 15:23:27"
    1767             :  *              "2-7-1997 15:23:27"
    1768             :  *              "1997-2-7 15:23:27"
    1769             :  *              "1997.038 15:23:27"       (day of year 1-366)
    1770             :  *      Also supports input in compact time:
    1771             :  *              "970207 152327"
    1772             :  *              "97038 152327"
    1773             :  *              "20011225T040506.789-07"
    1774             :  *
    1775             :  * Use the system-provided functions to get the current time zone
    1776             :  *  if not specified in the input string.
    1777             :  * If the date is outside the time_t system-supported time range,
    1778             :  *  then assume UTC time zone. - thomas 1997-05-27
    1779             :  */
    1780             : int
    1781         712 : DecodeDateTime(char **field, int *ftype, int nf,
    1782             :                int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates)
    1783             : {
    1784         712 :     int         fmask = 0,
    1785             :                 tmask,
    1786             :                 type;
    1787         712 :     int         ptype = 0;      /* "prefix type" for ISO y2001m02d04 format */
    1788             :     int         i;
    1789             :     int         val;
    1790         712 :     int         mer = HR24;
    1791         712 :     bool        haveTextMonth = false;
    1792         712 :     bool        is2digits = false;
    1793         712 :     bool        bc = false;
    1794         712 :     int         t = 0;
    1795         712 :     int        *tzp = &t;
    1796             : 
    1797             :     /***
    1798             :      * We'll insist on at least all of the date fields, but initialize the
    1799             :      * remaining fields in case they are not set later...
    1800             :      ***/
    1801         712 :     *dtype = DTK_DATE;
    1802         712 :     tm->tm_hour = 0;
    1803         712 :     tm->tm_min = 0;
    1804         712 :     tm->tm_sec = 0;
    1805         712 :     *fsec = 0;
    1806             :     /* don't know daylight savings time status apriori */
    1807         712 :     tm->tm_isdst = -1;
    1808         712 :     if (tzp != NULL)
    1809         712 :         *tzp = 0;
    1810             : 
    1811        2484 :     for (i = 0; i < nf; i++)
    1812             :     {
    1813        1792 :         switch (ftype[i])
    1814             :         {
    1815             :             case DTK_DATE:
    1816             :                 /***
    1817             :                  * Integral julian day with attached time zone?
    1818             :                  * All other forms with JD will be separated into
    1819             :                  * distinct fields, so we handle just this case here.
    1820             :                  ***/
    1821         504 :                 if (ptype == DTK_JULIAN)
    1822             :                 {
    1823             :                     char       *cp;
    1824             :                     int         val;
    1825             : 
    1826           0 :                     if (tzp == NULL)
    1827           0 :                         return -1;
    1828             : 
    1829           0 :                     val = strtoint(field[i], &cp, 10);
    1830           0 :                     if (*cp != '-')
    1831           0 :                         return -1;
    1832             : 
    1833           0 :                     j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1834             :                     /* Get the time zone from the end of the string */
    1835           0 :                     if (DecodeTimezone(cp, tzp) != 0)
    1836           0 :                         return -1;
    1837             : 
    1838           0 :                     tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
    1839           0 :                     ptype = 0;
    1840           0 :                     break;
    1841             :                 }
    1842             :                 /***
    1843             :                  * Already have a date? Then this might be a POSIX time
    1844             :                  * zone with an embedded dash (e.g. "PST-3" == "EST") or
    1845             :                  * a run-together time with trailing time zone (e.g. hhmmss-zz).
    1846             :                  * - thomas 2001-12-25
    1847             :                  ***/
    1848         504 :                 else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
    1849         504 :                          || (ptype != 0))
    1850             :                 {
    1851             :                     /* No time zone accepted? Then quit... */
    1852           0 :                     if (tzp == NULL)
    1853           0 :                         return -1;
    1854             : 
    1855           0 :                     if (isdigit((unsigned char) *field[i]) || ptype != 0)
    1856           0 :                     {
    1857             :                         char       *cp;
    1858             : 
    1859           0 :                         if (ptype != 0)
    1860             :                         {
    1861             :                             /* Sanity check; should not fail this test */
    1862           0 :                             if (ptype != DTK_TIME)
    1863           0 :                                 return -1;
    1864           0 :                             ptype = 0;
    1865             :                         }
    1866             : 
    1867             :                         /*
    1868             :                          * Starts with a digit but we already have a time
    1869             :                          * field? Then we are in trouble with a date and time
    1870             :                          * already...
    1871             :                          */
    1872           0 :                         if ((fmask & DTK_TIME_M) == DTK_TIME_M)
    1873           0 :                             return -1;
    1874             : 
    1875           0 :                         if ((cp = strchr(field[i], '-')) == NULL)
    1876           0 :                             return -1;
    1877             : 
    1878             :                         /* Get the time zone from the end of the string */
    1879           0 :                         if (DecodeTimezone(cp, tzp) != 0)
    1880           0 :                             return -1;
    1881           0 :                         *cp = '\0';
    1882             : 
    1883             :                         /*
    1884             :                          * Then read the rest of the field as a concatenated
    1885             :                          * time
    1886             :                          */
    1887           0 :                         if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask,
    1888             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    1889           0 :                             return -1;
    1890             : 
    1891             :                         /*
    1892             :                          * modify tmask after returning from
    1893             :                          * DecodeNumberField()
    1894             :                          */
    1895           0 :                         tmask |= DTK_M(TZ);
    1896             :                     }
    1897             :                     else
    1898             :                     {
    1899           0 :                         if (DecodePosixTimezone(field[i], tzp) != 0)
    1900           0 :                             return -1;
    1901             : 
    1902           0 :                         ftype[i] = DTK_TZ;
    1903           0 :                         tmask = DTK_M(TZ);
    1904             :                     }
    1905             :                 }
    1906         504 :                 else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    1907           0 :                     return -1;
    1908         504 :                 break;
    1909             : 
    1910             :             case DTK_TIME:
    1911         496 :                 if (DecodeTime(field[i], &tmask, tm, fsec) != 0)
    1912           0 :                     return -1;
    1913             : 
    1914             :                 /*
    1915             :                  * Check upper limit on hours; other limits checked in
    1916             :                  * DecodeTime()
    1917             :                  */
    1918             :                 /* test for > 24:00:00 */
    1919         988 :                 if (tm->tm_hour > 24 ||
    1920         492 :                     (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
    1921           4 :                     return -1;
    1922         492 :                 break;
    1923             : 
    1924             :             case DTK_TZ:
    1925             :                 {
    1926             :                     int         tz;
    1927             : 
    1928         204 :                     if (tzp == NULL)
    1929           0 :                         return -1;
    1930             : 
    1931         204 :                     if (DecodeTimezone(field[i], &tz) != 0)
    1932           0 :                         return -1;
    1933             : 
    1934             :                     /*
    1935             :                      * Already have a time zone? Then maybe this is the second
    1936             :                      * field of a POSIX time: EST+3 (equivalent to PST)
    1937             :                      */
    1938         204 :                     if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
    1939           0 :                         ftype[i - 1] == DTK_TZ &&
    1940           0 :                         isalpha((unsigned char) *field[i - 1]))
    1941             :                     {
    1942           0 :                         *tzp -= tz;
    1943           0 :                         tmask = 0;
    1944             :                     }
    1945             :                     else
    1946             :                     {
    1947         204 :                         *tzp = tz;
    1948         204 :                         tmask = DTK_M(TZ);
    1949             :                     }
    1950             :                 }
    1951         204 :                 break;
    1952             : 
    1953             :             case DTK_NUMBER:
    1954             : 
    1955             :                 /*
    1956             :                  * Was this an "ISO date" with embedded field labels? An
    1957             :                  * example is "y2001m02d04" - thomas 2001-02-04
    1958             :                  */
    1959         308 :                 if (ptype != 0)
    1960             :                 {
    1961             :                     char       *cp;
    1962             :                     int         val;
    1963             : 
    1964          24 :                     val = strtoint(field[i], &cp, 10);
    1965             : 
    1966             :                     /*
    1967             :                      * only a few kinds are allowed to have an embedded
    1968             :                      * decimal
    1969             :                      */
    1970          24 :                     if (*cp == '.')
    1971           0 :                         switch (ptype)
    1972             :                         {
    1973             :                             case DTK_JULIAN:
    1974             :                             case DTK_TIME:
    1975             :                             case DTK_SECOND:
    1976           0 :                                 break;
    1977             :                             default:
    1978           0 :                                 return 1;
    1979             :                                 break;
    1980             :                         }
    1981          24 :                     else if (*cp != '\0')
    1982           0 :                         return -1;
    1983             : 
    1984          24 :                     switch (ptype)
    1985             :                     {
    1986             :                         case DTK_YEAR:
    1987           0 :                             tm->tm_year = val;
    1988           0 :                             tmask = DTK_M(YEAR);
    1989           0 :                             break;
    1990             : 
    1991             :                         case DTK_MONTH:
    1992             : 
    1993             :                             /*
    1994             :                              * already have a month and hour? then assume
    1995             :                              * minutes
    1996             :                              */
    1997           0 :                             if ((fmask & DTK_M(MONTH)) != 0 &&
    1998           0 :                                 (fmask & DTK_M(HOUR)) != 0)
    1999             :                             {
    2000           0 :                                 tm->tm_min = val;
    2001           0 :                                 tmask = DTK_M(MINUTE);
    2002             :                             }
    2003             :                             else
    2004             :                             {
    2005           0 :                                 tm->tm_mon = val;
    2006           0 :                                 tmask = DTK_M(MONTH);
    2007             :                             }
    2008           0 :                             break;
    2009             : 
    2010             :                         case DTK_DAY:
    2011           0 :                             tm->tm_mday = val;
    2012           0 :                             tmask = DTK_M(DAY);
    2013           0 :                             break;
    2014             : 
    2015             :                         case DTK_HOUR:
    2016           0 :                             tm->tm_hour = val;
    2017           0 :                             tmask = DTK_M(HOUR);
    2018           0 :                             break;
    2019             : 
    2020             :                         case DTK_MINUTE:
    2021           0 :                             tm->tm_min = val;
    2022           0 :                             tmask = DTK_M(MINUTE);
    2023           0 :                             break;
    2024             : 
    2025             :                         case DTK_SECOND:
    2026           0 :                             tm->tm_sec = val;
    2027           0 :                             tmask = DTK_M(SECOND);
    2028           0 :                             if (*cp == '.')
    2029             :                             {
    2030             :                                 double      frac;
    2031             : 
    2032           0 :                                 frac = strtod(cp, &cp);
    2033           0 :                                 if (*cp != '\0')
    2034           0 :                                     return -1;
    2035           0 :                                 *fsec = frac * 1000000;
    2036             :                             }
    2037           0 :                             break;
    2038             : 
    2039             :                         case DTK_TZ:
    2040           0 :                             tmask = DTK_M(TZ);
    2041           0 :                             if (DecodeTimezone(field[i], tzp) != 0)
    2042           0 :                                 return -1;
    2043           0 :                             break;
    2044             : 
    2045             :                         case DTK_JULIAN:
    2046             :                             /***
    2047             :                              * previous field was a label for "julian date"?
    2048             :                              ***/
    2049          24 :                             tmask = DTK_DATE_M;
    2050          24 :                             j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2051             :                             /* fractional Julian Day? */
    2052          24 :                             if (*cp == '.')
    2053             :                             {
    2054             :                                 double      time;
    2055             : 
    2056           0 :                                 time = strtod(cp, &cp);
    2057           0 :                                 if (*cp != '\0')
    2058           0 :                                     return -1;
    2059             : 
    2060           0 :                                 tmask |= DTK_TIME_M;
    2061           0 :                                 dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
    2062             :                             }
    2063          24 :                             break;
    2064             : 
    2065             :                         case DTK_TIME:
    2066             :                             /* previous field was "t" for ISO time */
    2067           0 :                             if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M),
    2068             :                                                               &tmask, tm, fsec, &is2digits)) < 0)
    2069           0 :                                 return -1;
    2070             : 
    2071           0 :                             if (tmask != DTK_TIME_M)
    2072           0 :                                 return -1;
    2073           0 :                             break;
    2074             : 
    2075             :                         default:
    2076           0 :                             return -1;
    2077             :                             break;
    2078             :                     }
    2079             : 
    2080          24 :                     ptype = 0;
    2081          24 :                     *dtype = DTK_DATE;
    2082             :                 }
    2083             :                 else
    2084             :                 {
    2085             :                     char       *cp;
    2086             :                     int         flen;
    2087             : 
    2088         284 :                     flen = strlen(field[i]);
    2089         284 :                     cp = strchr(field[i], '.');
    2090             : 
    2091             :                     /* Embedded decimal and no date yet? */
    2092         284 :                     if (cp != NULL && !(fmask & DTK_DATE_M))
    2093             :                     {
    2094          52 :                         if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    2095           4 :                             return -1;
    2096             :                     }
    2097             :                     /* embedded decimal and several digits before? */
    2098         256 :                     else if (cp != NULL && flen - strlen(cp) > 2)
    2099             :                     {
    2100             :                         /*
    2101             :                          * Interpret as a concatenated date or time Set the
    2102             :                          * type field to allow decoding other fields later.
    2103             :                          * Example: 20011223 or 040506
    2104             :                          */
    2105           0 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2106             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2107           0 :                             return -1;
    2108             :                     }
    2109         256 :                     else if (flen > 4)
    2110             :                     {
    2111          56 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2112             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2113           0 :                             return -1;
    2114             :                     }
    2115             :                     /* otherwise it is a single date/time field... */
    2116         200 :                     else if (DecodeNumber(flen, field[i], fmask,
    2117             :                                           &tmask, tm, fsec, &is2digits, EuroDates) != 0)
    2118           0 :                         return -1;
    2119             :                 }
    2120         304 :                 break;
    2121             : 
    2122             :             case DTK_STRING:
    2123             :             case DTK_SPECIAL:
    2124         280 :                 type = DecodeSpecial(i, field[i], &val);
    2125         280 :                 if (type == IGNORE_DTF)
    2126           0 :                     continue;
    2127             : 
    2128         280 :                 tmask = DTK_M(type);
    2129         280 :                 switch (type)
    2130             :                 {
    2131             :                     case RESERV:
    2132           0 :                         switch (val)
    2133             :                         {
    2134             :                             case DTK_NOW:
    2135           0 :                                 tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
    2136           0 :                                 *dtype = DTK_DATE;
    2137           0 :                                 GetCurrentDateTime(tm);
    2138           0 :                                 break;
    2139             : 
    2140             :                             case DTK_YESTERDAY:
    2141           0 :                                 tmask = DTK_DATE_M;
    2142           0 :                                 *dtype = DTK_DATE;
    2143           0 :                                 GetCurrentDateTime(tm);
    2144           0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,
    2145             :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2146           0 :                                 tm->tm_hour = 0;
    2147           0 :                                 tm->tm_min = 0;
    2148           0 :                                 tm->tm_sec = 0;
    2149           0 :                                 break;
    2150             : 
    2151             :                             case DTK_TODAY:
    2152           0 :                                 tmask = DTK_DATE_M;
    2153           0 :                                 *dtype = DTK_DATE;
    2154           0 :                                 GetCurrentDateTime(tm);
    2155           0 :                                 tm->tm_hour = 0;
    2156           0 :                                 tm->tm_min = 0;
    2157           0 :                                 tm->tm_sec = 0;
    2158           0 :                                 break;
    2159             : 
    2160             :                             case DTK_TOMORROW:
    2161           0 :                                 tmask = DTK_DATE_M;
    2162           0 :                                 *dtype = DTK_DATE;
    2163           0 :                                 GetCurrentDateTime(tm);
    2164           0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,
    2165             :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2166           0 :                                 tm->tm_hour = 0;
    2167           0 :                                 tm->tm_min = 0;
    2168           0 :                                 tm->tm_sec = 0;
    2169           0 :                                 break;
    2170             : 
    2171             :                             case DTK_ZULU:
    2172           0 :                                 tmask = (DTK_TIME_M | DTK_M(TZ));
    2173           0 :                                 *dtype = DTK_DATE;
    2174           0 :                                 tm->tm_hour = 0;
    2175           0 :                                 tm->tm_min = 0;
    2176           0 :                                 tm->tm_sec = 0;
    2177           0 :                                 if (tzp != NULL)
    2178           0 :                                     *tzp = 0;
    2179           0 :                                 break;
    2180             : 
    2181             :                             default:
    2182           0 :                                 *dtype = val;
    2183             :                         }
    2184             : 
    2185           0 :                         break;
    2186             : 
    2187             :                     case MONTH:
    2188             : 
    2189             :                         /*
    2190             :                          * already have a (numeric) month? then see if we can
    2191             :                          * substitute...
    2192             :                          */
    2193         108 :                         if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
    2194          16 :                             !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31)
    2195             :                         {
    2196           8 :                             tm->tm_mday = tm->tm_mon;
    2197           8 :                             tmask = DTK_M(DAY);
    2198             :                         }
    2199         100 :                         haveTextMonth = true;
    2200         100 :                         tm->tm_mon = val;
    2201         100 :                         break;
    2202             : 
    2203             :                     case DTZMOD:
    2204             : 
    2205             :                         /*
    2206             :                          * daylight savings time modifier (solves "MET DST"
    2207             :                          * syntax)
    2208             :                          */
    2209           0 :                         tmask |= DTK_M(DTZ);
    2210           0 :                         tm->tm_isdst = 1;
    2211           0 :                         if (tzp == NULL)
    2212           0 :                             return -1;
    2213           0 :                         *tzp -= val;
    2214           0 :                         break;
    2215             : 
    2216             :                     case DTZ:
    2217             : 
    2218             :                         /*
    2219             :                          * set mask for TZ here _or_ check for DTZ later when
    2220             :                          * getting default timezone
    2221             :                          */
    2222          68 :                         tmask |= DTK_M(TZ);
    2223          68 :                         tm->tm_isdst = 1;
    2224          68 :                         if (tzp == NULL)
    2225           0 :                             return -1;
    2226          68 :                         *tzp = -val;
    2227          68 :                         ftype[i] = DTK_TZ;
    2228          68 :                         break;
    2229             : 
    2230             :                     case TZ:
    2231           0 :                         tm->tm_isdst = 0;
    2232           0 :                         if (tzp == NULL)
    2233           0 :                             return -1;
    2234           0 :                         *tzp = -val;
    2235           0 :                         ftype[i] = DTK_TZ;
    2236           0 :                         break;
    2237             : 
    2238             :                     case IGNORE_DTF:
    2239           0 :                         break;
    2240             : 
    2241             :                     case AMPM:
    2242           0 :                         mer = val;
    2243           0 :                         break;
    2244             : 
    2245             :                     case ADBC:
    2246          24 :                         bc = (val == BC);
    2247          24 :                         break;
    2248             : 
    2249             :                     case DOW:
    2250          52 :                         tm->tm_wday = val;
    2251          52 :                         break;
    2252             : 
    2253             :                     case UNITS:
    2254          24 :                         tmask = 0;
    2255          24 :                         ptype = val;
    2256          24 :                         break;
    2257             : 
    2258             :                     case ISOTIME:
    2259             : 
    2260             :                         /*
    2261             :                          * This is a filler field "t" indicating that the next
    2262             :                          * field is time. Try to verify that this is sensible.
    2263             :                          */
    2264           0 :                         tmask = 0;
    2265             : 
    2266             :                         /* No preceding date? Then quit... */
    2267           0 :                         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2268           0 :                             return -1;
    2269             : 
    2270             :                         /***
    2271             :                          * We will need one of the following fields:
    2272             :                          *  DTK_NUMBER should be hhmmss.fff
    2273             :                          *  DTK_TIME should be hh:mm:ss.fff
    2274             :                          *  DTK_DATE should be hhmmss-zz
    2275             :                          ***/
    2276           0 :                         if (i >= nf - 1 ||
    2277           0 :                             (ftype[i + 1] != DTK_NUMBER &&
    2278           0 :                              ftype[i + 1] != DTK_TIME &&
    2279           0 :                              ftype[i + 1] != DTK_DATE))
    2280           0 :                             return -1;
    2281             : 
    2282           0 :                         ptype = val;
    2283           0 :                         break;
    2284             : 
    2285             :                     default:
    2286          12 :                         return -1;
    2287             :                 }
    2288         268 :                 break;
    2289             : 
    2290             :             default:
    2291           0 :                 return -1;
    2292             :         }
    2293             : 
    2294        1772 :         if (tmask & fmask)
    2295           0 :             return -1;
    2296        1772 :         fmask |= tmask;
    2297             :     }
    2298             : 
    2299             :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    2300         692 :     if (bc)
    2301             :     {
    2302          24 :         if (tm->tm_year > 0)
    2303          24 :             tm->tm_year = -(tm->tm_year - 1);
    2304             :         else
    2305           0 :             return -1;
    2306             :     }
    2307         668 :     else if (is2digits)
    2308             :     {
    2309          24 :         if (tm->tm_year < 70)
    2310           0 :             tm->tm_year += 2000;
    2311          24 :         else if (tm->tm_year < 100)
    2312          24 :             tm->tm_year += 1900;
    2313             :     }
    2314             : 
    2315         692 :     if (mer != HR24 && tm->tm_hour > 12)
    2316           0 :         return -1;
    2317         692 :     if (mer == AM && tm->tm_hour == 12)
    2318           0 :         tm->tm_hour = 0;
    2319         692 :     else if (mer == PM && tm->tm_hour != 12)
    2320           0 :         tm->tm_hour += 12;
    2321             : 
    2322             :     /* do additional checking for full date specs... */
    2323         692 :     if (*dtype == DTK_DATE)
    2324             :     {
    2325         692 :         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2326           0 :             return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
    2327             : 
    2328             :         /*
    2329             :          * check for valid day of month, now that we know for sure the month
    2330             :          * and year...
    2331             :          */
    2332         692 :         if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    2333           0 :             return -1;
    2334             : 
    2335             :         /*
    2336             :          * backend tried to find local timezone here but we don't use the
    2337             :          * result afterwards anyway so we only check for this error: daylight
    2338             :          * savings time modifier but no standard timezone?
    2339             :          */
    2340         692 :         if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD)))
    2341           0 :             return -1;
    2342             :     }
    2343             : 
    2344         692 :     return 0;
    2345             : }                               /* DecodeDateTime() */
    2346             : 
    2347             : /* Function works as follows:
    2348             :  *
    2349             :  *
    2350             :  * */
    2351             : 
    2352             : static char *
    2353         428 : find_end_token(char *str, char *fmt)
    2354             : {
    2355             :     /*
    2356             :      * str: here is28the day12the hour fmt: here is%dthe day%hthe hour
    2357             :      *
    2358             :      * we extract the 28, we read the percent sign and the type "d" then this
    2359             :      * functions gets called as find_end_token("28the day12the hour", "the
    2360             :      * day%hthehour")
    2361             :      *
    2362             :      * fmt points to "the day%hthehour", next_percent points to %hthehour and
    2363             :      * we have to find a match for everything between these positions ("the
    2364             :      * day"). We look for "the day" in str and know that the pattern we are
    2365             :      * about to scan ends where this string starts (right after the "28")
    2366             :      *
    2367             :      * At the end, *fmt is '\0' and *str isn't. end_position then is
    2368             :      * unchanged.
    2369             :      */
    2370         428 :     char       *end_position = NULL;
    2371             :     char       *next_percent,
    2372         428 :                *subst_location = NULL;
    2373         428 :     int         scan_offset = 0;
    2374             :     char        last_char;
    2375             : 
    2376             :     /* are we at the end? */
    2377         428 :     if (!*fmt)
    2378             :     {
    2379          64 :         end_position = fmt;
    2380          64 :         return end_position;
    2381             :     }
    2382             : 
    2383             :     /* not at the end */
    2384         736 :     while (fmt[scan_offset] == '%' && fmt[scan_offset + 1])
    2385             :     {
    2386             :         /*
    2387             :          * there is no delimiter, skip to the next delimiter if we're reading
    2388             :          * a number and then something that is not a number "9:15pm", we might
    2389             :          * be able to recover with the strtol end pointer. Go for the next
    2390             :          * percent sign
    2391             :          */
    2392           8 :         scan_offset += 2;
    2393             :     }
    2394         364 :     next_percent = strchr(fmt + scan_offset, '%');
    2395         364 :     if (next_percent)
    2396             :     {
    2397             :         /*
    2398             :          * we don't want to allocate extra memory, so we temporarily set the
    2399             :          * '%' sign to '\0' and call strstr However since we allow whitespace
    2400             :          * to float around everything, we have to shorten the pattern until we
    2401             :          * reach a non-whitespace character
    2402             :          */
    2403             : 
    2404         352 :         subst_location = next_percent;
    2405         756 :         while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset)
    2406          52 :             subst_location--;
    2407         352 :         last_char = *subst_location;
    2408         352 :         *subst_location = '\0';
    2409             : 
    2410             :         /*
    2411             :          * the haystack is the str and the needle is the original fmt but it
    2412             :          * ends at the position where the next percent sign would be
    2413             :          */
    2414             : 
    2415             :         /*
    2416             :          * There is one special case. Imagine: str = " 2", fmt = "%d %...",
    2417             :          * since we want to allow blanks as "dynamic" padding we have to
    2418             :          * accept this. Now, we are called with a fmt of " %..." and look for
    2419             :          * " " in str. We find it at the first position and never read the
    2420             :          * 2...
    2421             :          */
    2422         704 :         while (*str == ' ')
    2423           0 :             str++;
    2424         352 :         end_position = strstr(str, fmt + scan_offset);
    2425         352 :         *subst_location = last_char;
    2426             :     }
    2427             :     else
    2428             :     {
    2429             :         /*
    2430             :          * there is no other percent sign. So everything up to the end has to
    2431             :          * match.
    2432             :          */
    2433          12 :         end_position = str + strlen(str);
    2434             :     }
    2435         364 :     if (!end_position)
    2436             :     {
    2437             :         /*
    2438             :          * maybe we have the following case:
    2439             :          *
    2440             :          * str = "4:15am" fmt = "%M:%S %p"
    2441             :          *
    2442             :          * at this place we could have
    2443             :          *
    2444             :          * str = "15am" fmt = " %p"
    2445             :          *
    2446             :          * and have set fmt to " " because overwrote the % sign with a NULL
    2447             :          *
    2448             :          * In this case where we would have to match a space but can't find
    2449             :          * it, set end_position to the end of the string
    2450             :          */
    2451           4 :         if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location)
    2452           4 :             end_position = str + strlen(str);
    2453             :     }
    2454         364 :     return end_position;
    2455             : }
    2456             : 
    2457             : static int
    2458         428 : pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt)
    2459             : {
    2460             :     /*
    2461             :      * scan everything between pstr and pstr_end. This is not including the
    2462             :      * last character so we might set it to '\0' for the parsing
    2463             :      */
    2464             : 
    2465             :     char        last_char;
    2466         428 :     int         err = 0;
    2467             :     char       *pstr_end;
    2468         428 :     char       *strtol_end = NULL;
    2469             : 
    2470         856 :     while (**pstr == ' ')
    2471           0 :         pstr++;
    2472         428 :     pstr_end = find_end_token(*pstr, pfmt);
    2473         428 :     if (!pstr_end)
    2474             :     {
    2475             :         /* there was an error, no match */
    2476           0 :         return 1;
    2477             :     }
    2478         428 :     last_char = *pstr_end;
    2479         428 :     *pstr_end = '\0';
    2480             : 
    2481         428 :     switch (scan_type)
    2482             :     {
    2483             :         case PGTYPES_TYPE_UINT:
    2484             : 
    2485             :             /*
    2486             :              * numbers may be blank-padded, this is the only deviation from
    2487             :              * the fmt-string we accept
    2488             :              */
    2489         752 :             while (**pstr == ' ')
    2490           0 :                 (*pstr)++;
    2491         376 :             errno = 0;
    2492         376 :             scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
    2493         376 :             if (errno)
    2494           0 :                 err = 1;
    2495         376 :             break;
    2496             :         case PGTYPES_TYPE_UINT_LONG:
    2497           8 :             while (**pstr == ' ')
    2498           0 :                 (*pstr)++;
    2499           4 :             errno = 0;
    2500           4 :             scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
    2501           4 :             if (errno)
    2502           0 :                 err = 1;
    2503           4 :             break;
    2504             :         case PGTYPES_TYPE_STRING_MALLOCED:
    2505          48 :             scan_val->str_val = pgtypes_strdup(*pstr);
    2506          48 :             if (scan_val->str_val == NULL)
    2507           0 :                 err = 1;
    2508          48 :             break;
    2509             :     }
    2510         428 :     if (strtol_end && *strtol_end)
    2511          28 :         *pstr = strtol_end;
    2512             :     else
    2513         400 :         *pstr = pstr_end;
    2514         428 :     *pstr_end = last_char;
    2515         428 :     return err;
    2516             : }
    2517             : 
    2518             : /* XXX range checking */
    2519             : int
    2520          88 : PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
    2521             :                             int *year, int *month, int *day,
    2522             :                             int *hour, int *minute, int *second,
    2523             :                             int *tz)
    2524             : {
    2525             :     union un_fmt_comb scan_val;
    2526             :     int         scan_type;
    2527             : 
    2528             :     char       *pstr,
    2529             :                *pfmt,
    2530             :                *tmp;
    2531          88 :     int         err = 1;
    2532             :     unsigned int j;
    2533             :     struct tm   tm;
    2534             : 
    2535          88 :     pfmt = fmt;
    2536          88 :     pstr = *str;
    2537             : 
    2538        1124 :     while (*pfmt)
    2539             :     {
    2540         952 :         err = 0;
    2541        2284 :         while (*pfmt == ' ')
    2542         380 :             pfmt++;
    2543        2376 :         while (*pstr == ' ')
    2544         472 :             pstr++;
    2545         952 :         if (*pfmt != '%')
    2546             :         {
    2547         380 :             if (*pfmt == *pstr)
    2548             :             {
    2549         376 :                 pfmt++;
    2550         376 :                 pstr++;
    2551             :             }
    2552             :             else
    2553             :             {
    2554             :                 /* Error: no match */
    2555           4 :                 err = 1;
    2556           4 :                 return err;
    2557             :             }
    2558         376 :             continue;
    2559             :         }
    2560             :         /* here *pfmt equals '%' */
    2561         572 :         pfmt++;
    2562         572 :         switch (*pfmt)
    2563             :         {
    2564             :             case 'a':
    2565          28 :                 pfmt++;
    2566             : 
    2567             :                 /*
    2568             :                  * we parse the day and see if it is a week day but we do not
    2569             :                  * check if the week day really matches the date
    2570             :                  */
    2571          28 :                 err = 1;
    2572          28 :                 j = 0;
    2573         112 :                 while (pgtypes_date_weekdays_short[j])
    2574             :                 {
    2575          84 :                     if (strncmp(pgtypes_date_weekdays_short[j], pstr,
    2576          84 :                                 strlen(pgtypes_date_weekdays_short[j])) == 0)
    2577             :                     {
    2578             :                         /* found it */
    2579          28 :                         err = 0;
    2580          28 :                         pstr += strlen(pgtypes_date_weekdays_short[j]);
    2581          28 :                         break;
    2582             :                     }
    2583          56 :                     j++;
    2584             :                 }
    2585          28 :                 break;
    2586             :             case 'A':
    2587             :                 /* see note above */
    2588           0 :                 pfmt++;
    2589           0 :                 err = 1;
    2590           0 :                 j = 0;
    2591           0 :                 while (days[j])
    2592             :                 {
    2593           0 :                     if (strncmp(days[j], pstr, strlen(days[j])) == 0)
    2594             :                     {
    2595             :                         /* found it */
    2596           0 :                         err = 0;
    2597           0 :                         pstr += strlen(days[j]);
    2598           0 :                         break;
    2599             :                     }
    2600           0 :                     j++;
    2601             :                 }
    2602           0 :                 break;
    2603             :             case 'b':
    2604             :             case 'h':
    2605          40 :                 pfmt++;
    2606          40 :                 err = 1;
    2607          40 :                 j = 0;
    2608         240 :                 while (months[j])
    2609             :                 {
    2610         200 :                     if (strncmp(months[j], pstr, strlen(months[j])) == 0)
    2611             :                     {
    2612             :                         /* found it */
    2613          40 :                         err = 0;
    2614          40 :                         pstr += strlen(months[j]);
    2615          40 :                         *month = j + 1;
    2616          40 :                         break;
    2617             :                     }
    2618         160 :                     j++;
    2619             :                 }
    2620          40 :                 break;
    2621             :             case 'B':
    2622             :                 /* see note above */
    2623          28 :                 pfmt++;
    2624          28 :                 err = 1;
    2625          28 :                 j = 0;
    2626         256 :                 while (pgtypes_date_months[j])
    2627             :                 {
    2628         228 :                     if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0)
    2629             :                     {
    2630             :                         /* found it */
    2631          28 :                         err = 0;
    2632          28 :                         pstr += strlen(pgtypes_date_months[j]);
    2633          28 :                         *month = j + 1;
    2634          28 :                         break;
    2635             :                     }
    2636         200 :                     j++;
    2637             :                 }
    2638          28 :                 break;
    2639             :             case 'c':
    2640             :                 /* XXX */
    2641           0 :                 break;
    2642             :             case 'C':
    2643           8 :                 pfmt++;
    2644           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2645           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2646           8 :                 *year = scan_val.uint_val * 100;
    2647           8 :                 break;
    2648             :             case 'd':
    2649             :             case 'e':
    2650          76 :                 pfmt++;
    2651          76 :                 scan_type = PGTYPES_TYPE_UINT;
    2652          76 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2653          76 :                 *day = scan_val.uint_val;
    2654          76 :                 break;
    2655             :             case 'D':
    2656             : 
    2657             :                 /*
    2658             :                  * we have to concatenate the strings in order to be able to
    2659             :                  * find the end of the substitution
    2660             :                  */
    2661           0 :                 pfmt++;
    2662           0 :                 tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1);
    2663           0 :                 strcpy(tmp, "%m/%d/%y");
    2664           0 :                 strcat(tmp, pfmt);
    2665           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2666           0 :                 free(tmp);
    2667           0 :                 return err;
    2668             :             case 'm':
    2669           8 :                 pfmt++;
    2670           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2671           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2672           8 :                 *month = scan_val.uint_val;
    2673           8 :                 break;
    2674             :             case 'y':
    2675             :             case 'g':           /* XXX difference to y (ISO) */
    2676           8 :                 pfmt++;
    2677           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2678           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2679           8 :                 if (*year < 0)
    2680             :                 {
    2681             :                     /* not yet set */
    2682           4 :                     *year = scan_val.uint_val;
    2683             :                 }
    2684             :                 else
    2685           4 :                     *year += scan_val.uint_val;
    2686           8 :                 if (*year < 100)
    2687           4 :                     *year += 1900;
    2688           8 :                 break;
    2689             :             case 'G':
    2690             :                 /* XXX difference to %V (ISO) */
    2691           0 :                 pfmt++;
    2692           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2693           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2694           0 :                 *year = scan_val.uint_val;
    2695           0 :                 break;
    2696             :             case 'H':
    2697             :             case 'I':
    2698             :             case 'k':
    2699             :             case 'l':
    2700          76 :                 pfmt++;
    2701          76 :                 scan_type = PGTYPES_TYPE_UINT;
    2702          76 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2703          76 :                 *hour += scan_val.uint_val;
    2704          76 :                 break;
    2705             :             case 'j':
    2706           0 :                 pfmt++;
    2707           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2708           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2709             : 
    2710             :                 /*
    2711             :                  * XXX what should we do with that? We could say that it's
    2712             :                  * sufficient if we have the year and the day within the year
    2713             :                  * to get at least a specific day.
    2714             :                  */
    2715           0 :                 break;
    2716             :             case 'M':
    2717          76 :                 pfmt++;
    2718          76 :                 scan_type = PGTYPES_TYPE_UINT;
    2719          76 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2720          76 :                 *minute = scan_val.uint_val;
    2721          76 :                 break;
    2722             :             case 'n':
    2723           8 :                 pfmt++;
    2724           8 :                 if (*pstr == '\n')
    2725           8 :                     pstr++;
    2726             :                 else
    2727           0 :                     err = 1;
    2728           8 :                 break;
    2729             :             case 'p':
    2730          16 :                 err = 1;
    2731          16 :                 pfmt++;
    2732          16 :                 if (strncmp(pstr, "am", 2) == 0)
    2733             :                 {
    2734          12 :                     *hour += 0;
    2735          12 :                     err = 0;
    2736          12 :                     pstr += 2;
    2737             :                 }
    2738          16 :                 if (strncmp(pstr, "a.m.", 4) == 0)
    2739             :                 {
    2740           0 :                     *hour += 0;
    2741           0 :                     err = 0;
    2742           0 :                     pstr += 4;
    2743             :                 }
    2744          16 :                 if (strncmp(pstr, "pm", 2) == 0)
    2745             :                 {
    2746           4 :                     *hour += 12;
    2747           4 :                     err = 0;
    2748           4 :                     pstr += 2;
    2749             :                 }
    2750          16 :                 if (strncmp(pstr, "p.m.", 4) == 0)
    2751             :                 {
    2752           0 :                     *hour += 12;
    2753           0 :                     err = 0;
    2754           0 :                     pstr += 4;
    2755             :                 }
    2756          16 :                 break;
    2757             :             case 'P':
    2758           4 :                 err = 1;
    2759           4 :                 pfmt++;
    2760           4 :                 if (strncmp(pstr, "AM", 2) == 0)
    2761             :                 {
    2762           0 :                     *hour += 0;
    2763           0 :                     err = 0;
    2764           0 :                     pstr += 2;
    2765             :                 }
    2766           4 :                 if (strncmp(pstr, "A.M.", 4) == 0)
    2767             :                 {
    2768           0 :                     *hour += 0;
    2769           0 :                     err = 0;
    2770           0 :                     pstr += 4;
    2771             :                 }
    2772           4 :                 if (strncmp(pstr, "PM", 2) == 0)
    2773             :                 {
    2774           0 :                     *hour += 12;
    2775           0 :                     err = 0;
    2776           0 :                     pstr += 2;
    2777             :                 }
    2778           4 :                 if (strncmp(pstr, "P.M.", 4) == 0)
    2779             :                 {
    2780           4 :                     *hour += 12;
    2781           4 :                     err = 0;
    2782           4 :                     pstr += 4;
    2783             :                 }
    2784           4 :                 break;
    2785             :             case 'r':
    2786           0 :                 pfmt++;
    2787           0 :                 tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1);
    2788           0 :                 strcpy(tmp, "%I:%M:%S %p");
    2789           0 :                 strcat(tmp, pfmt);
    2790           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2791           0 :                 free(tmp);
    2792           0 :                 return err;
    2793             :             case 'R':
    2794           0 :                 pfmt++;
    2795           0 :                 tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1);
    2796           0 :                 strcpy(tmp, "%H:%M");
    2797           0 :                 strcat(tmp, pfmt);
    2798           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2799           0 :                 free(tmp);
    2800           0 :                 return err;
    2801             :             case 's':
    2802           4 :                 pfmt++;
    2803           4 :                 scan_type = PGTYPES_TYPE_UINT_LONG;
    2804           4 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2805             :                 /* number of seconds in scan_val.luint_val */
    2806             :                 {
    2807             :                     struct tm  *tms;
    2808           4 :                     time_t      et = (time_t) scan_val.luint_val;
    2809             : 
    2810           4 :                     tms = gmtime(&et);
    2811             : 
    2812           4 :                     if (tms)
    2813             :                     {
    2814           4 :                         *year = tms->tm_year + 1900;
    2815           4 :                         *month = tms->tm_mon + 1;
    2816           4 :                         *day = tms->tm_mday;
    2817           4 :                         *hour = tms->tm_hour;
    2818           4 :                         *minute = tms->tm_min;
    2819           4 :                         *second = tms->tm_sec;
    2820             :                     }
    2821             :                     else
    2822           0 :                         err = 1;
    2823             :                 }
    2824           4 :                 break;
    2825             :             case 'S':
    2826          56 :                 pfmt++;
    2827          56 :                 scan_type = PGTYPES_TYPE_UINT;
    2828          56 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2829          56 :                 *second = scan_val.uint_val;
    2830          56 :                 break;
    2831             :             case 't':
    2832           0 :                 pfmt++;
    2833           0 :                 if (*pstr == '\t')
    2834           0 :                     pstr++;
    2835             :                 else
    2836           0 :                     err = 1;
    2837           0 :                 break;
    2838             :             case 'T':
    2839           0 :                 pfmt++;
    2840           0 :                 tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1);
    2841           0 :                 strcpy(tmp, "%H:%M:%S");
    2842           0 :                 strcat(tmp, pfmt);
    2843           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2844           0 :                 free(tmp);
    2845           0 :                 return err;
    2846             :             case 'u':
    2847           0 :                 pfmt++;
    2848           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2849           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2850           0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 7)
    2851           0 :                     err = 1;
    2852           0 :                 break;
    2853             :             case 'U':
    2854           0 :                 pfmt++;
    2855           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2856           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2857           0 :                 if (scan_val.uint_val > 53)
    2858           0 :                     err = 1;
    2859           0 :                 break;
    2860             :             case 'V':
    2861           0 :                 pfmt++;
    2862           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2863           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2864           0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 53)
    2865           0 :                     err = 1;
    2866           0 :                 break;
    2867             :             case 'w':
    2868           0 :                 pfmt++;
    2869           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2870           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2871           0 :                 if (scan_val.uint_val > 6)
    2872           0 :                     err = 1;
    2873           0 :                 break;
    2874             :             case 'W':
    2875           0 :                 pfmt++;
    2876           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2877           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2878           0 :                 if (scan_val.uint_val > 53)
    2879           0 :                     err = 1;
    2880           0 :                 break;
    2881             :             case 'x':
    2882             :             case 'X':
    2883             :                 /* XXX */
    2884           0 :                 break;
    2885             :             case 'Y':
    2886          68 :                 pfmt++;
    2887          68 :                 scan_type = PGTYPES_TYPE_UINT;
    2888          68 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2889          68 :                 *year = scan_val.uint_val;
    2890          68 :                 break;
    2891             :             case 'z':
    2892          32 :                 pfmt++;
    2893          32 :                 scan_type = PGTYPES_TYPE_STRING_MALLOCED;
    2894          32 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2895          32 :                 if (!err)
    2896             :                 {
    2897          32 :                     err = DecodeTimezone(scan_val.str_val, tz);
    2898          32 :                     free(scan_val.str_val);
    2899             :                 }
    2900          32 :                 break;
    2901             :             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             :                     /*
    2908             :                      * XXX use DecodeSpecial instead?  Do we need strcasecmp
    2909             :                      * here?
    2910             :                      */
    2911          16 :                     err = 1;
    2912         800 :                     for (j = 0; j < szdatetktbl; j++)
    2913             :                     {
    2914        1440 :                         if ((datetktbl[j].type == TZ || datetktbl[j].type == DTZ) &&
    2915         640 :                             pg_strcasecmp(datetktbl[j].token,
    2916         640 :                                           scan_val.str_val) == 0)
    2917             :                         {
    2918          16 :                             *tz = -datetktbl[j].value;
    2919          16 :                             err = 0;
    2920          16 :                             break;
    2921             :                         }
    2922             :                     }
    2923          16 :                     free(scan_val.str_val);
    2924             :                 }
    2925          16 :                 break;
    2926             :             case '+':
    2927             :                 /* XXX */
    2928           0 :                 break;
    2929             :             case '%':
    2930          16 :                 pfmt++;
    2931          16 :                 if (*pstr == '%')
    2932          16 :                     pstr++;
    2933             :                 else
    2934           0 :                     err = 1;
    2935          16 :                 break;
    2936             :             default:
    2937           4 :                 err = 1;
    2938             :         }
    2939             :     }
    2940          84 :     if (!err)
    2941             :     {
    2942          80 :         if (*second < 0)
    2943          20 :             *second = 0;
    2944          80 :         if (*minute < 0)
    2945           0 :             *minute = 0;
    2946          80 :         if (*hour < 0)
    2947           0 :             *hour = 0;
    2948          80 :         if (*day < 0)
    2949             :         {
    2950           0 :             err = 1;
    2951           0 :             *day = 1;
    2952             :         }
    2953          80 :         if (*month < 0)
    2954             :         {
    2955           0 :             err = 1;
    2956           0 :             *month = 1;
    2957             :         }
    2958          80 :         if (*year < 0)
    2959             :         {
    2960           0 :             err = 1;
    2961           0 :             *year = 1970;
    2962             :         }
    2963             : 
    2964          80 :         if (*second > 59)
    2965             :         {
    2966           0 :             err = 1;
    2967           0 :             *second = 0;
    2968             :         }
    2969          80 :         if (*minute > 59)
    2970             :         {
    2971           0 :             err = 1;
    2972           0 :             *minute = 0;
    2973             :         }
    2974         160 :         if (*hour > 24 ||        /* test for > 24:00:00 */
    2975          80 :             (*hour == 24 && (*minute > 0 || *second > 0)))
    2976             :         {
    2977           0 :             err = 1;
    2978           0 :             *hour = 0;
    2979             :         }
    2980          80 :         if (*month > MONTHS_PER_YEAR)
    2981             :         {
    2982           0 :             err = 1;
    2983           0 :             *month = 1;
    2984             :         }
    2985          80 :         if (*day > day_tab[isleap(*year)][*month - 1])
    2986             :         {
    2987          16 :             *day = day_tab[isleap(*year)][*month - 1];
    2988          16 :             err = 1;
    2989             :         }
    2990             : 
    2991          80 :         tm.tm_sec = *second;
    2992          80 :         tm.tm_min = *minute;
    2993          80 :         tm.tm_hour = *hour;
    2994          80 :         tm.tm_mday = *day;
    2995          80 :         tm.tm_mon = *month;
    2996          80 :         tm.tm_year = *year;
    2997             : 
    2998          80 :         tm2timestamp(&tm, 0, tz, d);
    2999             :     }
    3000          84 :     return err;
    3001             : }
    3002             : 
    3003             : /* XXX: 1900 is compiled in as the base for years */

Generated by: LCOV version 1.13