mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Adjust date/time functions so that they do a better job of keeping track
of whether the current time is UTC or localtime, and no-op the 'utc' and 'localtime' modifiers accordingly. See [forum:/info/e7a939e074|forum post e7a939e074]. Also add the datedebug() function, available only under -DSQLITE_DEBUG, for improved visibility of the DateTime object during debugging and testing. FossilOrigin-Name: dc569683748354a6db83438904422e802d3ea780775c48da85b474fff03ca8a1
This commit is contained in:
78
src/date.c
78
src/date.c
@@ -73,12 +73,12 @@ struct DateTime {
|
||||
char validJD; /* True (1) if iJD is valid */
|
||||
char validYMD; /* True (1) if Y,M,D are valid */
|
||||
char validHMS; /* True (1) if h,m,s are valid */
|
||||
char validTZ; /* True (1) if tz is valid */
|
||||
char nFloor; /* Days to implement "floor" */
|
||||
unsigned rawS : 1; /* Raw numeric value stored in s */
|
||||
unsigned tzSet : 1; /* Timezone was set explicitly */
|
||||
unsigned isError : 1; /* An overflow has occurred */
|
||||
unsigned useSubsec : 1; /* Display subsecond precision */
|
||||
unsigned isUtc : 1; /* Time is known to be UTC */
|
||||
unsigned isLocal : 1; /* Time is known to be localtime */
|
||||
};
|
||||
|
||||
|
||||
@@ -176,6 +176,8 @@ static int parseTimezone(const char *zDate, DateTime *p){
|
||||
sgn = +1;
|
||||
}else if( c=='Z' || c=='z' ){
|
||||
zDate++;
|
||||
p->isLocal = 0;
|
||||
p->isUtc = 1;
|
||||
goto zulu_time;
|
||||
}else{
|
||||
return c!=0;
|
||||
@@ -188,7 +190,6 @@ static int parseTimezone(const char *zDate, DateTime *p){
|
||||
p->tz = sgn*(nMn + nHr*60);
|
||||
zulu_time:
|
||||
while( sqlite3Isspace(*zDate) ){ zDate++; }
|
||||
p->tzSet = 1;
|
||||
return *zDate!=0;
|
||||
}
|
||||
|
||||
@@ -232,7 +233,6 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
|
||||
p->m = m;
|
||||
p->s = s + ms;
|
||||
if( parseTimezone(zDate, p) ) return 1;
|
||||
p->validTZ = (p->tz!=0)?1:0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,11 +279,13 @@ static void computeJD(DateTime *p){
|
||||
p->validJD = 1;
|
||||
if( p->validHMS ){
|
||||
p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
|
||||
if( p->validTZ ){
|
||||
if( p->tz ){
|
||||
p->iJD -= p->tz*60000;
|
||||
p->validYMD = 0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
p->tz = 0;
|
||||
p->isUtc = 1;
|
||||
p->isLocal = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,11 +352,14 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
|
||||
p->M = M;
|
||||
p->D = D;
|
||||
computeFloor(p);
|
||||
if( p->validTZ ){
|
||||
if( p->tz ){
|
||||
computeJD(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */
|
||||
|
||||
/*
|
||||
** Set the time to the current time reported by the VFS.
|
||||
@@ -365,6 +370,9 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
|
||||
p->iJD = sqlite3StmtCurrentTime(context);
|
||||
if( p->iJD>0 ){
|
||||
p->validJD = 1;
|
||||
p->isUtc = 1;
|
||||
p->isLocal = 0;
|
||||
clearYMD_HMS_TZ(p);
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
@@ -503,7 +511,7 @@ static void computeYMD_HMS(DateTime *p){
|
||||
static void clearYMD_HMS_TZ(DateTime *p){
|
||||
p->validYMD = 0;
|
||||
p->validHMS = 0;
|
||||
p->validTZ = 0;
|
||||
p->tz = 0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
@@ -635,7 +643,7 @@ static int toLocaltime(
|
||||
p->validHMS = 1;
|
||||
p->validJD = 0;
|
||||
p->rawS = 0;
|
||||
p->validTZ = 0;
|
||||
p->tz = 0;
|
||||
p->isError = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -793,7 +801,9 @@ static int parseModifier(
|
||||
** show local time.
|
||||
*/
|
||||
if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
|
||||
rc = toLocaltime(p, pCtx);
|
||||
rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
|
||||
p->isUtc = 0;
|
||||
p->isLocal = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -818,7 +828,7 @@ static int parseModifier(
|
||||
}
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
|
||||
if( p->tzSet==0 ){
|
||||
if( p->isUtc==0 ){
|
||||
i64 iOrigJD; /* Original localtime */
|
||||
i64 iGuess; /* Guess at the corresponding utc time */
|
||||
int cnt = 0; /* Safety to prevent infinite loop */
|
||||
@@ -841,7 +851,8 @@ static int parseModifier(
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->iJD = iGuess;
|
||||
p->validJD = 1;
|
||||
p->tzSet = 1;
|
||||
p->isUtc = 1;
|
||||
p->isLocal = 0;
|
||||
}
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
@@ -861,7 +872,7 @@ static int parseModifier(
|
||||
&& r>=0.0 && r<7.0 && (n=(int)r)==r ){
|
||||
sqlite3_int64 Z;
|
||||
computeYMD_HMS(p);
|
||||
p->validTZ = 0;
|
||||
p->tz = 0;
|
||||
p->validJD = 0;
|
||||
computeJD(p);
|
||||
Z = ((p->iJD + 129600000)/86400000) % 7;
|
||||
@@ -901,7 +912,7 @@ static int parseModifier(
|
||||
p->h = p->m = 0;
|
||||
p->s = 0.0;
|
||||
p->rawS = 0;
|
||||
p->validTZ = 0;
|
||||
p->tz = 0;
|
||||
p->validJD = 0;
|
||||
if( sqlite3_stricmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
@@ -1674,9 +1685,7 @@ static void timediffFunc(
|
||||
d1.iJD = d2.iJD - d1.iJD;
|
||||
d1.iJD += (u64)1486995408 * (u64)100000;
|
||||
}
|
||||
d1.validYMD = 0;
|
||||
d1.validHMS = 0;
|
||||
d1.validTZ = 0;
|
||||
clearYMD_HMS_TZ(&d1);
|
||||
computeYMD_HMS(&d1);
|
||||
sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
|
||||
sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
|
||||
@@ -1745,6 +1754,36 @@ static void currentTimeFunc(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** datedebug(...)
|
||||
**
|
||||
** This routine returns JSON that describes the internal DateTime object.
|
||||
** Used for debugging and testing only. Subject to change.
|
||||
*/
|
||||
static void datedebugFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
DateTime x;
|
||||
if( isDate(context, argc, argv, &x)==0 ){
|
||||
char *zJson;
|
||||
zJson = sqlite3_mprintf(
|
||||
"{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d,"
|
||||
"s:%.3f,validJD:%d,validYMS:%d,validHMS:%d,"
|
||||
"nFloor:%d,rawS:%d,isError:%d,useSubsec:%d,"
|
||||
"isUtc:%d,isLocal:%d}",
|
||||
x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz,
|
||||
x.s, x.validJD, x.validYMD, x.validHMS,
|
||||
x.nFloor, x.rawS, x.isError, x.useSubsec,
|
||||
x.isUtc, x.isLocal);
|
||||
sqlite3_result_text(context, zJson, -1, sqlite3_free);
|
||||
}
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */
|
||||
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
@@ -1760,6 +1799,9 @@ void sqlite3RegisterDateTimeFunctions(void){
|
||||
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
|
||||
PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
|
||||
PURE_DATE(timediff, 2, 0, 0, timediffFunc ),
|
||||
#ifdef SQLITE_DEBUG
|
||||
PURE_DATE(datedebug, -1, 0, 0, datedebugFunc ),
|
||||
#endif
|
||||
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
|
||||
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
|
||||
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
|
||||
|
Reference in New Issue
Block a user