diff options
author | drh <> | 2024-03-03 20:15:36 +0000 |
---|---|---|
committer | drh <> | 2024-03-03 20:15:36 +0000 |
commit | aefa7afddbe11afa11aa972fe096d34ec0338ce2 (patch) | |
tree | c6d13164a372ac21910a487ddbfb6f55e6e74635 /src | |
parent | ebc14e409f3c9cd1982aa9bd3e56ab0897924b15 (diff) | |
download | sqlite-aefa7afddbe11afa11aa972fe096d34ec0338ce2.tar.gz sqlite-aefa7afddbe11afa11aa972fe096d34ec0338ce2.zip |
Back out the previous change. Replace it with new date modifiers "ceiling"
and "floor".
FossilOrigin-Name: f0831cced2c919e409214d936c81473ae321a98c5bd78b5b729c1269bf71bc45
Diffstat (limited to 'src')
-rw-r--r-- | src/date.c | 100 |
1 files changed, 75 insertions, 25 deletions
diff --git a/src/date.c b/src/date.c index d4c3afdd3..37bf7fdb4 100644 --- a/src/date.c +++ b/src/date.c @@ -71,13 +71,14 @@ struct DateTime { int tz; /* Timezone offset in minutes */ double s; /* Seconds */ char validJD; /* True (1) if iJD is valid */ - char rawS; /* Raw numeric value stored in s */ 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 tzSet; /* Timezone was set explicitly */ - char isError; /* An overflow has occurred */ - char useSubsec; /* Display subsecond precision */ + 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 */ }; @@ -288,6 +289,29 @@ static void computeJD(DateTime *p){ } /* +** Given the YYYY-MM-DD information current in p, determine if there +** is day-of-month overflow and set nFloor to the number of days that +** would need to be subtracted from the date in order to bring the +** date back to the end of the month. +*/ +static void computeFloor(DateTime *p){ + assert( p->validYMD || p->isError ); + assert( (p->D>=1 && p->D<=31) || p->isError ); + assert( (p->M>=1 && p->M<=12) || p->isError ); + if( p->D<=28 ){ + p->nFloor = 0; + }else if( (1<<p->M) & 0x15aa ){ + p->nFloor = 0; + }else if( p->M!=2 ){ + p->nFloor = (p->D==31); + }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){ + p->nFloor = p->D - 28; + }else{ + p->nFloor = p->D - 29; + } +} + +/* ** Parse dates of the form ** ** YYYY-MM-DD HH:MM:SS.FFF @@ -325,6 +349,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){ p->Y = neg ? -Y : Y; p->M = M; p->D = D; + computeFloor(p); if( p->validTZ ){ computeJD(p); } @@ -635,9 +660,7 @@ static const struct { /* 2 */ { 4, "hour", 1.2897e+11, 3600.0 }, /* 3 */ { 3, "day", 5373485.0, 86400.0 }, /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 }, - /* 5 */ { 4, "mnth", 176546.0, 30.0*86400.0 }, - /* 6 */ { 4, "year", 14713.0, 365.0*86400.0 }, - /* 7 */ { 2, "yr", 14713.0, 365.0*86400.0 }, + /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 }, }; /* @@ -669,14 +692,20 @@ static void autoAdjustDate(DateTime *p){ ** NNN.NNNN seconds ** NNN months ** NNN years +** +/-YYYY-MM-DD HH:MM:SS.SSS +** ceiling +** floor ** start of month ** start of year ** start of week ** start of day ** weekday N ** unixepoch +** auto ** localtime ** utc +** subsec +** subsecond ** ** Return 0 on success and 1 if there is any kind of error. If the error ** is in a system call (i.e. localtime()), then an error message is written @@ -707,6 +736,37 @@ static int parseModifier( } break; } + case 'c': { + /* + ** ceiling + ** + ** Resolve day-of-month overflow by rolling forward into the next + ** month. As this is the default action, this modifier is really + ** a no-op that is only included for symmetry. See "floor". + */ + if( sqlite3_stricmp(z, "ceiling")==0 ){ + computeJD(p); + clearYMD_HMS_TZ(p); + rc = 0; + p->nFloor = 0; + } + break; + } + case 'f': { + /* + ** floor + ** + ** Resolve day-of-month overflow by rolling back to the end of the + ** previous month. + */ + if( sqlite3_stricmp(z, "floor")==0 ){ + computeJD(p); + p->iJD -= p->nFloor*86400000; + clearYMD_HMS_TZ(p); + rc = 0; + } + break; + } case 'j': { /* ** julianday @@ -912,6 +972,7 @@ static int parseModifier( x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; + computeFloor(p); computeJD(p); p->validHMS = 0; p->validYMD = 0; @@ -958,54 +1019,43 @@ static int parseModifier( z += n; while( sqlite3Isspace(*z) ) z++; n = sqlite3Strlen30(z); - if( n>10 || n<2 ) break; + if( n<3 || n>10 ) break; if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; computeJD(p); assert( rc==1 ); rRounder = r<0 ? -0.5 : +0.5; + p->nFloor = 0; 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 ){ - int targetMonth = 0; switch( i ){ - case 4: - case 5: { /* Special processing to add months */ + case 4: { /* Special processing to add months */ assert( strcmp(aXformType[4].zName,"month")==0 ); - assert( strcmp(aXformType[5].zName,"mnth")==0 ); 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; - assert( p->M>=1 && p->M<=12 ); - if( i==5 ) targetMonth = p->M; + computeFloor(p); p->validJD = 0; r -= (int)r; break; } - case 6: - case 7: { /* Special processing to add years */ + case 5: { /* Special processing to add years */ int y = (int)r; - assert( strcmp(aXformType[6].zName,"year")==0 ); - assert( strcmp(aXformType[7].zName,"yr")==0 ); + assert( strcmp(aXformType[5].zName,"year")==0 ); computeYMD_HMS(p); assert( p->M>=1 && p->M<=12 ); - if( i==7 ) targetMonth = p->M; p->Y += y; + computeFloor(p); p->validJD = 0; r -= (int)r; break; } } computeJD(p); - if( targetMonth>0 ){ - p->validYMD = 0; - computeYMD(p); - if( p->M==targetMonth+1 ) p->iJD -= p->D*86400000; - p->validYMD = 0; - } p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder); rc = 0; break; |