c日期格式化操作之timestamp

#include "logger.h"
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <ctype.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#define tAGO 257
#define tDAY 258
#define tDAY_UNIT 259
#define tDAYZONE 260
#define tDST 261
#define tHOUR_UNIT 262
#define tID 263
#define tMERIDIAN 264
#define tMINUTE_UNIT 265
#define tMONTH 266
#define tMONTH_UNIT 267
#define tSEC_UNIT 268
#define tSNUMBER 269
#define tUNUMBER 270
#define tYEAR_UNIT 271
#define tZONE 272

#define ISSPACE(c) (isascii (c) && isspace (c))
#define ISALPHA(c) (isascii (c) && isalpha (c))
#define ISUPPER(c) (isascii (c) && isupper (c))
#define ISDIGIT_LOCALE(c) (isascii (c) && isdigit (c))
#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) #define EPOCH 1970
#define HOUR(x) ((x) * 60)
#define MAX_BUFF_LEN    128
#define PARSE_DATE_FINAL 62
#define PARSE_DATE_FLAG -32768
#define PARSE_DATE_NTBASE 22
#define PARSE_DATE_TRANSLATE(x) ((unsigned)(x) <= 272 ? parse_date_translate[x] : 32)
#define PARSE_DATE_LAST 52
#define PARSE_DATE_TERROR 1
#define PARSE_DATE_ERRCODE 256
#define PARSE_DATE_INITDEPTH 200
#define PARSE_DATE_MAXDEPTH 10000
#define TM_YEAR_ORIGIN 1900

#define PARSE_DATE_BACKUP(token, value) \
do \
  if (parse_date_char == -2 && parse_date_len == 1) \
    { parse_date_char = (token), parse_date_lval = (value); \
      parse_date_char1 = PARSE_DATE_TRANSLATE (parse_date_char); \
      parse_date_vsp--, parse_date_ssp--; \
      goto parse_date_backup; \
    } \
  else \
    { parse_date_error ("syntax error: cannot back up"); goto parse_date_errlab1; } \
while (0)

typedef struct {
  const char *name;
  int type;
  int value;
} TABLE;

typedef enum {
  MERam, MERpm, MER24
} MERIDIAN;

typedef union {
  int Number;
  MERIDIAN Meridian;
} PARSE_DATE_STYPE;

int parse_date ();
static int parse_date_lex ();
static int parse_date_error ();
static const char *parse_date_Input;
static int parse_date_DayOrdinal;
static int parse_date_DayNumber;
static int parse_date_HaveDate;
static int parse_date_HaveDay;
static int parse_date_HaveRel;
static int parse_date_HaveTime;
static int parse_date_HaveZone;
static int parse_date_Timezone;
static int parse_date_Day;
static int parse_date_Hour;
static int parse_date_Minutes;
static int parse_date_Month;
static int parse_date_Seconds;
static int parse_date_Year;
static MERIDIAN parse_date_Meridian;
static int parse_date_RelDay;
static int parse_date_RelHour;
static int parse_date_RelMinutes;
static int parse_date_RelMonth;
static int parse_date_RelSeconds;
static int parse_date_RelYear;
int parse_date_char;
PARSE_DATE_STYPE parse_date_lval;
int parse_date_nerrs;

static const char parse_date_translate[] = { 0,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 20, 2, 2, 21, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 19, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
  7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  17, 18
};

static const char *const parse_date_tname[] =
  { "$", "error", "$undefined.", "tAGO", "tDAY",
  "tDAY_UNIT", "tDAYZONE", "tDST", "tHOUR_UNIT", "tID", "tMERIDIAN",
  "tMINUTE_UNIT",
  "tMONTH", "tMONTH_UNIT", "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tYEAR_UNIT",
  "tZONE",
  "':'", "','", "'/'", "spec", "item", "time", "zone", "day", "date", "rel",
  "relunit", "number",
  "o_merid", NULL
};

static const short parse_date_r1[] = { 0,
  22, 22, 23, 23, 23, 23, 23, 23, 24, 24,
  24, 24, 24, 25, 25, 25, 26, 26, 26, 27,
  27, 27, 27, 27, 27, 27, 27, 27, 28, 28,
  29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
  29, 29, 29, 29, 29, 29, 29, 29, 30, 31,
  31
};

static const short parse_date_r2[] = { 0,
  0, 2, 1, 1, 1, 1, 1, 1, 2, 4,
  4, 6, 6, 1, 1, 2, 1, 2, 2, 3,
  5, 3, 3, 3, 2, 4, 2, 3, 2, 1,
  2, 2, 1, 2, 2, 1, 2, 2, 1, 2,
  2, 1, 2, 2, 1, 2, 2, 1, 1, 0,
  1
};

static const short parse_date_defact[] = { 1,
  0, 17, 39, 15, 42, 45, 0, 36, 48, 0,
  49, 33, 14, 2, 3, 4, 6, 5, 7, 30,
  8, 18, 25, 38, 41, 44, 35, 47, 32, 19,
  37, 40, 9, 43, 27, 34, 46, 0, 31, 0,
  0, 16, 29, 24, 0, 23, 28, 22, 50, 20,
  26, 51, 11, 0, 10, 0, 50, 21, 13, 12,
  0, 0
};

static const short parse_date_defgoto[] = { 1,
  14, 15, 16, 17, 18, 19, 20, 21, 55
};

static const short parse_date_pact[] = { -32768,
  0, -19, -32768, -32768, -32768, -32768, -13, -32768, -32768, 30,
  15, -32768, 14, -32768, -32768, -32768, -32768, -32768, -32768, 19,
  -32768, -32768, 29, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
  -32768, -32768, -32768, -32768, -6, -32768, -32768, 9, -32768, 17,
  23, -32768, -32768, -32768, 24, -32768, -32768, -32768, 27, 10,
  -32768, -32768, -32768, 32, -32768, 34, -8, -32768, -32768, -32768,
  51, -32768
};

static const short parse_date_pgoto[] = { -32768,
  -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, -5
};

static const short parse_date_table[] = { 61,
  22, 52, 23, 2, 3, 4, 59, 5, 46, 47,
  6, 7, 8, 9, 10, 11, 12, 13, 30, 31,
  42, 43, 32, 48, 33, 34, 35, 36, 37, 38,
  56, 39, 49, 40, 24, 41, 52, 25, 50, 51,
  26, 53, 27, 28, 44, 54, 29, 57, 45, 58,
  62, 60
};

static const short parse_date_check[] = { 0,
  20, 10, 16, 4, 5, 6, 15, 8, 15, 16,
  11, 12, 13, 14, 15, 16, 17, 18, 4, 5,
  7, 3, 8, 15, 10, 11, 12, 13, 14, 15,
  21, 17, 16, 19, 5, 21, 10, 8, 16, 16,
  11, 15, 13, 14, 16, 19, 17, 16, 20, 16,
  0, 57
};


int
parse_date ()
{
  register int parse_date_state;
  register int parse_date_n;
  register short *parse_date_ssp;
  register PARSE_DATE_STYPE *parse_date_vsp;
  int parse_date_errstatus;
  int parse_date_char1 = 0;

  short parse_date_ssa[PARSE_DATE_INITDEPTH];
  PARSE_DATE_STYPE parse_date_vsa[PARSE_DATE_INITDEPTH];

  short *parse_date_ss = parse_date_ssa;
  PARSE_DATE_STYPE *parse_date_vs = parse_date_vsa;

  int parse_date_stacksize = PARSE_DATE_INITDEPTH;
  int parse_date_free_stacks = 0;

  PARSE_DATE_STYPE parse_date_val; /*  the variable used to return         */
  /*  semantic values from the action     */
  /*  routines                            */

  int parse_date_len;

  parse_date_state = 0;
  parse_date_errstatus = 0;
  parse_date_nerrs = 0;
  parse_date_char = -2; /* Cause a token to be read.  */

  /* Initialize stack pointers.
     Waste one element of value and location stack
     so that they stay on the same level as the state stack.
     The wasted elements are never initialized.  */


  parse_date_ssp = parse_date_ss - 1;
  parse_date_vsp = parse_date_vs;

parse_date_constructstate:

  *++parse_date_ssp = parse_date_state;

  if (parse_date_ssp >= parse_date_ss + parse_date_stacksize - 1) {
    PARSE_DATE_STYPE *parse_date_vs1 = parse_date_vs;
    short *parse_date_ss1 = parse_date_ss;

    /* Get the current used size of the three stacks, in elements.  */
    int size = parse_date_ssp - parse_date_ss + 1;

    if (parse_date_stacksize >= PARSE_DATE_MAXDEPTH) {
      parse_date_error ("parser stack overflow");
      if (parse_date_free_stacks) {
free (parse_date_ss);
free (parse_date_vs);
      }
      return 2;
    }
    parse_date_stacksize *= 2;
    if (parse_date_stacksize > PARSE_DATE_MAXDEPTH)
      parse_date_stacksize = PARSE_DATE_MAXDEPTH;
    parse_date_ss =
      (short *) malloc (parse_date_stacksize * sizeof (*parse_date_ssp));
    //__builtin_memcpy ((char *) parse_date_ss, (char *) parse_date_ss1,
//       size * (unsigned int) sizeof (*parse_date_ssp));
    memcpy ((char *) parse_date_ss, (char *) parse_date_ss1,
      size * (unsigned int) sizeof (*parse_date_ssp));
    parse_date_vs =
      (PARSE_DATE_STYPE *) malloc (parse_date_stacksize *
   sizeof (*parse_date_vsp));
    //__builtin_memcpy ((char *) parse_date_vs, (char *) parse_date_vs1,
//       size * (unsigned int) sizeof (*parse_date_vsp));
    memcpy ((char *) parse_date_vs, (char *) parse_date_vs1,
      size * (unsigned int) sizeof (*parse_date_vsp));

    parse_date_ssp = parse_date_ss + size - 1;
    parse_date_vsp = parse_date_vs + size - 1;


    if (parse_date_ssp >= parse_date_ss + parse_date_stacksize - 1)
      goto parse_date_abortlab;
  }


  goto parse_date_backup;
parse_date_backup:

  parse_date_n = parse_date_pact[parse_date_state];
  if (parse_date_n == PARSE_DATE_FLAG)
    goto parse_date_default;

  if (parse_date_char == -2) {
    parse_date_char = parse_date_lex ();
  }

  if (parse_date_char <= 0) { /* This means end of input. */
    parse_date_char1 = 0;
    parse_date_char = 0; /* Don't call parse_date_lex() any more */

  }
  else {
    parse_date_char1 = PARSE_DATE_TRANSLATE (parse_date_char);

  }

  parse_date_n += parse_date_char1;
  if (parse_date_n < 0 || parse_date_n > PARSE_DATE_LAST
      || parse_date_check[parse_date_n] != parse_date_char1)
    goto parse_date_default;

  parse_date_n = parse_date_table[parse_date_n];

  if (parse_date_n < 0) {
    if (parse_date_n == PARSE_DATE_FLAG)
      goto parse_date_errlab;
    parse_date_n = -parse_date_n;
    goto parse_date_reduce;
  }
  else if (parse_date_n == 0)
    goto parse_date_errlab;

  if (parse_date_n == PARSE_DATE_FINAL)
    goto parse_date_acceptlab;

  if (parse_date_char != 0)
    parse_date_char = -2;

  *++parse_date_vsp = parse_date_lval;

  /* count tokens shifted since error; after three, turn off error status.  */
  if (parse_date_errstatus)
    parse_date_errstatus--;

  parse_date_state = parse_date_n;
  goto parse_date_constructstate;

/* Do the default action for the current state.  */
parse_date_default:

  parse_date_n = parse_date_defact[parse_date_state];
  if (parse_date_n == 0)
    goto parse_date_errlab;

/* Do a reduction.  parse_date_n is the number of a rule to reduce with.  */
parse_date_reduce:
  parse_date_len = parse_date_r2[parse_date_n];
  if (parse_date_len > 0)
    parse_date_val = parse_date_vsp[1 - parse_date_len]; /* implement default value of the action */


  switch (parse_date_n) {

  case 3:
    {
      parse_date_HaveTime++;
      ;
      break;
    }
  case 4:
    {
      parse_date_HaveZone++;
      ;
      break;
    }
  case 5:
    {
      parse_date_HaveDate++;
      ;
      break;
    }
  case 6:
    {
      parse_date_HaveDay++;
      ;
      break;
    }
  case 7:
    {
      parse_date_HaveRel++;
      ;
      break;
    }
  case 9:
    {
      parse_date_Hour = parse_date_vsp[-1].Number;
      parse_date_Minutes = 0;
      parse_date_Seconds = 0;
      parse_date_Meridian = parse_date_vsp[0].Meridian;
      ;
      break;
    }
  case 10:
    {
      parse_date_Hour = parse_date_vsp[-3].Number;
      parse_date_Minutes = parse_date_vsp[-1].Number;
      parse_date_Seconds = 0;
      parse_date_Meridian = parse_date_vsp[0].Meridian;
      ;
      break;
    }
  case 11:
    {
      parse_date_Hour = parse_date_vsp[-3].Number;
      parse_date_Minutes = parse_date_vsp[-1].Number;
      parse_date_Meridian = MER24;
      parse_date_HaveZone++;
      parse_date_Timezone = (parse_date_vsp[0].Number < 0
     ? -parse_date_vsp[0].Number % 100 +
     (-parse_date_vsp[0].Number / 100) *
     60 : -(parse_date_vsp[0].Number % 100 +
    (parse_date_vsp[0].Number / 100) * 60));
      ;
      break;
    }
  case 12:
    {
      parse_date_Hour = parse_date_vsp[-5].Number;
      parse_date_Minutes = parse_date_vsp[-3].Number;
      parse_date_Seconds = parse_date_vsp[-1].Number;
      parse_date_Meridian = parse_date_vsp[0].Meridian;
      ;
      break;
    }
  case 13:
    {
      parse_date_Hour = parse_date_vsp[-5].Number;
      parse_date_Minutes = parse_date_vsp[-3].Number;
      parse_date_Seconds = parse_date_vsp[-1].Number;
      parse_date_Meridian = MER24;
      parse_date_HaveZone++;
      parse_date_Timezone = (parse_date_vsp[0].Number < 0
     ? -parse_date_vsp[0].Number % 100 +
     (-parse_date_vsp[0].Number / 100) *
     60 : -(parse_date_vsp[0].Number % 100 +
    (parse_date_vsp[0].Number / 100) * 60));
      ;
      break;
    }
  case 14:
    {
      parse_date_Timezone = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 15:
    {
      parse_date_Timezone = parse_date_vsp[0].Number - 60;
      ;
      break;
    }
  case 16:
    {
      parse_date_Timezone = parse_date_vsp[-1].Number - 60;
      ;
      break;
    }
  case 17:
    {
      parse_date_DayOrdinal = 1;
      parse_date_DayNumber = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 18:
    {
      parse_date_DayOrdinal = 1;
      parse_date_DayNumber = parse_date_vsp[-1].Number;
      ;
      break;
    }
  case 19:
    {
      parse_date_DayOrdinal = parse_date_vsp[-1].Number;
      parse_date_DayNumber = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 20:
    {
      parse_date_Month = parse_date_vsp[-2].Number;
      parse_date_Day = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 21:
    {
      /* Interpret as PARSE_DATE_PARSE_DATE_/MM/DD if $1 >= 1000, otherwise as MM/DD/PARSE_DATE_.
         The goal in recognizing PARSE_DATE_PARSE_DATE_/MM/DD is solely to support legacy
         machine-generated dates like those in an RCS log listing.  If
         you want portability, use the ISO 8601 format.  */

      if (parse_date_vsp[-4].Number >= 1000) {
parse_date_Year = parse_date_vsp[-4].Number;
parse_date_Month = parse_date_vsp[-2].Number;
parse_date_Day = parse_date_vsp[0].Number;
      }
      else {
parse_date_Month = parse_date_vsp[-4].Number;
parse_date_Day = parse_date_vsp[-2].Number;
parse_date_Year = parse_date_vsp[0].Number;
      }
      ;
      break;
    }
  case 22:
    {
      /* ISO 8601 format.  parse_date_date_-mm-dd.  */
      parse_date_Year = parse_date_vsp[-2].Number;
      parse_date_Month = -parse_date_vsp[-1].Number;
      parse_date_Day = -parse_date_vsp[0].Number;
      ;
      break;
    }
  case 23:
    {
      /* e.g. 17-JUN-1992.  */
      parse_date_Day = parse_date_vsp[-2].Number;
      parse_date_Month = parse_date_vsp[-1].Number;
      parse_date_Year = -parse_date_vsp[0].Number;
      ;
      break;
    }
  case 24:
    {
      parse_date_Month = parse_date_vsp[-2].Number;
      parse_date_Day = parse_date_vsp[-1].Number;
      parse_date_Year = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 25:
    {
      parse_date_Month = parse_date_vsp[-1].Number;
      parse_date_Day = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 26:
    {
      parse_date_Month = parse_date_vsp[-3].Number;
      parse_date_Day = parse_date_vsp[-2].Number;
      parse_date_Year = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 27:
    {
      parse_date_Month = parse_date_vsp[0].Number;
      parse_date_Day = parse_date_vsp[-1].Number;
      ;
      break;
    }
  case 28:
    {
      parse_date_Month = parse_date_vsp[-1].Number;
      parse_date_Day = parse_date_vsp[-2].Number;
      parse_date_Year = parse_date_vsp[0].Number;
      ;
      break;
    }
  case 29:
    {
      parse_date_RelSeconds = -parse_date_RelSeconds;
      parse_date_RelMinutes = -parse_date_RelMinutes;
      parse_date_RelHour = -parse_date_RelHour;
      parse_date_RelDay = -parse_date_RelDay;
      parse_date_RelMonth = -parse_date_RelMonth;
      parse_date_RelYear = -parse_date_RelYear;
      ;
      break;
    }
  case 31:
    {
      parse_date_RelYear +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 32:
    {
      parse_date_RelYear +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 33:
    {
      parse_date_RelYear += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 34:
    {
      parse_date_RelMonth +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 35:
    {
      parse_date_RelMonth +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 36:
    {
      parse_date_RelMonth += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 37:
    {
      parse_date_RelDay +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 38:
    {
      parse_date_RelDay +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 39:
    {
      parse_date_RelDay += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 40:
    {
      parse_date_RelHour +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 41:
    {
      parse_date_RelHour +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 42:
    {
      parse_date_RelHour += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 43:
    {
      parse_date_RelMinutes +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 44:
    {
      parse_date_RelMinutes +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 45:
    {
      parse_date_RelMinutes += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 46:
    {
      parse_date_RelSeconds +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 47:
    {
      parse_date_RelSeconds +=
parse_date_vsp[-1].Number * parse_date_vsp[0].Number;
      ;
      break;
    }
  case 48:
    {
      parse_date_RelSeconds += parse_date_vsp[0].Number;
      ;
      break;
    }
  case 49:
    {
      if (parse_date_HaveTime && parse_date_HaveDate && !parse_date_HaveRel)
parse_date_Year = parse_date_vsp[0].Number;
      else {
if (parse_date_vsp[0].Number > 10000) {
  parse_date_HaveDate++;
  parse_date_Day = (parse_date_vsp[0].Number) % 100;
  parse_date_Month = (parse_date_vsp[0].Number / 100) % 100;
  parse_date_Year = parse_date_vsp[0].Number / 10000;
}
else {
  parse_date_HaveTime++;
  if (parse_date_vsp[0].Number < 100) {
    parse_date_Hour = parse_date_vsp[0].Number;
    parse_date_Minutes = 0;
  }
  else {
    parse_date_Hour = parse_date_vsp[0].Number / 100;
    parse_date_Minutes = parse_date_vsp[0].Number % 100;
  }
  parse_date_Seconds = 0;
  parse_date_Meridian = MER24;
}
      }
      ;
      break;
    }
  case 50:
    {
      parse_date_val.Meridian = MER24;
      ;
      break;
    }
  case 51:
    {
      parse_date_val.Meridian = parse_date_vsp[0].Meridian;
      ;
      break;
    }
  }
  /* the action file gets copied in in place of this dollarsign */


  parse_date_vsp -= parse_date_len;
  parse_date_ssp -= parse_date_len;
  *++parse_date_vsp = parse_date_val;

  /* Now "shift" the result of the reduction.
     Determine what state that goes to,
     based on the state we popped back to
     and the rule number reduced by.  */


  parse_date_n = parse_date_r1[parse_date_n];

  parse_date_state =
    parse_date_pgoto[parse_date_n - PARSE_DATE_NTBASE] + *parse_date_ssp;
  if (parse_date_state >= 0 && parse_date_state <= PARSE_DATE_LAST
      && parse_date_check[parse_date_state] == *parse_date_ssp)
    parse_date_state = parse_date_table[parse_date_state];
  else
    parse_date_state = parse_date_defgoto[parse_date_n - PARSE_DATE_NTBASE];

  goto parse_date_constructstate;

parse_date_errlab: /* here on detecting error */

  if (!parse_date_errstatus)
    /* If not already recovering from an error, report this error.  */
  {
    ++parse_date_nerrs;

    parse_date_error ("parse error");
  }

  goto parse_date_errlab1;
parse_date_errlab1: /* here on error raised explicitly by an action */

  if (parse_date_errstatus == 3) {
    /* if just tried and failed to reuse lookahead token after an error, discard it.  */

    /* return failure if at end of input */
    if (parse_date_char == 0)
      goto parse_date_abortlab;

    parse_date_char = -2;
  }

  /* Else will try to reuse lookahead token
     after shifting the error token.  */


  parse_date_errstatus = 3; /* Each real token shifted decrements this */

  goto parse_date_errhandle;

parse_date_errdefault: /* current state does not do anything special for the error token. */

parse_date_errpop: /* pop the current state because it cannot handle the error token */

  if (parse_date_ssp == parse_date_ss)
    goto parse_date_abortlab;
  parse_date_vsp--;
  parse_date_state = *--parse_date_ssp;

parse_date_errhandle:

  parse_date_n = parse_date_pact[parse_date_state];
  if (parse_date_n == PARSE_DATE_FLAG)
    goto parse_date_errdefault;

  parse_date_n += PARSE_DATE_TERROR;
  if (parse_date_n < 0 || parse_date_n > PARSE_DATE_LAST
      || parse_date_check[parse_date_n] != PARSE_DATE_TERROR)
    goto parse_date_errdefault;

  parse_date_n = parse_date_table[parse_date_n];
  if (parse_date_n < 0) {
    if (parse_date_n == PARSE_DATE_FLAG)
      goto parse_date_errpop;
    parse_date_n = -parse_date_n;
    goto parse_date_reduce;
  }
  else if (parse_date_n == 0)
    goto parse_date_errpop;

  if (parse_date_n == PARSE_DATE_FINAL)
    goto parse_date_acceptlab;

  *++parse_date_vsp = parse_date_lval;

  parse_date_state = parse_date_n;
  goto parse_date_constructstate;

parse_date_acceptlab:
  /* goto parse_date_acceptlab comes here.  */
  if (parse_date_free_stacks) {
    free (parse_date_ss);
    free (parse_date_vs);
  }
  return 0;

parse_date_abortlab:
  /* goto parse_date_abortlab comes here.  */
  if (parse_date_free_stacks) {
    free (parse_date_ss);
    free (parse_date_vs);
  }
  return 1;
}


time_t get_date (char *p, time_t * now);

/* Month and day table. */
static TABLE const MonthDayTable[] = {
  {"january", tMONTH, 1},
  {"february", tMONTH, 2},
  {"march", tMONTH, 3},
  {"april", tMONTH, 4},
  {"may", tMONTH, 5},
  {"june", tMONTH, 6},
  {"july", tMONTH, 7},
  {"august", tMONTH, 8},
  {"september", tMONTH, 9},
  {"sept", tMONTH, 9},
  {"october", tMONTH, 10},
  {"november", tMONTH, 11},
  {"december", tMONTH, 12},
  {"sunday", tDAY, 0},
  {"monday", tDAY, 1},
  {"tuesday", tDAY, 2},
  {"tues", tDAY, 2},
  {"wednesday", tDAY, 3},
  {"wednes", tDAY, 3},
  {"thursday", tDAY, 4},
  {"thur", tDAY, 4},
  {"thurs", tDAY, 4},
  {"friday", tDAY, 5},
  {"saturday", tDAY, 6},
  {NULL, 0, 0}
};

/* Time units table. */
static TABLE const UnitsTable[] = {
  {"year", tYEAR_UNIT, 1},
  {"month", tMONTH_UNIT, 1},
  {"fortnight", tDAY_UNIT, 14},
  {"week", tDAY_UNIT, 7},
  {"day", tDAY_UNIT, 1},
  {"hour", tHOUR_UNIT, 1},
  {"minute", tMINUTE_UNIT, 1},
  {"min", tMINUTE_UNIT, 1},
  {"second", tSEC_UNIT, 1},
  {"sec", tSEC_UNIT, 1},
  {NULL, 0, 0}
};

/* Assorted relative-time words. */
static TABLE const OtherTable[] = {
  {"tomorrow", tDAY_UNIT, 1},
  {"yesterday", tDAY_UNIT, -1},
  {"today", tDAY_UNIT, 0},
  {"now", tDAY_UNIT, 0},
  {"last", tUNUMBER, -1},
  {"this", tMINUTE_UNIT, 0},
  {"next", tUNUMBER, 1},
  {"first", tUNUMBER, 1},
/*  { "second", tUNUMBER, 2 }, */
  {"third", tUNUMBER, 3},
  {"fourth", tUNUMBER, 4},
  {"fifth", tUNUMBER, 5},
  {"sixth", tUNUMBER, 6},
  {"seventh", tUNUMBER, 7},
  {"eighth", tUNUMBER, 8},
  {"ninth", tUNUMBER, 9},
  {"tenth", tUNUMBER, 10},
  {"eleventh", tUNUMBER, 11},
  {"twelfth", tUNUMBER, 12},
  {"ago", tAGO, 1},
  {NULL, 0, 0}
};

/* The timezone table. */
static TABLE const TimezoneTable[] = {
  {"gmt", tZONE, HOUR (0)}, /* Greenwich Mean */
  {"ut", tZONE, HOUR (0)}, /* Universal (Coordinated) */
  {"utc", tZONE, HOUR (0)},
  {"wet", tZONE, HOUR (0)}, /* Western European */
  {"bst", tDAYZONE, HOUR (0)}, /* British Summer */
  {"wat", tZONE, HOUR (1)}, /* West Africa */
  {"at", tZONE, HOUR (2)}, /* Azores */
  {"ast", tZONE, HOUR (4)}, /* Atlantic Standard */
  {"adt", tDAYZONE, HOUR (4)}, /* Atlantic Daylight */
  {"est", tZONE, HOUR (5)}, /* Eastern Standard */
  {"edt", tDAYZONE, HOUR (5)}, /* Eastern Daylight */
  {"cst", tZONE, HOUR (6)}, /* Central Standard */
  {"cdt", tDAYZONE, HOUR (6)}, /* Central Daylight */
  {"mst", tZONE, HOUR (7)}, /* Mountain Standard */
  {"mdt", tDAYZONE, HOUR (7)}, /* Mountain Daylight */
  {"pst", tZONE, HOUR (8)}, /* Pacific Standard */
  {"pdt", tDAYZONE, HOUR (8)}, /* Pacific Daylight */
  {"yst", tZONE, HOUR (9)}, /* Yukon Standard */
  {"ydt", tDAYZONE, HOUR (9)}, /* Yukon Daylight */
  {"hst", tZONE, HOUR (10)}, /* Hawaii Standard */
  {"hdt", tDAYZONE, HOUR (10)}, /* Hawaii Daylight */
  {"cat", tZONE, HOUR (10)}, /* Central Alaska */
  {"akst", tZONE, HOUR (10)}, /* Alaska Standard */
  {"akdt", tZONE, HOUR (10)}, /* Alaska Daylight */
  {"ahst", tZONE, HOUR (10)}, /* Alaska-Hawaii Standard */
  {"nt", tZONE, HOUR (11)}, /* Nome */
  {"idlw", tZONE, HOUR (12)}, /* International Date Line West */
  {"cet", tZONE, -HOUR (1)}, /* Central European */
  {"met", tZONE, -HOUR (1)}, /* Middle European */
  {"mewt", tZONE, -HOUR (1)}, /* Middle European Winter */
  {"mest", tDAYZONE, -HOUR (1)}, /* Middle European Summer */
  {"mesz", tDAYZONE, -HOUR (1)}, /* Middle European Summer */
  {"swt", tZONE, -HOUR (1)}, /* Swedish Winter */
  {"sst", tDAYZONE, -HOUR (1)}, /* Swedish Summer */
  {"fwt", tZONE, -HOUR (1)}, /* French Winter */
  {"fst", tDAYZONE, -HOUR (1)}, /* French Summer */
  {"eet", tZONE, -HOUR (2)}, /* Eastern Europe, USSR Zone 1 */
  {"bt", tZONE, -HOUR (3)}, /* Baghdad, USSR Zone 2 */
  {"zp4", tZONE, -HOUR (4)}, /* USSR Zone 3 */
  {"zp5", tZONE, -HOUR (5)}, /* USSR Zone 4 */
  {"zp6", tZONE, -HOUR (6)}, /* USSR Zone 5 */
  {"wast", tZONE, -HOUR (7)}, /* West Australian Standard */
  {"wadt", tDAYZONE, -HOUR (7)}, /* West Australian Daylight */
  {"cct", tZONE, -HOUR (8)}, /* China Coast, USSR Zone 7 */
  {"jst", tZONE, -HOUR (9)}, /* Japan Standard, USSR Zone 8 */
  {"east", tZONE, -HOUR (10)}, /* Eastern Australian Standard */
  {"eadt", tDAYZONE, -HOUR (10)}, /* Eastern Australian Daylight */
  {"gst", tZONE, -HOUR (10)}, /* Guam Standard, USSR Zone 9 */
  {"nzt", tZONE, -HOUR (12)}, /* New Zealand */
  {"nzst", tZONE, -HOUR (12)}, /* New Zealand Standard */
  {"nzdt", tDAYZONE, -HOUR (12)}, /* New Zealand Daylight */
  {"idle", tZONE, -HOUR (12)}, /* International Date Line East */
  {NULL, 0, 0}
};

/* Military timezone table. */
static TABLE const MilitaryTable[] = {
  {"a", tZONE, HOUR (1)},
  {"b", tZONE, HOUR (2)},
  {"c", tZONE, HOUR (3)},
  {"d", tZONE, HOUR (4)},
  {"e", tZONE, HOUR (5)},
  {"f", tZONE, HOUR (6)},
  {"g", tZONE, HOUR (7)},
  {"h", tZONE, HOUR (8)},
  {"i", tZONE, HOUR (9)},
  {"k", tZONE, HOUR (10)},
  {"l", tZONE, HOUR (11)},
  {"m", tZONE, HOUR (12)},
  {"n", tZONE, HOUR (-1)},
  {"o", tZONE, HOUR (-2)},
  {"p", tZONE, HOUR (-3)},
  {"q", tZONE, HOUR (-4)},
  {"r", tZONE, HOUR (-5)},
  {"s", tZONE, HOUR (-6)},
  {"t", tZONE, HOUR (-7)},
  {"u", tZONE, HOUR (-8)},
  {"v", tZONE, HOUR (-9)},
  {"w", tZONE, HOUR (-10)},
  {"x", tZONE, HOUR (-11)},
  {"y", tZONE, HOUR (-12)},
  {"z", tZONE, HOUR (0)},
  {NULL, 0, 0}
};



static int parse_date_error (char *s) {
  s = NULL;
  return 0;
}

static int ToHour (int Hours, MERIDIAN Meridian) {

  switch (Meridian) {
      case MER24:
        if (Hours < 0 || Hours > 23)
          return -1;
        return Hours;
      case MERam:
        if (Hours < 1 || Hours > 12)
          return -1;
        if (Hours == 12)
          Hours = 0;
        return Hours;
      case MERpm:
        if (Hours < 1 || Hours > 12)
          return -1;
        if (Hours == 12)
          Hours = 0;
        return Hours + 12;
      default:
        abort ();
  }

  return -1;
}

static int ToYear (int Year) {
  if (Year < 0)
    Year = -Year;

  /* XPG4 suggests that years 00-68 map to 2000-2068, and
     years 69-99 map to 1969-1999.  */

  if (Year < 69)
    Year += 2000;
  else if (Year < 100)
    Year += 1900;

  return Year;
}

static int LookupWord (char *buff) {
  register char *p;
  register char *q;
  register const TABLE *tp;
  int i;
  int abbrev;

  /* Make it lowercase. */
  for (p = buff; *p; p++)
    if (ISUPPER ((unsigned char) *p))
      *p = tolower (*p);

  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
    parse_date_lval.Meridian = MERam;
    return tMERIDIAN;
  }
  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
    parse_date_lval.Meridian = MERpm;
    return tMERIDIAN;
  }

  /* See if we have an abbreviation for a month. */
  if (strlen (buff) == 3)
    abbrev = 1;
  else if (strlen (buff) == 4 && buff[3] == '.') {
    abbrev = 1;
    buff[3] = '\0';
  }
  else
    abbrev = 0;

  for (tp = MonthDayTable; tp->name; tp++) {
    if (abbrev) {
      if (strncmp (buff, tp->name, 3) == 0) {
parse_date_lval.Number = tp->value;
return tp->type;
      }
    }
    else if (strcmp (buff, tp->name) == 0) {
      parse_date_lval.Number = tp->value;
      return tp->type;
    }
  }

  for (tp = TimezoneTable; tp->name; tp++)
    if (strcmp (buff, tp->name) == 0) {
      parse_date_lval.Number = tp->value;
      return tp->type;
    }

  if (strcmp (buff, "dst") == 0)
    return tDST;

  for (tp = UnitsTable; tp->name; tp++)
    if (strcmp (buff, tp->name) == 0) {
      parse_date_lval.Number = tp->value;
      return tp->type;
    }

  /* Strip off any plural and try the units table again. */
  i = strlen (buff) - 1;
  if (buff[i] == 's') {
    buff[i] = '\0';
    for (tp = UnitsTable; tp->name; tp++)
      if (strcmp (buff, tp->name) == 0) {
parse_date_lval.Number = tp->value;
return tp->type;
      }
    buff[i] = 's'; /* Put back for "this" in OtherTable. */
  }

  for (tp = OtherTable; tp->name; tp++)
    if (strcmp (buff, tp->name) == 0) {
      parse_date_lval.Number = tp->value;
      return tp->type;
    }

  /* Military timezones. */
  if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff)) {
    for (tp = MilitaryTable; tp->name; tp++)
      if (strcmp (buff, tp->name) == 0) {
parse_date_lval.Number = tp->value;
return tp->type;
      }
  }

  /* Drop out any periods and try the timezone table again. */
  for (i = 0, p = q = buff; *q; q++)
    if (*q != '.')
      *p++ = *q;
    else
      i++;
  *p = '\0';
  if (i)
    for (tp = TimezoneTable; tp->name; tp++)
      if (strcmp (buff, tp->name) == 0) {
parse_date_lval.Number = tp->value;
return tp->type;
      }

  return tID;
}

static int parse_date_lex () {
  register unsigned char c;
  register char *p;
  char buff[20];
  int Count;
  int sign;

  for (;;) {
    while (ISSPACE ((unsigned char) *parse_date_Input))
      parse_date_Input++;

    if (ISDIGIT (c = *parse_date_Input) || c == '-' || c == '+') {
      if (c == '-' || c == '+') {
sign = c == '-' ? -1 : 1;
if (!ISDIGIT (*++parse_date_Input))
  /* skip the '-' sign */
  continue;
      }
      else
sign = 0;
      for (parse_date_lval.Number = 0; ISDIGIT (c = *parse_date_Input++);)
parse_date_lval.Number = 10 * parse_date_lval.Number + c - '0';
      parse_date_Input--;
      if (sign < 0)
parse_date_lval.Number = -parse_date_lval.Number;
      return sign ? tSNUMBER : tUNUMBER;
    }
    if (ISALPHA (c)) {
      for (p = buff; (c = *parse_date_Input++, ISALPHA (c)) || c == '.';)
if (p < &buff[sizeof buff - 1])
  *p++ = c;
      *p = '\0';
      parse_date_Input--;
      return LookupWord (buff);
    }
    if (c != '(')
      return *parse_date_Input++;
    Count = 0;
    do {
      c = *parse_date_Input++;
      if (c == '\0')
return c;
      if (c == '(')
Count++;
      else if (c == ')')
Count--;
    }
    while (Count > 0);
  }
}


/* Yield A - B, measured in seconds.  */
static long difftm (struct tm *a, struct tm *b) {
  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
  long days = (
/* difference in day of year */
a->tm_yday - b->tm_yday
/* + intervening leap days */
+ ((ay >> 2) - (by >> 2))
- (ay / 100 - by / 100) + ((ay / 100 >> 2) - (by / 100 >> 2))
/* + difference in years * 365 */
+ (long) (ay - by) * 365);
  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec));
}

time_t get_timestamp (const char *date) {
  struct tm tm, tm0, *tmp;
  time_t Start;

  if (date == NULL) {
      return time(NULL);
  }

  parse_date_Input = date;
  Start = time(NULL);
  tmp = localtime(&Start);
  if (!tmp)
    return -1;
  parse_date_Year = tmp->tm_year + TM_YEAR_ORIGIN;
  parse_date_Month = tmp->tm_mon + 1;
  parse_date_Day = tmp->tm_mday;
  parse_date_Hour = tmp->tm_hour;
  parse_date_Minutes = tmp->tm_min;
  parse_date_Seconds = tmp->tm_sec;
  tm.tm_isdst = tmp->tm_isdst;
  parse_date_Meridian = MER24;
  parse_date_RelSeconds = 0;
  parse_date_RelMinutes = 0;
  parse_date_RelHour = 0;
  parse_date_RelDay = 0;
  parse_date_RelMonth = 0;
  parse_date_RelYear = 0;
  parse_date_HaveDate = 0;
  parse_date_HaveDay = 0;
  parse_date_HaveRel = 0;
  parse_date_HaveTime = 0;
  parse_date_HaveZone = 0;

  if (parse_date ()
      || parse_date_HaveTime > 1 || parse_date_HaveZone > 1
      || parse_date_HaveDate > 1 || parse_date_HaveDay > 1)
    return -1;

  tm.tm_year = ToYear (parse_date_Year) - TM_YEAR_ORIGIN + parse_date_RelYear;
  tm.tm_mon = parse_date_Month - 1 + parse_date_RelMonth;
  tm.tm_mday = parse_date_Day + parse_date_RelDay;
  if (parse_date_HaveTime
      || (parse_date_HaveRel && !parse_date_HaveDate
  && !parse_date_HaveDay)) {
    tm.tm_hour = ToHour (parse_date_Hour, parse_date_Meridian);
    if (tm.tm_hour < 0)
      return -1;
    tm.tm_min = parse_date_Minutes;
    tm.tm_sec = parse_date_Seconds;
  }
  else {
    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
  }
  tm.tm_hour += parse_date_RelHour;
  tm.tm_min += parse_date_RelMinutes;
  tm.tm_sec += parse_date_RelSeconds;

  if (parse_date_HaveDate | parse_date_HaveDay | parse_date_HaveTime |
      parse_date_RelDay | parse_date_RelMonth | parse_date_RelYear)
    tm.tm_isdst = -1;

  tm0 = tm;

  Start = mktime (&tm);

  if (Start == (time_t) - 1) {

    /* Guard against falsely reporting errors near the time_t boundaries
       when parsing times in other time zones.  For example, if the min
       time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
       of UTC, then the min localtime value is 1970-01-01 08:00:00; if
       we apply mktime to 1970-01-01 00:00:00 we will get an error, so
       we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
       zone by 24 hours to compensate.  This algorithm assumes that
       there is no DST transition within a day of the time_t boundaries.  */

    if (parse_date_HaveZone) {
      tm = tm0;
      if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) {
tm.tm_mday++;
parse_date_Timezone -= 24 * 60;
      }
      else {
tm.tm_mday--;
parse_date_Timezone += 24 * 60;
      }
      Start = mktime (&tm);
    }

    if (Start == (time_t) - 1)
      return Start;
  }

  if (parse_date_HaveDay && !parse_date_HaveDate) {
    tm.tm_mday += ((parse_date_DayNumber - tm.tm_wday + 7) % 7
   + 7 * (parse_date_DayOrdinal -
  (0 < parse_date_DayOrdinal)));
    Start = mktime (&tm);
    if (Start == (time_t) - 1)
      return Start;
  }

  if (parse_date_HaveZone) {
    long delta;
    struct tm *gmt = gmtime (&Start);
    if (!gmt)
      return -1;
    delta = parse_date_Timezone * 60L + difftm (&tm, gmt);
    if ((Start + delta < Start) != (delta < 0))
      return -1; /* time_t overflow */
    Start += delta;
  }

  return Start;
}
posted @ 2011-09-27 12:47  火腿骑士  阅读(462)  评论(0编辑  收藏  举报