mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +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:
12
manifest
12
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Extend\sthe\svalid\srange\sof\s'unixepoch'\sdates\sfrom\sJulianDay\s0\sthrough\s9999-12-31.
|
C Simplify\sthe\sdate/time\sfunction\slogic\sfor\simproved\srebustness\sand\salso\sto\ndecrease\sthe\ssize\sof\sthe\sbinary.
|
||||||
D 2016-12-02T17:08:27.447
|
D 2016-12-02T19:07:03.138
|
||||||
F Makefile.in 7639c6a09da11a9c7c6f2630fc981ee588d1072d
|
F Makefile.in 7639c6a09da11a9c7c6f2630fc981ee588d1072d
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
|
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
|
||||||
@@ -338,7 +338,7 @@ F src/build.c 178f16698cbcb43402c343a9413fe22c99ffee21
|
|||||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||||
F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
|
F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
|
||||||
F src/date.c 58d4275a8778c2da80fcb515e2605c791a2b8884
|
F src/date.c 116097946bffdfe510b30affa15b36026f632ae6
|
||||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||||
F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495
|
F src/delete.c cac97d1117a3008934da3a6a587b3608e65e1495
|
||||||
F src/expr.c b22e09630f874c52db0770973b7ce55ee50c1dde
|
F src/expr.c b22e09630f874c52db0770973b7ce55ee50c1dde
|
||||||
@@ -1536,7 +1536,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 0bdb7ae126d3909344640813489ee68ecad041c4
|
P 768c9859b21a3c88be084d6dd87acab4211b3a87
|
||||||
R de507b0b0d00b8f392dd9c1b935d5409
|
R 65ce4f7c2b4b3fd05ab801cab333052f
|
||||||
U drh
|
U drh
|
||||||
Z 8b7f9d120e42b1682165e88e877e78a0
|
Z 0e9aea10c8c8bd36917285b40426a93d
|
||||||
|
@@ -1 +1 @@
|
|||||||
768c9859b21a3c88be084d6dd87acab4211b3a87
|
6e144735ed0cd3d4461ae6a4d8034264563e3165
|
135
src/date.c
135
src/date.c
@@ -414,10 +414,8 @@ static void computeYMD(DateTime *p){
|
|||||||
p->Y = 2000;
|
p->Y = 2000;
|
||||||
p->M = 1;
|
p->M = 1;
|
||||||
p->D = 1;
|
p->D = 1;
|
||||||
}else if( !validJulianDay(p->iJD) ){
|
|
||||||
datetimeError(p);
|
|
||||||
return;
|
|
||||||
}else{
|
}else{
|
||||||
|
assert( validJulianDay(p->iJD) );
|
||||||
Z = (int)((p->iJD + 43200000)/86400000);
|
Z = (int)((p->iJD + 43200000)/86400000);
|
||||||
A = (int)((Z - 1867216.25)/36524.25);
|
A = (int)((Z - 1867216.25)/36524.25);
|
||||||
A = Z + 1 + A - (A/4);
|
A = Z + 1 + A - (A/4);
|
||||||
@@ -597,6 +595,29 @@ static sqlite3_int64 localtimeOffset(
|
|||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_LOCALTIME */
|
#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
|
** Process a modifier to a date-time stamp. The modifiers are
|
||||||
** as follows:
|
** as follows:
|
||||||
@@ -621,17 +642,15 @@ static sqlite3_int64 localtimeOffset(
|
|||||||
** to context pCtx. If the error is an unrecognized modifier, no error is
|
** to context pCtx. If the error is an unrecognized modifier, no error is
|
||||||
** written to pCtx.
|
** 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 rc = 1;
|
||||||
int n;
|
|
||||||
double r;
|
double r;
|
||||||
char *z, zBuf[30];
|
switch(sqlite3UpperToLower[(u8)z[0]] ){
|
||||||
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] ){
|
|
||||||
#ifndef SQLITE_OMIT_LOCALTIME
|
#ifndef SQLITE_OMIT_LOCALTIME
|
||||||
case 'l': {
|
case 'l': {
|
||||||
/* localtime
|
/* 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
|
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
|
||||||
** show local time.
|
** show local time.
|
||||||
*/
|
*/
|
||||||
if( strcmp(z, "localtime")==0 ){
|
if( sqlite3_stricmp(z, "localtime")==0 ){
|
||||||
computeJD(p);
|
computeJD(p);
|
||||||
p->iJD += localtimeOffset(p, pCtx, &rc);
|
p->iJD += localtimeOffset(p, pCtx, &rc);
|
||||||
clearYMD_HMS_TZ(p);
|
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
|
** Treat the current value of p->s as the number of
|
||||||
** seconds since 1970. Convert to a real julian day number.
|
** 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;
|
double r = p->s*1000.0 + 210866760000000.0;
|
||||||
if( r>=0.0 && r<464269060800000.0 ){
|
if( r>=0.0 && r<464269060800000.0 ){
|
||||||
clearYMD_HMS_TZ(p);
|
clearYMD_HMS_TZ(p);
|
||||||
@@ -665,7 +684,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_LOCALTIME
|
#ifndef SQLITE_OMIT_LOCALTIME
|
||||||
else if( strcmp(z, "utc")==0 ){
|
else if( sqlite3_stricmp(z, "utc")==0 ){
|
||||||
if( p->tzSet==0 ){
|
if( p->tzSet==0 ){
|
||||||
sqlite3_int64 c1;
|
sqlite3_int64 c1;
|
||||||
computeJD(p);
|
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
|
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
|
||||||
** date is already on the appropriate weekday, this is a no-op.
|
** 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)
|
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
|
||||||
&& (n=(int)r)==r && n>=0 && r<7 ){
|
&& (n=(int)r)==r && n>=0 && r<7 ){
|
||||||
sqlite3_int64 Z;
|
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,
|
** Move the date backwards to the beginning of the current day,
|
||||||
** or month or year.
|
** or month or year.
|
||||||
*/
|
*/
|
||||||
if( strncmp(z, "start of ", 9)!=0 ) break;
|
if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
|
||||||
z += 9;
|
z += 9;
|
||||||
computeYMD(p);
|
computeYMD(p);
|
||||||
p->validHMS = 1;
|
p->validHMS = 1;
|
||||||
@@ -722,15 +741,15 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
|||||||
p->s = 0.0;
|
p->s = 0.0;
|
||||||
p->validTZ = 0;
|
p->validTZ = 0;
|
||||||
p->validJD = 0;
|
p->validJD = 0;
|
||||||
if( strcmp(z,"month")==0 ){
|
if( sqlite3_stricmp(z,"month")==0 ){
|
||||||
p->D = 1;
|
p->D = 1;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}else if( strcmp(z,"year")==0 ){
|
}else if( sqlite3_stricmp(z,"year")==0 ){
|
||||||
computeYMD(p);
|
computeYMD(p);
|
||||||
p->M = 1;
|
p->M = 1;
|
||||||
p->D = 1;
|
p->D = 1;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}else if( strcmp(z,"day")==0 ){
|
}else if( sqlite3_stricmp(z,"day")==0 ){
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -748,7 +767,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
|||||||
case '8':
|
case '8':
|
||||||
case '9': {
|
case '9': {
|
||||||
double rRounder;
|
double rRounder;
|
||||||
double rAbs;
|
int i;
|
||||||
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
|
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
|
||||||
if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
|
if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
|
||||||
rc = 1;
|
rc = 1;
|
||||||
@@ -777,47 +796,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If control reaches this point, it means the transformation is
|
||||||
|
** one of the forms like "+NNN days". */
|
||||||
z += n;
|
z += n;
|
||||||
while( sqlite3Isspace(*z) ) z++;
|
while( sqlite3Isspace(*z) ) z++;
|
||||||
n = sqlite3Strlen30(z);
|
n = sqlite3Strlen30(z);
|
||||||
if( n>10 || n<3 ) break;
|
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);
|
computeJD(p);
|
||||||
rc = 0;
|
rc = 1;
|
||||||
rRounder = r<0 ? -0.5 : +0.5;
|
rRounder = r<0 ? -0.5 : +0.5;
|
||||||
rAbs = r<0 ? -r : r;
|
for(i=0; i<ArraySize(aXformType); i++){
|
||||||
if( n==3 && strcmp(z,"day")==0 && rAbs<5373485.0 ){
|
if( aXformType[i].nName==n
|
||||||
p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
|
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0
|
||||||
}else if( n==4 && strcmp(z,"hour")==0 && rAbs<128963628.0 ){
|
&& r>-aXformType[i].rLimit && r<aXformType[i].rLimit
|
||||||
p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
|
){
|
||||||
}else if( n==6 && strcmp(z,"minute")==0 && rAbs<7737817680.0 ){
|
switch( aXformType[i].eType ){
|
||||||
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
|
case 1: { /* Special processing to add months */
|
||||||
}else if( n==6 && strcmp(z,"second")==0 && rAbs<464269060800.0 ){
|
int x;
|
||||||
p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
|
computeYMD_HMS(p);
|
||||||
}else if( n==5 && strcmp(z,"month")==0 && rAbs<176546.0 ){
|
p->M += (int)r;
|
||||||
int x, y;
|
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
||||||
computeYMD_HMS(p);
|
p->Y += x;
|
||||||
p->M += (int)r;
|
p->M -= x*12;
|
||||||
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
p->validJD = 0;
|
||||||
p->Y += x;
|
r -= (int)r;
|
||||||
p->M -= x*12;
|
break;
|
||||||
p->validJD = 0;
|
}
|
||||||
computeJD(p);
|
case 2: { /* Special processing to add years */
|
||||||
y = (int)r;
|
int y = (int)r;
|
||||||
if( y!=r ){
|
computeYMD_HMS(p);
|
||||||
p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
|
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);
|
clearYMD_HMS_TZ(p);
|
||||||
break;
|
break;
|
||||||
@@ -844,7 +864,7 @@ static int isDate(
|
|||||||
sqlite3_value **argv,
|
sqlite3_value **argv,
|
||||||
DateTime *p
|
DateTime *p
|
||||||
){
|
){
|
||||||
int i;
|
int i, n;
|
||||||
const unsigned char *z;
|
const unsigned char *z;
|
||||||
int eType;
|
int eType;
|
||||||
memset(p, 0, sizeof(*p));
|
memset(p, 0, sizeof(*p));
|
||||||
@@ -862,7 +882,8 @@ static int isDate(
|
|||||||
}
|
}
|
||||||
for(i=1; i<argc; i++){
|
for(i=1; i<argc; i++){
|
||||||
z = sqlite3_value_text(argv[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);
|
computeJD(p);
|
||||||
if( p->isError || !validJulianDay(p->iJD) ) return 1;
|
if( p->isError || !validJulianDay(p->iJD) ) return 1;
|
||||||
|
Reference in New Issue
Block a user