]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add support in the strftime() SQL function for conversion letters %G, %g,
authordrh <>
Thu, 18 Jan 2024 16:50:25 +0000 (16:50 +0000)
committerdrh <>
Thu, 18 Jan 2024 16:50:25 +0000 (16:50 +0000)
%U, and %V.

FossilOrigin-Name: e1155d6aa4b960ecfd14fa3467f28672af3327699c547f5b9e75da3ac1348ff7

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

index b0ad7329f931b59a43f997405a4e3c36ac94ec26..2ef2bf10a88d8ba9b985a7d0934d50b573f4e4fb 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sharmless\s"unused\sparameter"\scompiler\swarning\sin\sthe\snew\sfts3IntegrityMethod\nimplementation.
-D 2024-01-16T16:14:52.891
+C Add\ssupport\sin\sthe\sstrftime()\sSQL\sfunction\sfor\sconversion\sletters\s%G,\s%g,\n%U,\sand\s%V.
+D 2024-01-18T16:50:25.492
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -684,7 +684,7 @@ F src/build.c e7d9044592eeeea8e78d8ae53ca8d31fd6e92ca0d4f53e2f2e8ccf7352e0b04b
 F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
-F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91
+F src/date.c 7ed194fee09bc3aa2129cfe74ebf5daca6fc24c0995dd28cf2a2feacf4d8d44f
 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
@@ -1030,10 +1030,10 @@ F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c47
 F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270
 F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
 F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
-F test/date.test ff2341a1ef71b9a27979494d299222f9a293aa22cb9ff6e9c38d88a895317ebf
+F test/date.test b1a5208e6a9c390cf1d1fa4e38a910386b427b0e27046901c6b0fb995d19800e
 F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
 F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
-F test/date4.test 8aeb3de5b5e9fda968baa9357e4c0fae573724b7904943410195a19e96e31b6a
+F test/date4.test 77b3781c28d3a5e181c6474315aa58e1f6cf79f5171a4e46e248837b506e7adf
 F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
 F test/dbfuzz001.test 6c9a4622029d69dc38926f115864b055cb2f39badd25ec22cbfb130c8ba8e9c3
@@ -2158,8 +2158,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 b855886c4ccce0745af6957943e77be18949722f09821688725d546d3d79b4fb
-R e3234ce42cab7cdbc84f346ed1a36dc2
+P bb1fe53a97672fc868e3f3897162ea0d714dc1da95187f9c7e35255049f2b0e7
+R 600b04759487eea2e950d6a6bdd54077
 U drh
-Z 29787cb80c2a8f6910db50466343041a
+Z fe80399e6509893ac8c8ba9e1f44bd65
 # Remove this line to create a well-formed Fossil manifest.
index d671591dbfc263b7d433f4f569530f78940ac9b2..e751fb38dc07a1259a27e440d407071668314394 100644 (file)
@@ -1 +1 @@
-bb1fe53a97672fc868e3f3897162ea0d714dc1da95187f9c7e35255049f2b0e7
\ No newline at end of file
+e1155d6aa4b960ecfd14fa3467f28672af3327699c547f5b9e75da3ac1348ff7
\ No newline at end of file
index e493542db93a217d34c1a41c21069404b537c8d5..059d4c88a685c790655f507cffb92f4b89386006 100644 (file)
@@ -1236,22 +1236,98 @@ static void dateFunc(
   }
 }
 
+/*
+** Compute the one-based day of the year for the DateTime pDate.
+** Jan01 = 1,  Jan02 = 2, ... Dec31 = 356 or 366.
+*/
+static int dayOfYear(DateTime *pDate){
+  DateTime jan01 = *pDate;
+  assert( jan01.validYMD );
+  assert( jan01.validHMS );
+  assert( pDate->validJD );
+  jan01.validJD = 0;
+  jan01.M = 1;
+  jan01.D = 1;
+  computeJD(&jan01);
+  return (int)((pDate->iJD-jan01.iJD+45300000)/86400000) + 1;
+}
+
+/*
+** Return the day of the week.  1==Monday, 2=Tues, ..., 7=Sunday.
+*/
+static int dayOfWeek(DateTime *pDate){
+  int w;
+  assert( pDate->validJD );
+  w = ((pDate->iJD+129600000)/86400000) % 7;
+  if( w==0 ) w = 7;
+  return w;
+}
+
+/*
+** Compute the day-of-week (0=Sunday, 1=Monday, ..., 6=Saturday) for
+** the last day of the calendar year Y.
+*/
+static int lastDayOfYear(int Y){
+  return (Y + (Y/4) - (Y/100) + (Y/400))%7;
+}
+
+/*
+** Return the number of ISO weeks in calendar year Y.  The answer is
+** either 52 or 53.
+*/
+static int weeksInYear(int Y){
+  if( lastDayOfYear(Y)==4 || lastDayOfYear(Y-1)==3 ){
+    return 53;
+  }else{
+    return 52;
+  }
+}
+
+/*
+** Compute the number days since the start of the ISO-week year for pDate.
+** The ISO-week year starts on the first day of the week (always a Monday)
+** that contains the first Thursday on or after January 1.
+*/
+static int isoWeekNumber(DateTime *pDate){
+  int wn = (10 + dayOfYear(pDate) - dayOfWeek(pDate))/7;
+  if( wn<1 ){
+    wn = weeksInYear(pDate->Y-1);
+  }else if( wn>weeksInYear(pDate->Y) ){
+    wn = 1;
+  }
+  return wn;
+}
+
 /*
 **    strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
 **
 ** Return a string described by FORMAT.  Conversions as follows:
 **
-**   %d  day of month
+**   %d  day of month  01-31
+**   %e  day of month  1-31
 **   %f  ** fractional seconds  SS.SSS
+**   %F  ISO date.  YYYY-MM-DD
+**   %G  ISO year corresponding to %V 0000-9999.
+**   %g  2-digit ISO year corresponding to %V 00-99
 **   %H  hour 00-24
-**   %j  day of year 000-366
+**   %k  hour  0-24  (leading zero converted to space)
+**   %I  hour 01-12
+**   %j  day of year 001-366
 **   %J  ** julian day number
+**   %l  hour  1-12  (leading zero converted to space)
 **   %m  month 01-12
 **   %M  minute 00-59
+**   %p  "am" or "pm"
+**   %P  "AM" or "PM"
+**   %R  time as HH:MM
 **   %s  seconds since 1970-01-01
 **   %S  seconds 00-59
-**   %w  day of week 0-6  Sunday==0
-**   %W  week of year 00-53
+**   %T  time as HH:MM:SS
+**   %u  day of week 1-7  Monday==1, Sunday==7
+**   %w  day of week 0-6  Sunday==0, Monday==1
+**   %U  week of year 00-53  (First Sunday is start of week 01)
+**   %V  week of year 01-53  (First week containing Thursday is week 01)
+**   %W  week of year 00-53  (First Monday is start of week 01)
 **   %Y  year 0000-9999
 **   %%  %
 */
@@ -1288,7 +1364,7 @@ static void strftimeFunc(
         sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
         break;
       }
-      case 'f': {
+      case 'f': {  /* Fractional seconds.  (Non-standard) */
         double s = x.s;
         if( s>59.999 ) s = 59.999;
         sqlite3_str_appendf(&sRes, "%06.3f", s);
@@ -1298,6 +1374,21 @@ static void strftimeFunc(
         sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
         break;
       }
+      case 'G': /* Fall thru */
+      case 'g': {
+        int Y = x.Y;
+        if( x.M==12 && isoWeekNumber(&x)==1 ){
+          Y++;
+        }else if( x.M==1 && isoWeekNumber(&x)>=52 ){
+          Y--;
+        }
+        if( cf=='g' ){
+          sqlite3_str_appendf(&sRes, "%02d", Y%100);
+        }else{
+          sqlite3_str_appendf(&sRes, "%04d", Y);
+        }
+        break;
+      }
       case 'H':
       case 'k': {
         sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
@@ -1311,25 +1402,12 @@ static void strftimeFunc(
         sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
         break;
       }
-      case 'W': /* Fall thru */
-      case 'j': {
-        int nDay;             /* Number of days since 1st day of year */
-        DateTime y = x;
-        y.validJD = 0;
-        y.M = 1;
-        y.D = 1;
-        computeJD(&y);
-        nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
-        if( cf=='W' ){
-          int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
-          wd = (int)(((x.iJD+43200000)/86400000)%7);
-          sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
-        }else{
-          sqlite3_str_appendf(&sRes,"%03d",nDay+1);
-        }
+      case 'j': {  /* Day of year.  Jan01==1, Jan02==2, and so forth */
+        int nDay = dayOfYear(&x);
+        sqlite3_str_appendf(&sRes,"%03d",nDay);
         break;
       }
-      case 'J': {
+      case 'J': {  /* Julian day number.  (Non-standard) */
         sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
         break;
       }
@@ -1372,13 +1450,33 @@ static void strftimeFunc(
         sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
         break;
       }
-      case 'u': /* Fall thru */
-      case 'w': {
+      case 'u':    /* Day of week.  1 to 7.  Monday==1, Sunday==7 */
+      case 'w': {  /* Day of week.  0 to 6.  Sunday==0, Monday==1 */
         char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
         if( c=='0' && cf=='u' ) c = '7';
         sqlite3_str_appendchar(&sRes, 1, c);
         break;
       }
+      case 'U': {  /* Week num. 00-53. First Sun of the year is week 01 */
+        int wd;    /* 0=Sunday, 1=Monday, 2=Tuesday, ... 7=Saturday */
+        int nDay;  /* Day of the year.  0..364 or 0..365 for leapyears */
+        nDay = dayOfYear(&x);
+        wd = (int)(((x.iJD+43200000)/86400000 + 1)%7);
+        sqlite3_str_appendf(&sRes,"%02d",(nDay+6-wd)/7);
+        break;
+      }
+      case 'V': {  /* Week num. 01-53. First week with a Thur is week 01 */
+        sqlite3_str_appendf(&sRes,"%02d", isoWeekNumber(&x));
+        break;
+      }
+      case 'W': {  /* Week num. 00-53. First Mon of the year is week 01 */
+        int wd;    /* 0=Monday, 1=Tuesday, ... 6=Sunday */
+        int nDay;  /* Day of the year.  0..364 or 0..365 for leapyears */
+        nDay = dayOfYear(&x);
+        wd = (int)(((x.iJD+43200000)/86400000)%7);
+        sqlite3_str_appendf(&sRes,"%02d",(nDay+6-wd)/7);
+        break;
+      }
       case 'Y': {
         sqlite3_str_appendf(&sRes,"%04d",x.Y);
         break;
index 19cecc2db324aa41dbc93fa73c2cdc4355c65854..d536c65fce9ebb2aadee6803d6757765693550af 100644 (file)
@@ -209,8 +209,8 @@ datetest 3.16 "strftime('[repeat 200 %Y]','2003-10-31')" [repeat 200 2003]
 datetest 3.17 "strftime('[repeat 200 abc%m123]','2003-10-31')" \
     [repeat 200 abc10123]
 
-foreach c {a b c h i n o q r t v x y z
-           A B C D E G K L N O Q V Z
+foreach c {a b c h i n o q r t v x y z
+           A B C D E K L N O Q Z
            0 1 2 3 4 5 6 6 7 9 _} {
   datetest 3.18.$c "strftime('%$c','2003-10-31')" NULL
 }
index 0d820a0a40425f9b626b6d14116c42eb7601d4c9..0dd06debb7c0d63e64528f5f2af0a9ac414beea8 100644 (file)
@@ -24,7 +24,7 @@ ifcapable {!datetime} {
 }
 
 if {$tcl_platform(os)=="Linux"} {
-  set FMT {%d,%e,%F,%H,%k,%I,%l,%j,%m,%M,%u,%w,%W,%Y,%%,%P,%p}
+  set FMT {%d,%e,%F,%H,%k,%I,%l,%j,%m,%M,%u,%w,%W,%Y,%%,%P,%p,%U,%V,%G,%g}
 } else {
   set FMT {%d,%e,%F,%H,%I,%j,%p,%R,%u,%w,%W,%%}
 }