]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Back out the previous change. Replace it with new date modifiers "ceiling"
authordrh <>
Sun, 3 Mar 2024 20:15:36 +0000 (20:15 +0000)
committerdrh <>
Sun, 3 Mar 2024 20:15:36 +0000 (20:15 +0000)
and "floor".

FossilOrigin-Name: f0831cced2c919e409214d936c81473ae321a98c5bd78b5b729c1269bf71bc45

manifest
manifest.uuid
src/date.c
test/date.test

index 8e0dc8a6674e17cc6b67d7d3cef7e495cb9d021a..69581e9a5b1db562ac765bfd767a61061cae3292 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C New\sdate/time\smodifiers\s"mnth"\sand\s"yr"\swork\slike\s"month"\sand\s"year"\sbut\nresolve\sday-of-month\soverflow\sby\struncating\srather\sthan\srolling\sover\sinto\nthe\snext\smonth.\s[forum:/forumpost/232d1abb5d|Forum\sthread\s232d1abb5d]
-D 2024-03-02T21:02:41.160
+C Back\sout\sthe\sprevious\schange.\s\sReplace\sit\swith\snew\sdate\smodifiers\s"ceiling"\nand\s"floor".
+D 2024-03-03T20:15:36.398
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -696,7 +696,7 @@ F src/build.c 04f1bcee189f045ab086d84fee95db42cb49df82ff8e84af8136309ff3c8a75f
 F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
-F src/date.c 89083264f1832e2bb892d6b313a6c642a5cd730cfcc89574019aa06c69192dcd
+F src/date.c b36a3cc75ac691bf72b4759130b04ac2926af6fd4ca98df3400ff20d34a15878
 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
@@ -1042,7 +1042,7 @@ F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c47
 F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270
 F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
 F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
-F test/date.test 9583b421058d8366a06d4a07135ced29b64e31b5e7dafd03a2040bf84ef69adb
+F test/date.test 99bfd3a77a3f9ae54eebd374a4301af960f2b2e9a581cf63e26445bae830a435
 F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
 F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
 F test/date4.test 75dc8401e8c0639a228cd26a6eaa4ff5ea8ccda912b9853d1c9462c476670e17
@@ -2176,9 +2176,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 803481f25020f3c25941f1e7d1a8071937820dea951e8798198b0b0fa3fb48ce 296b46c529d79385d7f4db2c789254a992c01ff66fe8ba6d3a3ce4aaac0203fb
-R e86e5c292ead4f22cefd158cafe4f8bc
-T +closed 296b46c529d79385d7f4db2c789254a992c01ff66fe8ba6d3a3ce4aaac0203fb
+P 5d392c16bb5658bc92f60d250ab82c45cc109e32d58a073498c9a487b8625e96
+R 9967c002ac0a5c05f7a39fb253518624
 U drh
-Z b02519e2fed4e4d80162d593e160efa1
+Z 10e35251deea062b6c8093330abd75ed
 # Remove this line to create a well-formed Fossil manifest.
index d954bb7e4a8d7dedabdd1d3a8d3b087e9519e34f..deb11dc730873cf4231b0ebf2f65b65e43418e48 100644 (file)
@@ -1 +1 @@
-5d392c16bb5658bc92f60d250ab82c45cc109e32d58a073498c9a487b8625e96
\ No newline at end of file
+f0831cced2c919e409214d936c81473ae321a98c5bd78b5b729c1269bf71bc45
\ No newline at end of file
index d4c3afdd388de2d80961c6a4023d45d53b653dd9..37bf7fdb4f61b56e05e523a1538807937bdbdce9 100644 (file)
@@ -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 */
 };
 
 
@@ -287,6 +288,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
 **
@@ -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;
index f0616f657058f7487427e8c5c3db0738175fd16f..2a6e93df40c063039cee6fe41fad693b57af3b73 100644 (file)
@@ -148,15 +148,6 @@ datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL
 
 datetest 2.60 {datetime('2023-02-31')} {2023-03-03 00:00:00}
 
-datetest 2.70 {date('2024-01-31','+1 month')} {2024-03-02}
-datetest 2.71 {date('2024-01-31','+1 mnth')} {2024-02-29}
-datetest 2.72 {date('2023-01-31','+1 month')} {2023-03-03}
-datetest 2.73 {date('2023-01-31','+1 mnth')} {2023-02-28}
-datetest 2.74 {date('2024-02-29','+1 year')} {2025-03-01}
-datetest 2.75 {date('2024-02-29','+1 yr')} {2025-02-28}
-datetest 2.76 {date('2024-02-29','-110 years')} {1914-03-01}
-datetest 2.77 {date('2024-02-29','-110 yrs')} {1914-02-28}
-
 datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
 datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post
 datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999
@@ -582,4 +573,51 @@ datetest 18.2 {unixepoch('1970-01-01T00:00:00.1', 'subsec')} {0.1}
 datetest 18.3 {unixepoch('1970-01-01T00:00:00.2', 'subsecond')} {0.2}
 datetest 18.4 {julianday('-4713-11-24 13:40:48.864', 'subsec')} {0.07001}
 datetest 18.5 {typeof(unixepoch('now', 'subsecond'))} {real}
+
+# 2024-03-03 the 'ceiling' and 'floor' operators.
+#
+datetest 19.1 {date('2000-01-31','floor')} {2000-01-31}
+datetest 19.2a {date('2000-02-31','floor')} {2000-02-29}
+datetest 19.2b {date('1999-02-31','floor')} {1999-02-28}
+datetest 19.2c {date('1900-02-31','floor')} {1900-02-28}
+datetest 19.3 {date('2000-03-31','floor')} {2000-03-31}
+datetest 19.4 {date('2000-04-31','floor')} {2000-04-30}
+datetest 19.5 {date('2000-05-31','floor')} {2000-05-31}
+datetest 19.6 {date('2000-06-31','floor')} {2000-06-30}
+datetest 19.7 {date('2000-07-31','floor')} {2000-07-31}
+datetest 19.8 {date('2000-08-31','floor')} {2000-08-31}
+datetest 19.9 {date('2000-09-31','floor')} {2000-09-30}
+datetest 19.10 {date('2000-10-31','floor')} {2000-10-31}
+datetest 19.11 {date('2000-11-31','floor')} {2000-11-30}
+datetest 19.12 {date('2000-12-31','floor')} {2000-12-31}
+datetest 19.21 {date('2000-01-31','ceiling')} {2000-01-31}
+datetest 19.22a {date('2000-02-31','ceiling')} {2000-03-02}
+datetest 19.22b {date('1999-02-31','ceiling')} {1999-03-03}
+datetest 19.22c {date('1900-02-31','ceiling')} {1900-03-03}
+datetest 19.23 {date('2000-03-31','ceiling')} {2000-03-31}
+datetest 19.24 {date('2000-04-31','ceiling')} {2000-05-01}
+datetest 19.25 {date('2000-05-31','ceiling')} {2000-05-31}
+datetest 19.26 {date('2000-06-31','ceiling')} {2000-07-01}
+datetest 19.27 {date('2000-07-31','ceiling')} {2000-07-31}
+datetest 19.28 {date('2000-08-31','ceiling')} {2000-08-31}
+datetest 19.29 {date('2000-09-31','ceiling')} {2000-10-01}
+datetest 19.30 {date('2000-10-31','ceiling')} {2000-10-31}
+datetest 19.31 {date('2000-11-31','ceiling')} {2000-12-01}
+datetest 19.32 {date('2000-12-31','ceiling')} {2000-12-31}
+datetest 19.40 {date('2024-01-31','+1 month','ceiling')} {2024-03-02}
+datetest 19.41 {date('2024-01-31','+1 month','floor')} {2024-02-29}
+datetest 19.42 {date('2023-01-31','+1 month','ceiling')} {2023-03-03}
+datetest 19.43 {date('2023-01-31','+1 month','floor')} {2023-02-28}
+datetest 19.44 {date('2024-02-29','+1 year','ceiling')} {2025-03-01}
+datetest 19.45 {date('2024-02-29','+1 year','floor')} {2025-02-28}
+datetest 19.46 {date('2024-02-29','-110 years','ceiling')} {1914-03-01}
+datetest 19.47 {date('2024-02-29','-110 years','floor')} {1914-02-28}
+datetest 19.48 {date('2024-02-29','-0110-00-00','floor')} {1914-02-28}
+datetest 19.49 {date('2024-02-29','-0110-00-00','ceiling')} {1914-03-01}
+datetest 19.50 {date('2000-08-31','+0023-06-00','floor')} {2024-02-29}
+datetest 19.51 {date('2000-08-31','+0022-06-00','floor')} {2023-02-28}
+datetest 19.52 {date('2000-08-31','+0023-06-00','ceiling')} {2024-03-02}
+datetest 19.53 {date('2000-08-31','+0022-06-00','ceiling')} {2023-03-03}
+
+
 finish_test