github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/sqlite3/date.patch (about)

     1  # Backport from 3.46.
     2  # https://sqlite.org/draft/releaselog/current.html
     3  --- sqlite3.c.orig
     4  +++ sqlite3.c
     5  @@ -71,13 +71,14 @@ struct DateTime {
     6     int tz;             /* Timezone offset in minutes */
     7     double s;           /* Seconds */
     8     char validJD;       /* True (1) if iJD is valid */
     9  -  char rawS;          /* Raw numeric value stored in s */
    10     char validYMD;      /* True (1) if Y,M,D are valid */
    11     char validHMS;      /* True (1) if h,m,s are valid */
    12  -  char validTZ;       /* True (1) if tz is valid */
    13  -  char tzSet;         /* Timezone was set explicitly */
    14  -  char isError;       /* An overflow has occurred */
    15  -  char useSubsec;     /* Display subsecond precision */
    16  +  char nFloor;            /* Days to implement "floor" */
    17  +  unsigned rawS      : 1; /* Raw numeric value stored in s */
    18  +  unsigned isError   : 1; /* An overflow has occurred */
    19  +  unsigned useSubsec : 1; /* Display subsecond precision */
    20  +  unsigned isUtc     : 1; /* Time is known to be UTC */
    21  +  unsigned isLocal   : 1; /* Time is known to be localtime */
    22   };
    23   
    24   
    25  @@ -175,6 +176,8 @@ static int parseTimezone(const char *zDate, DateTime *p){
    26       sgn = +1;
    27     }else if( c=='Z' || c=='z' ){
    28       zDate++;
    29  +    p->isLocal = 0;
    30  +    p->isUtc = 1;
    31       goto zulu_time;
    32     }else{
    33       return c!=0;
    34  @@ -187,7 +190,6 @@ static int parseTimezone(const char *zDate, DateTime *p){
    35     p->tz = sgn*(nMn + nHr*60);
    36   zulu_time:
    37     while( sqlite3Isspace(*zDate) ){ zDate++; }
    38  -  p->tzSet = 1;
    39     return *zDate!=0;
    40   }
    41   
    42  @@ -231,7 +233,6 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
    43     p->m = m;
    44     p->s = s + ms;
    45     if( parseTimezone(zDate, p) ) return 1;
    46  -  p->validTZ = (p->tz!=0)?1:0;
    47     return 0;
    48   }
    49   
    50  @@ -278,15 +279,40 @@ static void computeJD(DateTime *p){
    51     p->validJD = 1;
    52     if( p->validHMS ){
    53       p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
    54  -    if( p->validTZ ){
    55  +    if( p->tz ){
    56         p->iJD -= p->tz*60000;
    57         p->validYMD = 0;
    58         p->validHMS = 0;
    59  -      p->validTZ = 0;
    60  +      p->tz = 0;
    61  +      p->isUtc = 1;
    62  +      p->isLocal = 0;
    63       }
    64     }
    65   }
    66   
    67  +/*
    68  +** Given the YYYY-MM-DD information current in p, determine if there
    69  +** is day-of-month overflow and set nFloor to the number of days that
    70  +** would need to be subtracted from the date in order to bring the
    71  +** date back to the end of the month.
    72  +*/
    73  +static void computeFloor(DateTime *p){
    74  +  assert( p->validYMD || p->isError );
    75  +  assert( p->D>=0 && p->D<=31 );
    76  +  assert( p->M>=0 && p->M<=12 );
    77  +  if( p->D<=28 ){
    78  +    p->nFloor = 0;
    79  +  }else if( (1<<p->M) & 0x15aa ){
    80  +    p->nFloor = 0;
    81  +  }else if( p->M!=2 ){
    82  +    p->nFloor = (p->D==31);
    83  +  }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){
    84  +    p->nFloor = p->D - 28;
    85  +  }else{
    86  +    p->nFloor = p->D - 29;
    87  +  }
    88  +}
    89  +
    90   /*
    91   ** Parse dates of the form
    92   **
    93  @@ -325,12 +351,16 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
    94     p->Y = neg ? -Y : Y;
    95     p->M = M;
    96     p->D = D;
    97  -  if( p->validTZ ){
    98  +  computeFloor(p);
    99  +  if( p->tz ){
   100       computeJD(p);
   101     }
   102     return 0;
   103   }
   104   
   105  +
   106  +static void clearYMD_HMS_TZ(DateTime *p);  /* Forward declaration */
   107  +
   108   /*
   109   ** Set the time to the current time reported by the VFS.
   110   **
   111  @@ -340,6 +370,9 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
   112     p->iJD = sqlite3StmtCurrentTime(context);
   113     if( p->iJD>0 ){
   114       p->validJD = 1;
   115  +    p->isUtc = 1;
   116  +    p->isLocal = 0;
   117  +    clearYMD_HMS_TZ(p);
   118       return 0;
   119     }else{
   120       return 1;
   121  @@ -478,7 +511,7 @@ static void computeYMD_HMS(DateTime *p){
   122   static void clearYMD_HMS_TZ(DateTime *p){
   123     p->validYMD = 0;
   124     p->validHMS = 0;
   125  -  p->validTZ = 0;
   126  +  p->tz = 0;
   127   }
   128   
   129   #ifndef SQLITE_OMIT_LOCALTIME
   130  @@ -610,7 +643,7 @@ static int toLocaltime(
   131     p->validHMS = 1;
   132     p->validJD = 0;
   133     p->rawS = 0;
   134  -  p->validTZ = 0;
   135  +  p->tz = 0;
   136     p->isError = 0;
   137     return SQLITE_OK;
   138   }
   139  @@ -630,12 +663,12 @@ static const struct {
   140     float rLimit;       /* Maximum NNN value for this transform */
   141     float rXform;       /* Constant used for this transform */
   142   } aXformType[] = {
   143  -  { 6, "second", 4.6427e+14,       1.0  },
   144  -  { 6, "minute", 7.7379e+12,      60.0  },
   145  -  { 4, "hour",   1.2897e+11,    3600.0  },
   146  -  { 3, "day",    5373485.0,    86400.0  },
   147  -  { 5, "month",  176546.0,   2592000.0  },
   148  -  { 4, "year",   14713.0,   31536000.0  },
   149  +  /* 0 */ { 6, "second",   4.6427e+14,         1.0  },
   150  +  /* 1 */ { 6, "minute",   7.7379e+12,        60.0  },
   151  +  /* 2 */ { 4, "hour",     1.2897e+11,      3600.0  },
   152  +  /* 3 */ { 3, "day",      5373485.0,      86400.0  },
   153  +  /* 4 */ { 5, "month",    176546.0,  30.0*86400.0  },
   154  +  /* 5 */ { 4, "year",     14713.0,  365.0*86400.0  },
   155   };
   156   
   157   /*
   158  @@ -667,14 +700,20 @@ static void autoAdjustDate(DateTime *p){
   159   **     NNN.NNNN seconds
   160   **     NNN months
   161   **     NNN years
   162  +**     +/-YYYY-MM-DD HH:MM:SS.SSS
   163  +**     ceiling
   164  +**     floor
   165   **     start of month
   166   **     start of year
   167   **     start of week
   168   **     start of day
   169   **     weekday N
   170   **     unixepoch
   171  +**     auto
   172   **     localtime
   173   **     utc
   174  +**     subsec
   175  +**     subsecond
   176   **
   177   ** Return 0 on success and 1 if there is any kind of error. If the error
   178   ** is in a system call (i.e. localtime()), then an error message is written
   179  @@ -705,6 +744,37 @@ static int parseModifier(
   180         }
   181         break;
   182       }
   183  +    case 'c': {
   184  +      /*
   185  +      **    ceiling
   186  +      **
   187  +      ** Resolve day-of-month overflow by rolling forward into the next
   188  +      ** month.  As this is the default action, this modifier is really
   189  +      ** a no-op that is only included for symmetry.  See "floor".
   190  +      */
   191  +      if( sqlite3_stricmp(z, "ceiling")==0 ){
   192  +        computeJD(p);
   193  +        clearYMD_HMS_TZ(p);
   194  +        rc = 0;
   195  +        p->nFloor = 0;
   196  +      }
   197  +      break;
   198  +    }
   199  +    case 'f': {
   200  +      /*
   201  +      **    floor
   202  +      **
   203  +      ** Resolve day-of-month overflow by rolling back to the end of the
   204  +      ** previous month.
   205  +      */
   206  +      if( sqlite3_stricmp(z, "floor")==0 ){
   207  +        computeJD(p);
   208  +        p->iJD -= p->nFloor*86400000;
   209  +        clearYMD_HMS_TZ(p);
   210  +        rc = 0;
   211  +      }
   212  +      break;
   213  +    }
   214       case 'j': {
   215         /*
   216         **    julianday
   217  @@ -731,7 +801,9 @@ static int parseModifier(
   218         ** show local time.
   219         */
   220         if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
   221  -        rc = toLocaltime(p, pCtx);
   222  +        rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
   223  +        p->isUtc = 0;
   224  +        p->isLocal = 1;
   225         }
   226         break;
   227       }
   228  @@ -756,7 +828,7 @@ static int parseModifier(
   229         }
   230   #ifndef SQLITE_OMIT_LOCALTIME
   231         else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
   232  -        if( p->tzSet==0 ){
   233  +        if( p->isUtc==0 ){
   234             i64 iOrigJD;              /* Original localtime */
   235             i64 iGuess;               /* Guess at the corresponding utc time */
   236             int cnt = 0;              /* Safety to prevent infinite loop */
   237  @@ -779,7 +851,8 @@ static int parseModifier(
   238             memset(p, 0, sizeof(*p));
   239             p->iJD = iGuess;
   240             p->validJD = 1;
   241  -          p->tzSet = 1;
   242  +          p->isUtc = 1;
   243  +          p->isLocal = 0;
   244           }
   245           rc = SQLITE_OK;
   246         }
   247  @@ -799,7 +872,7 @@ static int parseModifier(
   248                  && r>=0.0 && r<7.0 && (n=(int)r)==r ){
   249           sqlite3_int64 Z;
   250           computeYMD_HMS(p);
   251  -        p->validTZ = 0;
   252  +        p->tz = 0;
   253           p->validJD = 0;
   254           computeJD(p);
   255           Z = ((p->iJD + 129600000)/86400000) % 7;
   256  @@ -839,7 +912,7 @@ static int parseModifier(
   257         p->h = p->m = 0;
   258         p->s = 0.0;
   259         p->rawS = 0;
   260  -      p->validTZ = 0;
   261  +      p->tz = 0;
   262         p->validJD = 0;
   263         if( sqlite3_stricmp(z,"month")==0 ){
   264           p->D = 1;
   265  @@ -910,6 +983,7 @@ static int parseModifier(
   266           x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
   267           p->Y += x;
   268           p->M -= x*12;
   269  +        computeFloor(p);
   270           computeJD(p);
   271           p->validHMS = 0;
   272           p->validYMD = 0;
   273  @@ -956,11 +1030,12 @@ static int parseModifier(
   274         z += n;
   275         while( sqlite3Isspace(*z) ) z++;
   276         n = sqlite3Strlen30(z);
   277  -      if( n>10 || n<3 ) break;
   278  +      if( n<3 || n>10 ) break;
   279         if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
   280         computeJD(p);
   281         assert( rc==1 );
   282         rRounder = r<0 ? -0.5 : +0.5;
   283  +      p->nFloor = 0;
   284         for(i=0; i<ArraySize(aXformType); i++){
   285           if( aXformType[i].nName==n
   286            && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
   287  @@ -968,21 +1043,24 @@ static int parseModifier(
   288           ){
   289             switch( i ){
   290               case 4: { /* Special processing to add months */
   291  -              assert( strcmp(aXformType[i].zName,"month")==0 );
   292  +              assert( strcmp(aXformType[4].zName,"month")==0 );
   293                 computeYMD_HMS(p);
   294                 p->M += (int)r;
   295                 x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
   296                 p->Y += x;
   297                 p->M -= x*12;
   298  +              computeFloor(p);
   299                 p->validJD = 0;
   300                 r -= (int)r;
   301                 break;
   302               }
   303               case 5: { /* Special processing to add years */
   304                 int y = (int)r;
   305  -              assert( strcmp(aXformType[i].zName,"year")==0 );
   306  +              assert( strcmp(aXformType[5].zName,"year")==0 );
   307                 computeYMD_HMS(p);
   308  +              assert( p->M>=0 && p->M<=12 );
   309                 p->Y += y;
   310  +              computeFloor(p);
   311                 p->validJD = 0;
   312                 r -= (int)r;
   313                 break;
   314  @@ -1236,22 +1314,83 @@ static void dateFunc(
   315     }
   316   }
   317   
   318  +/*
   319  +** Compute the number of days after the most recent January 1.
   320  +**
   321  +** In other words, compute the zero-based day number for the
   322  +** current year:
   323  +**
   324  +**   Jan01 = 0,  Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ...
   325  +**   Dec31 = 364 or 365.
   326  +*/
   327  +static int daysAfterJan01(DateTime *pDate){
   328  +  DateTime jan01 = *pDate;
   329  +  assert( jan01.validYMD );
   330  +  assert( jan01.validHMS );
   331  +  assert( pDate->validJD );
   332  +  jan01.validJD = 0;
   333  +  jan01.M = 1;
   334  +  jan01.D = 1;
   335  +  computeJD(&jan01);
   336  +  return (int)((pDate->iJD-jan01.iJD+43200000)/86400000);
   337  +}
   338  +
   339  +/*
   340  +** Return the number of days after the most recent Monday.
   341  +**
   342  +** In other words, return the day of the week according
   343  +** to this code:
   344  +**
   345  +**   0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday.
   346  +*/
   347  +static int daysAfterMonday(DateTime *pDate){
   348  +  assert( pDate->validJD );
   349  +  return (int)((pDate->iJD+43200000)/86400000) % 7;
   350  +}
   351  +
   352  +/*
   353  +** Return the number of days after the most recent Sunday.
   354  +**
   355  +** In other words, return the day of the week according
   356  +** to this code:
   357  +**
   358  +**   0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday
   359  +*/
   360  +static int daysAfterSunday(DateTime *pDate){
   361  +  assert( pDate->validJD );
   362  +  return (int)((pDate->iJD+129600000)/86400000) % 7;
   363  +}
   364  +
   365   /*
   366   **    strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
   367   **
   368   ** Return a string described by FORMAT.  Conversions as follows:
   369   **
   370  -**   %d  day of month
   371  +**   %d  day of month  01-31
   372  +**   %e  day of month  1-31
   373   **   %f  ** fractional seconds  SS.SSS
   374  +**   %F  ISO date.  YYYY-MM-DD
   375  +**   %G  ISO year corresponding to %V 0000-9999.
   376  +**   %g  2-digit ISO year corresponding to %V 00-99
   377   **   %H  hour 00-24
   378  -**   %j  day of year 000-366
   379  +**   %k  hour  0-24  (leading zero converted to space)
   380  +**   %I  hour 01-12
   381  +**   %j  day of year 001-366
   382   **   %J  ** julian day number
   383  +**   %l  hour  1-12  (leading zero converted to space)
   384   **   %m  month 01-12
   385   **   %M  minute 00-59
   386  +**   %p  "am" or "pm"
   387  +**   %P  "AM" or "PM"
   388  +**   %R  time as HH:MM
   389   **   %s  seconds since 1970-01-01
   390   **   %S  seconds 00-59
   391  -**   %w  day of week 0-6  Sunday==0
   392  -**   %W  week of year 00-53
   393  +**   %T  time as HH:MM:SS
   394  +**   %u  day of week 1-7  Monday==1, Sunday==7
   395  +**   %w  day of week 0-6  Sunday==0, Monday==1
   396  +**   %U  week of year 00-53  (First Sunday is start of week 01)
   397  +**   %V  week of year 01-53  (First week containing Thursday is week 01)
   398  +**   %W  week of year 00-53  (First Monday is start of week 01)
   399   **   %Y  year 0000-9999
   400   **   %%  %
   401   */
   402  @@ -1288,7 +1427,7 @@ static void strftimeFunc(
   403           sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
   404           break;
   405         }
   406  -      case 'f': {
   407  +      case 'f': {  /* Fractional seconds.  (Non-standard) */
   408           double s = x.s;
   409           if( s>59.999 ) s = 59.999;
   410           sqlite3_str_appendf(&sRes, "%06.3f", s);
   411  @@ -1298,6 +1437,21 @@ static void strftimeFunc(
   412           sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
   413           break;
   414         }
   415  +      case 'G': /* Fall thru */
   416  +      case 'g': {
   417  +        DateTime y = x;
   418  +        assert( y.validJD );
   419  +        /* Move y so that it is the Thursday in the same week as x */
   420  +        y.iJD += (3 - daysAfterMonday(&x))*86400000;
   421  +        y.validYMD = 0;
   422  +        computeYMD(&y);
   423  +        if( cf=='g' ){
   424  +          sqlite3_str_appendf(&sRes, "%02d", y.Y%100);
   425  +        }else{
   426  +          sqlite3_str_appendf(&sRes, "%04d", y.Y);
   427  +        }
   428  +        break;
   429  +      }
   430         case 'H':
   431         case 'k': {
   432           sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
   433  @@ -1311,25 +1465,11 @@ static void strftimeFunc(
   434           sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
   435           break;
   436         }
   437  -      case 'W': /* Fall thru */
   438  -      case 'j': {
   439  -        int nDay;             /* Number of days since 1st day of year */
   440  -        DateTime y = x;
   441  -        y.validJD = 0;
   442  -        y.M = 1;
   443  -        y.D = 1;
   444  -        computeJD(&y);
   445  -        nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
   446  -        if( cf=='W' ){
   447  -          int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
   448  -          wd = (int)(((x.iJD+43200000)/86400000)%7);
   449  -          sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
   450  -        }else{
   451  -          sqlite3_str_appendf(&sRes,"%03d",nDay+1);
   452  -        }
   453  +      case 'j': {  /* Day of year.  Jan01==1, Jan02==2, and so forth */
   454  +        sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1);
   455           break;
   456         }
   457  -      case 'J': {
   458  +      case 'J': {  /* Julian day number.  (Non-standard) */
   459           sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
   460           break;
   461         }
   462  @@ -1372,13 +1512,33 @@ static void strftimeFunc(
   463           sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
   464           break;
   465         }
   466  -      case 'u': /* Fall thru */
   467  -      case 'w': {
   468  -        char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
   469  +      case 'u':    /* Day of week.  1 to 7.  Monday==1, Sunday==7 */
   470  +      case 'w': {  /* Day of week.  0 to 6.  Sunday==0, Monday==1 */
   471  +        char c = (char)daysAfterSunday(&x) + '0';
   472           if( c=='0' && cf=='u' ) c = '7';
   473           sqlite3_str_appendchar(&sRes, 1, c);
   474           break;
   475         }
   476  +      case 'U': {  /* Week num. 00-53. First Sun of the year is week 01 */
   477  +        sqlite3_str_appendf(&sRes,"%02d",
   478  +              (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7);
   479  +        break;
   480  +      }
   481  +      case 'V': {  /* Week num. 01-53. First week with a Thur is week 01 */
   482  +        DateTime y = x;
   483  +        /* Adjust y so that is the Thursday in the same week as x */
   484  +        assert( y.validJD );
   485  +        y.iJD += (3 - daysAfterMonday(&x))*86400000;
   486  +        y.validYMD = 0;
   487  +        computeYMD(&y);
   488  +        sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1);
   489  +        break;
   490  +      }
   491  +      case 'W': {  /* Week num. 00-53. First Mon of the year is week 01 */
   492  +        sqlite3_str_appendf(&sRes,"%02d",
   493  +           (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7);
   494  +        break;
   495  +      }
   496         case 'Y': {
   497           sqlite3_str_appendf(&sRes,"%04d",x.Y);
   498           break;
   499  @@ -1525,9 +1685,7 @@ static void timediffFunc(
   500       d1.iJD = d2.iJD - d1.iJD;
   501       d1.iJD += (u64)1486995408 * (u64)100000;
   502     }
   503  -  d1.validYMD = 0;
   504  -  d1.validHMS = 0;
   505  -  d1.validTZ = 0;
   506  +  clearYMD_HMS_TZ(&d1);
   507     computeYMD_HMS(&d1);
   508     sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
   509     sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
   510  @@ -1596,6 +1754,36 @@ static void currentTimeFunc(
   511   }
   512   #endif
   513   
   514  +#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG)
   515  +/*
   516  +**   datedebug(...)
   517  +**
   518  +** This routine returns JSON that describes the internal DateTime object.
   519  +** Used for debugging and testing only.  Subject to change.
   520  +*/
   521  +static void datedebugFunc(
   522  +  sqlite3_context *context,
   523  +  int argc,
   524  +  sqlite3_value **argv
   525  +){
   526  +  DateTime x;
   527  +  if( isDate(context, argc, argv, &x)==0 ){
   528  +    char *zJson;
   529  +    zJson = sqlite3_mprintf(
   530  +      "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d,"
   531  +      "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d,"
   532  +      "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d,"
   533  +      "isUtc:%d,isLocal:%d}",
   534  +      x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz,
   535  +      x.s, x.validJD, x.validYMD, x.validHMS,
   536  +      x.nFloor, x.rawS, x.isError, x.useSubsec,
   537  +      x.isUtc, x.isLocal);
   538  +    sqlite3_result_text(context, zJson, -1, sqlite3_free);
   539  +  }
   540  +}
   541  +#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */
   542  +
   543  +
   544   /*
   545   ** This function registered all of the above C functions as SQL
   546   ** functions.  This should be the only routine in this file with
   547  @@ -1611,6 +1799,9 @@ void sqlite3RegisterDateTimeFunctions(void){
   548       PURE_DATE(datetime,         -1, 0, 0, datetimeFunc  ),
   549       PURE_DATE(strftime,         -1, 0, 0, strftimeFunc  ),
   550       PURE_DATE(timediff,          2, 0, 0, timediffFunc  ),
   551  +#ifdef SQLITE_DEBUG
   552  +    PURE_DATE(datedebug,        -1, 0, 0, datedebugFunc ),
   553  +#endif
   554       DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
   555       DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
   556       DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),