mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Simplify the date/time function logic for improved rebustness and also to
decrease the size of the binary. FossilOrigin-Name: 6e144735ed0cd3d4461ae6a4d8034264563e3165
This commit is contained in:
135
src/date.c
135
src/date.c
@@ -414,10 +414,8 @@ static void computeYMD(DateTime *p){
|
||||
p->Y = 2000;
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
}else if( !validJulianDay(p->iJD) ){
|
||||
datetimeError(p);
|
||||
return;
|
||||
}else{
|
||||
assert( validJulianDay(p->iJD) );
|
||||
Z = (int)((p->iJD + 43200000)/86400000);
|
||||
A = (int)((Z - 1867216.25)/36524.25);
|
||||
A = Z + 1 + A - (A/4);
|
||||
@@ -597,6 +595,29 @@ static sqlite3_int64 localtimeOffset(
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LOCALTIME */
|
||||
|
||||
/*
|
||||
** The following table defines various date transformations of the form
|
||||
**
|
||||
** 'NNN days'
|
||||
**
|
||||
** Where NNN is an arbitrary floating-point number and "days" can be one
|
||||
** of several units of time.
|
||||
*/
|
||||
static const struct {
|
||||
u8 eType; /* Transformation type code */
|
||||
u8 nName; /* Length of th name */
|
||||
char *zName; /* Name of the transformation */
|
||||
double rLimit; /* Maximum NNN value for this transform */
|
||||
double rXform; /* Constant used for this transform */
|
||||
} aXformType[] = {
|
||||
{ 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
|
||||
{ 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
|
||||
{ 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
|
||||
{ 0, 3, "day", 5373485.0, 86400000.0 },
|
||||
{ 1, 5, "month", 176546.0, 30.0*86400000.0 },
|
||||
{ 2, 4, "year", 14713.0, 365.0*86400000.0 },
|
||||
};
|
||||
|
||||
/*
|
||||
** Process a modifier to a date-time stamp. The modifiers are
|
||||
** as follows:
|
||||
@@ -621,17 +642,15 @@ static sqlite3_int64 localtimeOffset(
|
||||
** to context pCtx. If the error is an unrecognized modifier, no error is
|
||||
** written to pCtx.
|
||||
*/
|
||||
static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
static int parseModifier(
|
||||
sqlite3_context *pCtx, /* Function context */
|
||||
const char *z, /* The text of the modifier */
|
||||
int n, /* Length of zMod in bytes */
|
||||
DateTime *p /* The date/time value to be modified */
|
||||
){
|
||||
int rc = 1;
|
||||
int n;
|
||||
double r;
|
||||
char *z, zBuf[30];
|
||||
z = zBuf;
|
||||
for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
|
||||
z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
|
||||
}
|
||||
z[n] = 0;
|
||||
switch( z[0] ){
|
||||
switch(sqlite3UpperToLower[(u8)z[0]] ){
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
case 'l': {
|
||||
/* localtime
|
||||
@@ -639,7 +658,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
|
||||
** show local time.
|
||||
*/
|
||||
if( strcmp(z, "localtime")==0 ){
|
||||
if( sqlite3_stricmp(z, "localtime")==0 ){
|
||||
computeJD(p);
|
||||
p->iJD += localtimeOffset(p, pCtx, &rc);
|
||||
clearYMD_HMS_TZ(p);
|
||||
@@ -654,7 +673,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
** Treat the current value of p->s as the number of
|
||||
** seconds since 1970. Convert to a real julian day number.
|
||||
*/
|
||||
if( strcmp(z, "unixepoch")==0 && p->rawS ){
|
||||
if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
|
||||
double r = p->s*1000.0 + 210866760000000.0;
|
||||
if( r>=0.0 && r<464269060800000.0 ){
|
||||
clearYMD_HMS_TZ(p);
|
||||
@@ -665,7 +684,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
else if( strcmp(z, "utc")==0 ){
|
||||
else if( sqlite3_stricmp(z, "utc")==0 ){
|
||||
if( p->tzSet==0 ){
|
||||
sqlite3_int64 c1;
|
||||
computeJD(p);
|
||||
@@ -691,7 +710,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
|
||||
** date is already on the appropriate weekday, this is a no-op.
|
||||
*/
|
||||
if( strncmp(z, "weekday ", 8)==0
|
||||
if( sqlite3_strnicmp(z, "weekday ", 8)==0
|
||||
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
|
||||
&& (n=(int)r)==r && n>=0 && r<7 ){
|
||||
sqlite3_int64 Z;
|
||||
@@ -714,7 +733,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
** Move the date backwards to the beginning of the current day,
|
||||
** or month or year.
|
||||
*/
|
||||
if( strncmp(z, "start of ", 9)!=0 ) break;
|
||||
if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
|
||||
z += 9;
|
||||
computeYMD(p);
|
||||
p->validHMS = 1;
|
||||
@@ -722,15 +741,15 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
p->s = 0.0;
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
if( strcmp(z,"month")==0 ){
|
||||
if( sqlite3_stricmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"year")==0 ){
|
||||
}else if( sqlite3_stricmp(z,"year")==0 ){
|
||||
computeYMD(p);
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( strcmp(z,"day")==0 ){
|
||||
}else if( sqlite3_stricmp(z,"day")==0 ){
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
@@ -748,7 +767,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
case '8':
|
||||
case '9': {
|
||||
double rRounder;
|
||||
double rAbs;
|
||||
int i;
|
||||
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
|
||||
if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
|
||||
rc = 1;
|
||||
@@ -777,47 +796,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If control reaches this point, it means the transformation is
|
||||
** one of the forms like "+NNN days". */
|
||||
z += n;
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
n = sqlite3Strlen30(z);
|
||||
if( n>10 || n<3 ) break;
|
||||
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
|
||||
if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
|
||||
computeJD(p);
|
||||
rc = 0;
|
||||
rc = 1;
|
||||
rRounder = r<0 ? -0.5 : +0.5;
|
||||
rAbs = r<0 ? -r : r;
|
||||
if( n==3 && strcmp(z,"day")==0 && rAbs<5373485.0 ){
|
||||
p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
|
||||
}else if( n==4 && strcmp(z,"hour")==0 && rAbs<128963628.0 ){
|
||||
p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
|
||||
}else if( n==6 && strcmp(z,"minute")==0 && rAbs<7737817680.0 ){
|
||||
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
|
||||
}else if( n==6 && strcmp(z,"second")==0 && rAbs<464269060800.0 ){
|
||||
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
|
||||
}else if( n==5 && strcmp(z,"month")==0 && rAbs<176546.0 ){
|
||||
int x, y;
|
||||
computeYMD_HMS(p);
|
||||
p->M += (int)r;
|
||||
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
||||
p->Y += x;
|
||||
p->M -= x*12;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
y = (int)r;
|
||||
if( y!=r ){
|
||||
p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
|
||||
for(i=0; i<ArraySize(aXformType); i++){
|
||||
if( aXformType[i].nName==n
|
||||
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0
|
||||
&& r>-aXformType[i].rLimit && r<aXformType[i].rLimit
|
||||
){
|
||||
switch( aXformType[i].eType ){
|
||||
case 1: { /* Special processing to add months */
|
||||
int x;
|
||||
computeYMD_HMS(p);
|
||||
p->M += (int)r;
|
||||
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
||||
p->Y += x;
|
||||
p->M -= x*12;
|
||||
p->validJD = 0;
|
||||
r -= (int)r;
|
||||
break;
|
||||
}
|
||||
case 2: { /* Special processing to add years */
|
||||
int y = (int)r;
|
||||
computeYMD_HMS(p);
|
||||
p->Y += y;
|
||||
p->validJD = 0;
|
||||
r -= (int)r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
computeJD(p);
|
||||
p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}else if( n==4 && strcmp(z,"year")==0 && rAbs<14713.0 ){
|
||||
int y = (int)r;
|
||||
computeYMD_HMS(p);
|
||||
p->Y += y;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
if( y!=r ){
|
||||
p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
|
||||
}
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
clearYMD_HMS_TZ(p);
|
||||
break;
|
||||
@@ -844,7 +864,7 @@ static int isDate(
|
||||
sqlite3_value **argv,
|
||||
DateTime *p
|
||||
){
|
||||
int i;
|
||||
int i, n;
|
||||
const unsigned char *z;
|
||||
int eType;
|
||||
memset(p, 0, sizeof(*p));
|
||||
@@ -862,7 +882,8 @@ static int isDate(
|
||||
}
|
||||
for(i=1; i<argc; i++){
|
||||
z = sqlite3_value_text(argv[i]);
|
||||
if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
|
||||
n = sqlite3_value_bytes(argv[i]);
|
||||
if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
|
||||
}
|
||||
computeJD(p);
|
||||
if( p->isError || !validJulianDay(p->iJD) ) return 1;
|
||||
|
Reference in New Issue
Block a user