summaryrefslogtreecommitdiff
path: root/ext/sqlite/libsqlite/src/date.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/sqlite/libsqlite/src/date.c')
-rw-r--r--ext/sqlite/libsqlite/src/date.c230
1 files changed, 129 insertions, 101 deletions
diff --git a/ext/sqlite/libsqlite/src/date.c b/ext/sqlite/libsqlite/src/date.c
index 64fc3bccdf..d7382aefae 100644
--- a/ext/sqlite/libsqlite/src/date.c
+++ b/ext/sqlite/libsqlite/src/date.c
@@ -47,7 +47,6 @@
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
-#ifndef SQLITE_OMIT_DATETIME_FUNCS
#include "os.h"
#include "sqliteInt.h"
#include <ctype.h>
@@ -55,6 +54,8 @@
#include <assert.h>
#include <time.h>
+#ifndef SQLITE_OMIT_DATETIME_FUNCS
+
/*
** A structure for holding a single date and time.
*/
@@ -73,17 +74,50 @@ struct DateTime {
/*
-** Convert N digits from zDate into an integer. Return
-** -1 if zDate does not begin with N digits.
+** Convert zDate into one or more integers. Additional arguments
+** come in groups of 5 as follows:
+**
+** N number of digits in the integer
+** min minimum allowed value of the integer
+** max maximum allowed value of the integer
+** nextC first character after the integer
+** pVal where to write the integers value.
+**
+** Conversions continue until one with nextC==0 is encountered.
+** The function returns the number of successful conversions.
*/
-static int getDigits(const char *zDate, int N){
- int val = 0;
- while( N-- ){
- if( !isdigit(*zDate) ) return -1;
- val = val*10 + *zDate - '0';
+static int getDigits(const char *zDate, ...){
+ va_list ap;
+ int val;
+ int N;
+ int min;
+ int max;
+ int nextC;
+ int *pVal;
+ int cnt = 0;
+ va_start(ap, zDate);
+ do{
+ N = va_arg(ap, int);
+ min = va_arg(ap, int);
+ max = va_arg(ap, int);
+ nextC = va_arg(ap, int);
+ pVal = va_arg(ap, int*);
+ val = 0;
+ while( N-- ){
+ if( !isdigit(*zDate) ){
+ return cnt;
+ }
+ val = val*10 + *zDate - '0';
+ zDate++;
+ }
+ if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
+ return cnt;
+ }
+ *pVal = val;
zDate++;
- }
- return val;
+ cnt++;
+ }while( nextC );
+ return cnt;
}
/*
@@ -91,38 +125,9 @@ static int getDigits(const char *zDate, int N){
** the number of digits converted.
*/
static int getValue(const char *z, double *pR){
- double r = 0.0;
- double rDivide = 1.0;
- int isNeg = 0;
- int nChar = 0;
- if( *z=='+' ){
- z++;
- nChar++;
- }else if( *z=='-' ){
- z++;
- isNeg = 1;
- nChar++;
- }
- if( !isdigit(*z) ) return 0;
- while( isdigit(*z) ){
- r = r*10.0 + *z - '0';
- nChar++;
- z++;
- }
- if( *z=='.' && isdigit(z[1]) ){
- z++;
- nChar++;
- while( isdigit(*z) ){
- r = r*10.0 + *z - '0';
- rDivide *= 10.0;
- nChar++;
- z++;
- }
- r /= rDivide;
- }
- if( *z!=0 && !isspace(*z) ) return 0;
- *pR = isNeg ? -r : r;
- return nChar;
+ const char *zEnd;
+ *pR = sqliteAtoF(z, &zEnd);
+ return zEnd - z;
}
/*
@@ -150,14 +155,10 @@ static int parseTimezone(const char *zDate, DateTime *p){
return *zDate!=0;
}
zDate++;
- nHr = getDigits(zDate, 2);
- if( nHr<0 || nHr>14 ) return 1;
- zDate += 2;
- if( zDate[0]!=':' ) return 1;
- zDate++;
- nMn = getDigits(zDate, 2);
- if( nMn<0 || nMn>59 ) return 1;
- zDate += 2;
+ if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
+ return 1;
+ }
+ zDate += 5;
p->tz = sgn*(nMn + nHr*60);
while( isspace(*zDate) ){ zDate++; }
return *zDate!=0;
@@ -173,16 +174,16 @@ static int parseTimezone(const char *zDate, DateTime *p){
static int parseHhMmSs(const char *zDate, DateTime *p){
int h, m, s;
double ms = 0.0;
- h = getDigits(zDate, 2);
- if( h<0 || zDate[2]!=':' ) return 1;
- zDate += 3;
- m = getDigits(zDate, 2);
- if( m<0 || m>59 ) return 1;
- zDate += 2;
+ if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
+ return 1;
+ }
+ zDate += 5;
if( *zDate==':' ){
- s = getDigits(&zDate[1], 2);
- if( s<0 || s>59 ) return 1;
- zDate += 3;
+ zDate++;
+ if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
+ return 1;
+ }
+ zDate += 2;
if( *zDate=='.' && isdigit(zDate[1]) ){
double rScale = 1.0;
zDate++;
@@ -259,20 +260,21 @@ static void computeJD(DateTime *p){
** date.
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
- int Y, M, D;
+ int Y, M, D, neg;
- Y = getDigits(zDate, 4);
- if( Y<0 || zDate[4]!='-' ) return 1;
- zDate += 5;
- M = getDigits(zDate, 2);
- if( M<=0 || M>12 || zDate[2]!='-' ) return 1;
- zDate += 3;
- D = getDigits(zDate, 2);
- if( D<=0 || D>31 ) return 1;
- zDate += 2;
+ if( zDate[0]=='-' ){
+ zDate++;
+ neg = 1;
+ }else{
+ neg = 0;
+ }
+ if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
+ return 1;
+ }
+ zDate += 10;
while( isspace(*zDate) ){ zDate++; }
- if( isdigit(*zDate) ){
- if( parseHhMmSs(zDate, p) ) return 1;
+ if( parseHhMmSs(zDate, p)==0 ){
+ /* We got the time */
}else if( *zDate==0 ){
p->validHMS = 0;
}else{
@@ -280,7 +282,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
}
p->validJD = 0;
p->validYMD = 1;
- p->Y = Y;
+ p->Y = neg ? -Y : Y;
p->M = M;
p->D = D;
if( p->validTZ ){
@@ -306,15 +308,12 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** as there is a year and date.
*/
static int parseDateOrTime(const char *zDate, DateTime *p){
- int i;
memset(p, 0, sizeof(*p));
- for(i=0; isdigit(zDate[i]); i++){}
- if( i==4 && zDate[i]=='-' ){
- return parseYyyyMmDd(zDate, p);
- }else if( i==2 && zDate[i]==':' ){
- return parseHhMmSs(zDate, p);
+ if( parseYyyyMmDd(zDate,p)==0 ){
+ return 0;
+ }else if( parseHhMmSs(zDate, p)==0 ){
return 0;
- }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){
+ }else if( sqliteStrICmp(zDate,"now")==0){
double r;
if( sqliteOsCurrentTime(&r)==0 ){
p->rJD = r;
@@ -323,7 +322,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
}
return 1;
}else if( sqliteIsNumber(zDate) ){
- p->rJD = sqliteAtoF(zDate);
+ p->rJD = sqliteAtoF(zDate, 0);
p->validJD = 1;
return 0;
}
@@ -336,17 +335,23 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
static void computeYMD(DateTime *p){
int Z, A, B, C, D, E, X1;
if( p->validYMD ) return;
- Z = p->rJD + 0.5;
- A = (Z - 1867216.25)/36524.25;
- A = Z + 1 + A - (A/4);
- B = A + 1524;
- C = (B - 122.1)/365.25;
- D = 365.25*C;
- E = (B-D)/30.6001;
- X1 = 30.6001*E;
- p->D = B - D - X1;
- p->M = E<14 ? E-1 : E-13;
- p->Y = p->M>2 ? C - 4716 : C - 4715;
+ if( !p->validJD ){
+ p->Y = 2000;
+ p->M = 1;
+ p->D = 1;
+ }else{
+ Z = p->rJD + 0.5;
+ A = (Z - 1867216.25)/36524.25;
+ A = Z + 1 + A - (A/4);
+ B = A + 1524;
+ C = (B - 122.1)/365.25;
+ D = 365.25*C;
+ E = (B-D)/30.6001;
+ X1 = 30.6001*E;
+ p->D = B - D - X1;
+ p->M = E<14 ? E-1 : E-13;
+ p->Y = p->M>2 ? C - 4716 : C - 4715;
+ }
p->validYMD = 1;
}
@@ -452,8 +457,9 @@ static int parseModifier(const char *zMod, DateTime *p){
int rc = 1;
int n;
double r;
- char z[30];
- for(n=0; n<sizeof(z)-1 && zMod[n]; n++){
+ char *z, zBuf[30];
+ z = zBuf;
+ for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
z[n] = tolower(zMod[n]);
}
z[n] = 0;
@@ -526,22 +532,22 @@ static int parseModifier(const char *zMod, DateTime *p){
** or month or year.
*/
if( strncmp(z, "start of ", 9)!=0 ) break;
- zMod = &z[9];
+ z += 9;
computeYMD(p);
p->validHMS = 1;
p->h = p->m = 0;
p->s = 0.0;
p->validTZ = 0;
p->validJD = 0;
- if( strcmp(zMod,"month")==0 ){
+ if( strcmp(z,"month")==0 ){
p->D = 1;
rc = 0;
- }else if( strcmp(zMod,"year")==0 ){
+ }else if( strcmp(z,"year")==0 ){
computeYMD(p);
p->M = 1;
p->D = 1;
rc = 0;
- }else if( strcmp(zMod,"day")==0 ){
+ }else if( strcmp(z,"day")==0 ){
rc = 0;
}
break;
@@ -560,11 +566,33 @@ static int parseModifier(const char *zMod, DateTime *p){
case '9': {
n = getValue(z, &r);
if( n<=0 ) break;
- zMod = &z[n];
- while( isspace(zMod[0]) ) zMod++;
- n = strlen(zMod);
+ if( z[n]==':' ){
+ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
+ ** specified number of hours, minutes, seconds, and fractional seconds
+ ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
+ ** omitted.
+ */
+ const char *z2 = z;
+ DateTime tx;
+ int day;
+ if( !isdigit(*z2) ) z2++;
+ memset(&tx, 0, sizeof(tx));
+ if( parseHhMmSs(z2, &tx) ) break;
+ computeJD(&tx);
+ tx.rJD -= 0.5;
+ day = (int)tx.rJD;
+ tx.rJD -= day;
+ if( z[0]=='-' ) tx.rJD = -tx.rJD;
+ computeJD(p);
+ clearYMD_HMS_TZ(p);
+ p->rJD += tx.rJD;
+ rc = 0;
+ break;
+ }
+ z += n;
+ while( isspace(z[0]) ) z++;
+ n = strlen(z);
if( n>10 || n<3 ) break;
- strcpy(z, zMod);
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
computeJD(p);
rc = 0;