mirror of https://github.com/postgres/postgres
parent
26a6378e84
commit
2e6f97560a
@ -0,0 +1,12 @@ |
|||||||
|
#ifndef PGTYPES_DATETIME |
||||||
|
#define PGTYPES_DATETIME |
||||||
|
|
||||||
|
#define Date long |
||||||
|
|
||||||
|
extern Date PGTYPESdate_atod(char *, char **); |
||||||
|
extern char *PGTYPESdate_dtoa(Date); |
||||||
|
extern int PGTYPESdate_julmdy(Date, int*); |
||||||
|
extern int PGTYPESdate_mdyjul(int*, Date *); |
||||||
|
extern int PGTYPESdate_day(Date); |
||||||
|
|
||||||
|
#endif /* PGTYPES_DATETIME */ |
@ -0,0 +1,16 @@ |
|||||||
|
#ifndef PGTYPES_TIMESTAMP |
||||||
|
#define PGTYPES_TIMESTAMP |
||||||
|
|
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
typedef int64 Timestamp; |
||||||
|
typedef int64 TimestampTz; |
||||||
|
|
||||||
|
#else |
||||||
|
typedef double Timestamp; |
||||||
|
typedef double TimestampTz; |
||||||
|
#endif |
||||||
|
|
||||||
|
extern Timestamp PGTYPEStimestamp_atot(char *, char **); |
||||||
|
extern char *PGTYPEStimestamp_ttoa(Timestamp); |
||||||
|
|
||||||
|
#endif /* PGTYPES_TIMESTAMP */ |
@ -0,0 +1,29 @@ |
|||||||
|
#include <errno.h> |
||||||
|
|
||||||
|
#include "extern.h" |
||||||
|
|
||||||
|
char * |
||||||
|
pgtypes_alloc(long size) |
||||||
|
{ |
||||||
|
char *new = (char *) calloc(1L, size); |
||||||
|
|
||||||
|
if (!new) |
||||||
|
{ |
||||||
|
errno = ENOMEM; |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
memset(new, '\0', size); |
||||||
|
return (new); |
||||||
|
} |
||||||
|
|
||||||
|
char * |
||||||
|
pgtypes_strdup(char *str) |
||||||
|
{ |
||||||
|
char *new = (char *) strdup(str); |
||||||
|
|
||||||
|
if (!new) |
||||||
|
errno = ENOMEM; |
||||||
|
return (new); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,105 @@ |
|||||||
|
#include <ctype.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <time.h> |
||||||
|
#include <float.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#include "dt.h" |
||||||
|
#include "extern.h" |
||||||
|
#include "pgtypes_error.h" |
||||||
|
#include "pgtypes_date.h" |
||||||
|
|
||||||
|
Date |
||||||
|
PGTYPESdate_atod(char *str, char **endptr) |
||||||
|
{ |
||||||
|
|
||||||
|
Date dDate; |
||||||
|
fsec_t fsec; |
||||||
|
struct tm tt, |
||||||
|
*tm = &tt; |
||||||
|
int tzp; |
||||||
|
int dtype; |
||||||
|
int nf; |
||||||
|
char *field[MAXDATEFIELDS]; |
||||||
|
int ftype[MAXDATEFIELDS]; |
||||||
|
char lowstr[MAXDATELEN + 1]; |
||||||
|
char *realptr; |
||||||
|
char **ptr = (endptr != NULL) ? endptr : &realptr; |
||||||
|
|
||||||
|
bool EuroDates = FALSE; |
||||||
|
|
||||||
|
if (strlen(str) >= sizeof(lowstr)) |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_DATE; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0) |
||||||
|
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp, EuroDates) != 0)) |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_DATE; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
switch (dtype) |
||||||
|
{ |
||||||
|
case DTK_DATE: |
||||||
|
break; |
||||||
|
|
||||||
|
case DTK_EPOCH: |
||||||
|
GetEpochTime(tm);
|
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
errno = PGTYPES_BAD_DATE; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1)); |
||||||
|
|
||||||
|
return dDate; |
||||||
|
} |
||||||
|
|
||||||
|
char * |
||||||
|
PGTYPESdate_dtoa(Date dDate) |
||||||
|
{ |
||||||
|
struct tm tt, *tm = &tt; |
||||||
|
char buf[MAXDATELEN + 1]; |
||||||
|
int DateStyle=0; |
||||||
|
bool EuroDates = FALSE; |
||||||
|
|
||||||
|
j2date((dDate + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); |
||||||
|
EncodeDateOnly(tm, DateStyle, buf, EuroDates); |
||||||
|
return pgtypes_strdup(buf); |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
PGTYPESdate_julmdy(Date jd, int* mdy) |
||||||
|
{ |
||||||
|
printf("day: %d\n", mdy[0]); |
||||||
|
printf("month: %d\n", mdy[1]); |
||||||
|
printf("year: %d\n", mdy[2]); |
||||||
|
j2date((int) jd, mdy+2, mdy+1, mdy+0); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
PGTYPESdate_mdyjul(int* mdy, Date *jdate) |
||||||
|
{ |
||||||
|
/* month is mdy[0] */ |
||||||
|
/* day is mdy[1] */ |
||||||
|
/* year is mdy[2] */ |
||||||
|
printf("day: %d\n", mdy[1]); |
||||||
|
printf("month: %d\n", mdy[0]); |
||||||
|
printf("year: %d\n", mdy[2]); |
||||||
|
*jdate = (Date) date2j(mdy[2], mdy[0], mdy[1]); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
PGTYPESdate_day(Date dDate) |
||||||
|
{ |
||||||
|
return j2day(dDate); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,303 @@ |
|||||||
|
#ifndef DT_H |
||||||
|
#define DT_H |
||||||
|
|
||||||
|
#define MAXTZLEN 10 |
||||||
|
|
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
|
||||||
|
typedef int32 fsec_t; |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
typedef double fsec_t; |
||||||
|
|
||||||
|
#define TIME_PREC_INV 1000000.0 |
||||||
|
#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef bool |
||||||
|
#define bool char |
||||||
|
#endif /* ndef bool */ |
||||||
|
|
||||||
|
#ifndef FALSE |
||||||
|
#define FALSE 0 |
||||||
|
#endif /* FALSE */ |
||||||
|
|
||||||
|
#ifndef TRUE |
||||||
|
#define TRUE 1 |
||||||
|
#endif /* TRUE */ |
||||||
|
|
||||||
|
#define USE_POSTGRES_DATES 0 |
||||||
|
#define USE_ISO_DATES 1 |
||||||
|
#define USE_SQL_DATES 2 |
||||||
|
#define USE_GERMAN_DATES 3 |
||||||
|
|
||||||
|
#define DAGO "ago" |
||||||
|
#define EPOCH "epoch" |
||||||
|
#define INVALID "invalid" |
||||||
|
#define EARLY "-infinity" |
||||||
|
#define LATE "infinity" |
||||||
|
#define NOW "now" |
||||||
|
#define TODAY "today" |
||||||
|
#define TOMORROW "tomorrow" |
||||||
|
#define YESTERDAY "yesterday" |
||||||
|
#define ZULU "zulu" |
||||||
|
|
||||||
|
#define DMICROSEC "usecond" |
||||||
|
#define DMILLISEC "msecond" |
||||||
|
#define DSECOND "second" |
||||||
|
#define DMINUTE "minute" |
||||||
|
#define DHOUR "hour" |
||||||
|
#define DDAY "day" |
||||||
|
#define DWEEK "week" |
||||||
|
#define DMONTH "month" |
||||||
|
#define DQUARTER "quarter" |
||||||
|
#define DYEAR "year" |
||||||
|
#define DDECADE "decade" |
||||||
|
#define DCENTURY "century" |
||||||
|
#define DMILLENNIUM "millennium" |
||||||
|
#define DA_D "ad" |
||||||
|
#define DB_C "bc" |
||||||
|
#define DTIMEZONE "timezone" |
||||||
|
#define DCURRENT "current" |
||||||
|
|
||||||
|
/*
|
||||||
|
* Fundamental time field definitions for parsing. |
||||||
|
* |
||||||
|
* Meridian: am, pm, or 24-hour style. |
||||||
|
* Millennium: ad, bc |
||||||
|
*/ |
||||||
|
|
||||||
|
#define AM 0 |
||||||
|
#define PM 1 |
||||||
|
#define HR24 2 |
||||||
|
|
||||||
|
#define AD 0 |
||||||
|
#define BC 1 |
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields for time decoding. |
||||||
|
* |
||||||
|
* Can't have more of these than there are bits in an unsigned int |
||||||
|
* since these are turned into bit masks during parsing and decoding. |
||||||
|
* |
||||||
|
* Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND |
||||||
|
* must be in the range 0..14 so that the associated bitmasks can fit |
||||||
|
* into the left half of an INTERVAL's typmod value. |
||||||
|
*/ |
||||||
|
|
||||||
|
#define RESERV 0 |
||||||
|
#define MONTH 1 |
||||||
|
#define YEAR 2 |
||||||
|
#define DAY 3 |
||||||
|
#define JULIAN 4 |
||||||
|
#define TZ 5 |
||||||
|
#define DTZ 6 |
||||||
|
#define DTZMOD 7 |
||||||
|
#define IGNORE_DTF 8 |
||||||
|
#define AMPM 9 |
||||||
|
#define HOUR 10 |
||||||
|
#define MINUTE 11 |
||||||
|
#define SECOND 12 |
||||||
|
#define DOY 13 |
||||||
|
#define DOW 14 |
||||||
|
#define UNITS 15 |
||||||
|
#define ADBC 16 |
||||||
|
/* these are only for relative dates */ |
||||||
|
#define AGO 17 |
||||||
|
#define ABS_BEFORE 18 |
||||||
|
#define ABS_AFTER 19 |
||||||
|
/* generic fields to help with parsing */ |
||||||
|
#define ISODATE 20 |
||||||
|
#define ISOTIME 21 |
||||||
|
/* reserved for unrecognized string values */ |
||||||
|
#define UNKNOWN_FIELD 31 |
||||||
|
|
||||||
|
/*
|
||||||
|
* Token field definitions for time parsing and decoding. |
||||||
|
* These need to fit into the datetkn table type. |
||||||
|
* At the moment, that means keep them within [-127,127]. |
||||||
|
* These are also used for bit masks in DecodeDateDelta() |
||||||
|
* so actually restrict them to within [0,31] for now. |
||||||
|
* - thomas 97/06/19 |
||||||
|
* Not all of these fields are used for masks in DecodeDateDelta |
||||||
|
* so allow some larger than 31. - thomas 1997-11-17 |
||||||
|
*/ |
||||||
|
|
||||||
|
#define DTK_NUMBER 0 |
||||||
|
#define DTK_STRING 1 |
||||||
|
|
||||||
|
#define DTK_DATE 2 |
||||||
|
#define DTK_TIME 3 |
||||||
|
#define DTK_TZ 4 |
||||||
|
#define DTK_AGO 5 |
||||||
|
|
||||||
|
#define DTK_SPECIAL 6 |
||||||
|
#define DTK_INVALID 7 |
||||||
|
#define DTK_CURRENT 8 |
||||||
|
#define DTK_EARLY 9 |
||||||
|
#define DTK_LATE 10 |
||||||
|
#define DTK_EPOCH 11 |
||||||
|
#define DTK_NOW 12 |
||||||
|
#define DTK_YESTERDAY 13 |
||||||
|
#define DTK_TODAY 14 |
||||||
|
#define DTK_TOMORROW 15 |
||||||
|
#define DTK_ZULU 16 |
||||||
|
|
||||||
|
#define DTK_DELTA 17 |
||||||
|
#define DTK_SECOND 18 |
||||||
|
#define DTK_MINUTE 19 |
||||||
|
#define DTK_HOUR 20 |
||||||
|
#define DTK_DAY 21 |
||||||
|
#define DTK_WEEK 22 |
||||||
|
#define DTK_MONTH 23 |
||||||
|
#define DTK_QUARTER 24 |
||||||
|
#define DTK_YEAR 25 |
||||||
|
#define DTK_DECADE 26 |
||||||
|
#define DTK_CENTURY 27 |
||||||
|
#define DTK_MILLENNIUM 28 |
||||||
|
#define DTK_MILLISEC 29 |
||||||
|
#define DTK_MICROSEC 30 |
||||||
|
#define DTK_JULIAN 31 |
||||||
|
|
||||||
|
#define DTK_DOW 32 |
||||||
|
#define DTK_DOY 33 |
||||||
|
#define DTK_TZ_HOUR 34 |
||||||
|
#define DTK_TZ_MINUTE 35 |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit mask definitions for time parsing. |
||||||
|
*/ |
||||||
|
|
||||||
|
#define DTK_M(t) (0x01 << (t)) |
||||||
|
|
||||||
|
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) |
||||||
|
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) |
||||||
|
|
||||||
|
#define MAXDATELEN 51 /* maximum possible length of an input |
||||||
|
* date string (not counting tr. null) */ |
||||||
|
#define MAXDATEFIELDS 25 /* maximum possible number of fields in a |
||||||
|
* date string */ |
||||||
|
#define TOKMAXLEN 10 /* only this many chars are stored in |
||||||
|
* datetktbl */ |
||||||
|
|
||||||
|
/* keep this struct small; it gets used a lot */ |
||||||
|
typedef struct |
||||||
|
{ |
||||||
|
#if defined(_AIX) |
||||||
|
char *token; |
||||||
|
#else |
||||||
|
char token[TOKMAXLEN]; |
||||||
|
#endif /* _AIX */ |
||||||
|
char type; |
||||||
|
char value; /* this may be unsigned, alas */ |
||||||
|
} datetkn; |
||||||
|
|
||||||
|
|
||||||
|
/* TMODULO()
|
||||||
|
* Macro to replace modf(), which is broken on some platforms. |
||||||
|
* t = input and remainder |
||||||
|
* q = integer part |
||||||
|
* u = divisor |
||||||
|
*/ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
#define TMODULO(t,q,u) \ |
||||||
|
do { \
|
||||||
|
q = (t / u); \
|
||||||
|
if (q != 0) t -= (q * u); \
|
||||||
|
} while(0) |
||||||
|
#else |
||||||
|
#define TMODULO(t,q,u) \ |
||||||
|
do { \
|
||||||
|
q = ((t < 0)? ceil(t / u): floor(t / u)); \
|
||||||
|
if (q != 0) t -= rint(q * u); \
|
||||||
|
} while(0) |
||||||
|
#endif |
||||||
|
|
||||||
|
/* Global variable holding time zone information. */ |
||||||
|
#if defined(__CYGWIN__) || defined(N_PLAT_NLM) |
||||||
|
#define TIMEZONE_GLOBAL _timezone |
||||||
|
#else |
||||||
|
#define TIMEZONE_GLOBAL timezone |
||||||
|
#endif |
||||||
|
|
||||||
|
/*
|
||||||
|
* Date/time validation |
||||||
|
* Include check for leap year. |
||||||
|
*/ |
||||||
|
|
||||||
|
extern int day_tab[2][13]; |
||||||
|
|
||||||
|
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) |
||||||
|
|
||||||
|
/* Julian date support for date2j() and j2date()
|
||||||
|
* Set the minimum year to one greater than the year of the first valid day |
||||||
|
* to avoid having to check year and day both. - tgl 97/05/08 |
||||||
|
*/ |
||||||
|
|
||||||
|
#define JULIAN_MINYEAR (-4713) |
||||||
|
#define JULIAN_MINMONTH (11) |
||||||
|
#define JULIAN_MINDAY (24) |
||||||
|
|
||||||
|
#define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \ |
||||||
|
|| (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
|
||||||
|
|| (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY))))) |
||||||
|
|
||||||
|
#define UTIME_MINYEAR (1901) |
||||||
|
#define UTIME_MINMONTH (12) |
||||||
|
#define UTIME_MINDAY (14) |
||||||
|
#define UTIME_MAXYEAR (2038) |
||||||
|
#define UTIME_MAXMONTH (01) |
||||||
|
#define UTIME_MAXDAY (18) |
||||||
|
|
||||||
|
#define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \ |
||||||
|
|| (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \
|
||||||
|
|| (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \
|
||||||
|
&& (((y) < UTIME_MAXYEAR) \
|
||||||
|
|| (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \
|
||||||
|
|| (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY)))))) |
||||||
|
|
||||||
|
#ifdef HUGE_VAL |
||||||
|
#define DT_NOBEGIN (-HUGE_VAL) |
||||||
|
#define DT_NOEND (HUGE_VAL) |
||||||
|
#else |
||||||
|
#define DT_NOBEGIN (-DBL_MAX) |
||||||
|
#define DT_NOEND (DBL_MAX) |
||||||
|
#endif |
||||||
|
|
||||||
|
#define TIMESTAMP_NOBEGIN(j) do {j = DT_NOBEGIN;} while (0) |
||||||
|
#define TIMESTAMP_NOEND(j) do {j = DT_NOEND;} while (0) |
||||||
|
#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) |
||||||
|
#define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND) |
||||||
|
#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) |
||||||
|
|
||||||
|
extern int DecodeTimeOnly(char **field, int *ftype, |
||||||
|
int nf, int *dtype, |
||||||
|
struct tm * tm, fsec_t *fsec, int *tzp); |
||||||
|
|
||||||
|
extern int DecodeInterval(char **field, int *ftype, |
||||||
|
int nf, int *dtype, |
||||||
|
struct tm * tm, fsec_t *fsec); |
||||||
|
|
||||||
|
extern int EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str); |
||||||
|
extern int EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str, bool); |
||||||
|
extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str); |
||||||
|
|
||||||
|
extern int DecodeUnits(int field, char *lowtoken, int *val); |
||||||
|
extern bool ClearDateCache(bool, bool, bool); |
||||||
|
|
||||||
|
extern int j2day(int jd); |
||||||
|
|
||||||
|
extern bool CheckDateTokenTables(void); |
||||||
|
|
||||||
|
extern int EncodeDateOnly(struct tm *, int, char *, bool); |
||||||
|
extern void GetEpochTime(struct tm *); |
||||||
|
extern int ParseDateTime(char *, char *, char **, int *, int, int *, char **); |
||||||
|
extern int DecodeDateTime(char **, int *, int, int *, struct tm *, fsec_t *, int *, bool); |
||||||
|
extern void j2date(int, int *, int *, int *); |
||||||
|
extern int date2j(int, int, int); |
||||||
|
extern double rint(double x); |
||||||
|
|
||||||
|
#endif /* DT_H */ |
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@ |
|||||||
|
#include <string.h> |
||||||
|
|
||||||
|
extern char *pgtypes_alloc(long); |
||||||
|
extern char *pgtypes_strdup(char *); |
@ -0,0 +1,356 @@ |
|||||||
|
#include <math.h> |
||||||
|
#include <time.h> |
||||||
|
#include <string.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <float.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#ifdef __FAST_MATH__ |
||||||
|
#error -ffast-math is known to break this code |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "dt.h" |
||||||
|
#include "extern.h" |
||||||
|
#include "pgtypes_error.h" |
||||||
|
#include "pgtypes_timestamp.h" |
||||||
|
|
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
static int64 |
||||||
|
time2t(const int hour, const int min, const int sec, const fsec_t fsec) |
||||||
|
{ |
||||||
|
return ((((((hour * 60) + min) * 60) + sec) * INT64CONST(1000000)) + fsec); |
||||||
|
} /* time2t() */ |
||||||
|
|
||||||
|
#else |
||||||
|
static double |
||||||
|
time2t(const int hour, const int min, const int sec, const fsec_t fsec) |
||||||
|
{ |
||||||
|
return ((((hour * 60) + min) * 60) + sec + fsec); |
||||||
|
} /* time2t() */ |
||||||
|
#endif |
||||||
|
|
||||||
|
static Timestamp |
||||||
|
dt2local(Timestamp dt, int tz) |
||||||
|
{ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
dt -= (tz * INT64CONST(1000000)); |
||||||
|
#else |
||||||
|
dt -= tz; |
||||||
|
dt = JROUND(dt); |
||||||
|
#endif |
||||||
|
return dt; |
||||||
|
} /* dt2local() */ |
||||||
|
|
||||||
|
/* tm2timestamp()
|
||||||
|
* Convert a tm structure to a timestamp data type. |
||||||
|
* Note that year is _not_ 1900-based, but is an explicit full value. |
||||||
|
* Also, month is one-based, _not_ zero-based. |
||||||
|
*/ |
||||||
|
static int |
||||||
|
tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result) |
||||||
|
{ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
int date; |
||||||
|
int64 time; |
||||||
|
|
||||||
|
#else |
||||||
|
double date, |
||||||
|
time; |
||||||
|
#endif |
||||||
|
|
||||||
|
/* Julian day routines are not correct for negative Julian days */ |
||||||
|
if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday)) |
||||||
|
return -1; |
||||||
|
|
||||||
|
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1); |
||||||
|
time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec); |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
*result = ((date * INT64CONST(86400000000)) + time); |
||||||
|
if ((*result < 0 && date >= 0) || (*result >= 0 && date < 0)) |
||||||
|
elog(ERROR, "TIMESTAMP out of range '%04d-%02d-%02d'", |
||||||
|
tm->tm_year, tm->tm_mon, tm->tm_mday); |
||||||
|
#else |
||||||
|
*result = ((date * 86400) + time); |
||||||
|
#endif |
||||||
|
if (tzp != NULL) |
||||||
|
*result = dt2local(*result, -(*tzp)); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} /* tm2timestamp() */ |
||||||
|
|
||||||
|
static Timestamp |
||||||
|
SetEpochTimestamp(void) |
||||||
|
{ |
||||||
|
Timestamp dt; |
||||||
|
struct tm tt, *tm = &tt; |
||||||
|
|
||||||
|
GetEpochTime(tm); |
||||||
|
tm2timestamp(tm, 0, NULL, &dt); |
||||||
|
return dt; |
||||||
|
} /* SetEpochTimestamp() */ |
||||||
|
|
||||||
|
static void |
||||||
|
dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec) |
||||||
|
{ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
int64 time; |
||||||
|
#else |
||||||
|
double time; |
||||||
|
#endif |
||||||
|
|
||||||
|
time = jd; |
||||||
|
|
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
*hour = (time / INT64CONST(3600000000)); |
||||||
|
time -= ((*hour) * INT64CONST(3600000000)); |
||||||
|
*min = (time / INT64CONST(60000000)); |
||||||
|
time -= ((*min) * INT64CONST(60000000)); |
||||||
|
*sec = (time / INT64CONST(1000000)); |
||||||
|
*fsec = (time - (*sec * INT64CONST(1000000))); |
||||||
|
*sec = (time / INT64CONST(1000000)); |
||||||
|
*fsec = (time - (*sec * INT64CONST(1000000))); |
||||||
|
#else |
||||||
|
*hour = (time / 3600); |
||||||
|
time -= ((*hour) * 3600); |
||||||
|
*min = (time / 60); |
||||||
|
time -= ((*min) * 60); |
||||||
|
*sec = time; |
||||||
|
*fsec = JROUND(time - *sec); |
||||||
|
#endif |
||||||
|
return; |
||||||
|
} /* dt2time() */ |
||||||
|
|
||||||
|
/* timestamp2tm()
|
||||||
|
* Convert timestamp data type to POSIX time structure. |
||||||
|
* Note that year is _not_ 1900-based, but is an explicit full value. |
||||||
|
* Also, month is one-based, _not_ zero-based. |
||||||
|
* Returns: |
||||||
|
* 0 on success |
||||||
|
* -1 on out of range |
||||||
|
* |
||||||
|
* For dates within the system-supported time_t range, convert to the |
||||||
|
* local time zone. If out of this range, leave as GMT. - tgl 97/05/27 |
||||||
|
*/ |
||||||
|
static int |
||||||
|
timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, fsec_t *fsec, char **tzn) |
||||||
|
{ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
int date, |
||||||
|
date0; |
||||||
|
int64 time; |
||||||
|
|
||||||
|
#else |
||||||
|
double date, |
||||||
|
date0; |
||||||
|
double time; |
||||||
|
#endif |
||||||
|
time_t utime; |
||||||
|
|
||||||
|
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) |
||||||
|
struct tm *tx; |
||||||
|
#endif |
||||||
|
|
||||||
|
date0 = date2j(2000, 1, 1); |
||||||
|
|
||||||
|
time = dt; |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
TMODULO(time, date, INT64CONST(86400000000)); |
||||||
|
|
||||||
|
if (time < INT64CONST(0)) |
||||||
|
{ |
||||||
|
time += INT64CONST(86400000000); |
||||||
|
date -= 1; |
||||||
|
} |
||||||
|
#else |
||||||
|
TMODULO(time, date, 86400e0); |
||||||
|
|
||||||
|
if (time < 0) |
||||||
|
{ |
||||||
|
time += 86400; |
||||||
|
date -= 1; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
/* Julian day routine does not work for negative Julian days */ |
||||||
|
if (date < -date0) |
||||||
|
return -1; |
||||||
|
|
||||||
|
/* add offset to go from J2000 back to standard Julian date */ |
||||||
|
date += date0; |
||||||
|
|
||||||
|
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); |
||||||
|
dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); |
||||||
|
|
||||||
|
if (tzp != NULL) |
||||||
|
{ |
||||||
|
/*
|
||||||
|
* Does this fall within the capabilities of the localtime() |
||||||
|
* interface? Then use this to rotate to the local time zone. |
||||||
|
*/ |
||||||
|
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) |
||||||
|
{ |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
utime = ((dt / INT64CONST(1000000)) |
||||||
|
+ ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400))); |
||||||
|
#else |
||||||
|
utime = (dt + ((date0 - date2j(1970, 1, 1)) * 86400)); |
||||||
|
#endif |
||||||
|
|
||||||
|
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE) |
||||||
|
tx = localtime(&utime); |
||||||
|
tm->tm_year = tx->tm_year + 1900; |
||||||
|
tm->tm_mon = tx->tm_mon + 1; |
||||||
|
tm->tm_mday = tx->tm_mday; |
||||||
|
tm->tm_hour = tx->tm_hour; |
||||||
|
tm->tm_min = tx->tm_min; |
||||||
|
tm->tm_isdst = tx->tm_isdst; |
||||||
|
|
||||||
|
#if defined(HAVE_TM_ZONE) |
||||||
|
tm->tm_gmtoff = tx->tm_gmtoff; |
||||||
|
tm->tm_zone = tx->tm_zone; |
||||||
|
|
||||||
|
*tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */ |
||||||
|
if (tzn != NULL) |
||||||
|
*tzn = (char *) tm->tm_zone; |
||||||
|
#elif defined(HAVE_INT_TIMEZONE) |
||||||
|
*tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL); |
||||||
|
if (tzn != NULL) |
||||||
|
*tzn = tzname[(tm->tm_isdst > 0)]; |
||||||
|
#endif |
||||||
|
|
||||||
|
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ |
||||||
|
*tzp = 0; |
||||||
|
/* Mark this as *no* time zone available */ |
||||||
|
tm->tm_isdst = -1; |
||||||
|
if (tzn != NULL) |
||||||
|
*tzn = NULL; |
||||||
|
#endif |
||||||
|
|
||||||
|
dt = dt2local(dt, *tzp); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
*tzp = 0; |
||||||
|
/* Mark this as *no* time zone available */ |
||||||
|
tm->tm_isdst = -1; |
||||||
|
if (tzn != NULL) |
||||||
|
*tzn = NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
tm->tm_isdst = -1; |
||||||
|
if (tzn != NULL) |
||||||
|
*tzn = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} /* timestamp2tm() */ |
||||||
|
|
||||||
|
/* EncodeSpecialTimestamp()
|
||||||
|
* * Convert reserved timestamp data type to string. |
||||||
|
* */ |
||||||
|
static int |
||||||
|
EncodeSpecialTimestamp(Timestamp dt, char *str) |
||||||
|
{ |
||||||
|
if (TIMESTAMP_IS_NOBEGIN(dt)) |
||||||
|
strcpy(str, EARLY); |
||||||
|
else if (TIMESTAMP_IS_NOEND(dt)) |
||||||
|
strcpy(str, LATE); |
||||||
|
else |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
return TRUE; |
||||||
|
} /* EncodeSpecialTimestamp() */ |
||||||
|
|
||||||
|
Timestamp |
||||||
|
PGTYPEStimestamp_atot(char *str, char **endptr) |
||||||
|
{ |
||||||
|
Timestamp result; |
||||||
|
#ifdef HAVE_INT64_TIMESTAMP |
||||||
|
int64 noresult = 0; |
||||||
|
#else |
||||||
|
double noresult = 0.0; |
||||||
|
#endif |
||||||
|
fsec_t fsec; |
||||||
|
struct tm tt, *tm = &tt; |
||||||
|
int tz; |
||||||
|
int dtype; |
||||||
|
int nf; |
||||||
|
char *field[MAXDATEFIELDS]; |
||||||
|
int ftype[MAXDATEFIELDS]; |
||||||
|
char lowstr[MAXDATELEN + MAXDATEFIELDS]; |
||||||
|
char *realptr; |
||||||
|
char **ptr = (endptr != NULL) ? endptr : &realptr; |
||||||
|
|
||||||
|
errno = 0; |
||||||
|
if (strlen(str) >= sizeof(lowstr)) |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return (noresult); |
||||||
|
} |
||||||
|
|
||||||
|
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0) |
||||||
|
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz, 0) != 0)) |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return (noresult); |
||||||
|
} |
||||||
|
|
||||||
|
switch (dtype) |
||||||
|
{ |
||||||
|
case DTK_DATE: |
||||||
|
if (tm2timestamp(tm, fsec, NULL, &result) != 0) |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return (noresult);; |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case DTK_EPOCH: |
||||||
|
result = SetEpochTimestamp(); |
||||||
|
break; |
||||||
|
|
||||||
|
case DTK_LATE: |
||||||
|
TIMESTAMP_NOEND(result); |
||||||
|
break; |
||||||
|
|
||||||
|
case DTK_EARLY: |
||||||
|
TIMESTAMP_NOBEGIN(result); |
||||||
|
break; |
||||||
|
|
||||||
|
case DTK_INVALID: |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return (noresult); |
||||||
|
|
||||||
|
default: |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return (noresult); |
||||||
|
} |
||||||
|
|
||||||
|
/* AdjustTimestampForTypmod(&result, typmod); */ |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
char * |
||||||
|
PGTYPEStimestamp_ttoa(Timestamp tstamp) |
||||||
|
{ |
||||||
|
struct tm tt, *tm = &tt; |
||||||
|
char buf[MAXDATELEN + 1]; |
||||||
|
char *tzn = NULL; |
||||||
|
fsec_t fsec; |
||||||
|
int DateStyle = 0; |
||||||
|
|
||||||
|
if (TIMESTAMP_NOT_FINITE(tstamp)) |
||||||
|
EncodeSpecialTimestamp(tstamp, buf); |
||||||
|
else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0) |
||||||
|
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf, 0); |
||||||
|
else |
||||||
|
{ |
||||||
|
errno = PGTYPES_BAD_TIMESTAMP; |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
return pgtypes_strdup(buf); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,51 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <pgtypes_date.h> |
||||||
|
#include <pgtypes_timestamp.h> |
||||||
|
|
||||||
|
int |
||||||
|
main() |
||||||
|
{ |
||||||
|
exec sql begin declare section; |
||||||
|
date date1; |
||||||
|
timestamp ts1; |
||||||
|
char *text; |
||||||
|
exec sql end declare section; |
||||||
|
#if 0 |
||||||
|
Date date2; |
||||||
|
short int mdy[3] = { 4, 19, 1998 }; |
||||||
|
#endif |
||||||
|
FILE *dbgs; |
||||||
|
|
||||||
|
if ((dbgs = fopen("log", "w")) != NULL) |
||||||
|
ECPGdebug(1, dbgs); |
||||||
|
exec sql whenever sqlerror do sqlprint(); |
||||||
|
exec sql connect to mm; |
||||||
|
exec sql create table date_test (d date, ts timestamp); |
||||||
|
|
||||||
|
exec sql insert into date_test(d, ts) values ('Mon Jan 17 1966', '2000-7-12 17:34:29'); |
||||||
|
|
||||||
|
exec sql select * into :date1, :ts1 from date_test; |
||||||
|
|
||||||
|
text = PGTYPESdate_dtoa(date1); |
||||||
|
printf ("Date: %s\n", text); |
||||||
|
ts1 = PGTYPEStimestamp_atot("2000-7-12 17:34:29", NULL); |
||||||
|
text = PGTYPEStimestamp_ttoa(ts1); |
||||||
|
printf ("timestamp: %s\n", text); |
||||||
|
#if 0 |
||||||
|
PGTYPESdate_mdyjul(mdy, &date2); |
||||||
|
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]); |
||||||
|
/* reset */ |
||||||
|
mdy[0] = mdy[1] = mdy[2] = 0; |
||||||
|
|
||||||
|
PGTYPESdate_julmdy(date2, mdy); |
||||||
|
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]); |
||||||
|
#endif |
||||||
|
exec sql rollback; |
||||||
|
exec sql disconnect; |
||||||
|
|
||||||
|
if (dbgs != NULL) |
||||||
|
fclose(dbgs); |
||||||
|
|
||||||
|
return (0); |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue