SQLite

Check-in [dc569683]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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 post e7a939e074. Also add the datedebug() function, available only under -DSQLITE_DEBUG, for improved visibility of the DateTime object during debugging and testing.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: dc569683748354a6db83438904422e802d3ea780775c48da85b474fff03ca8a1
User & Date: drh 2024-03-04 13:58:09
Context
2024-03-04
16:18
Fix harmless compiler warnings in the increment integrity_check extension. (check-in: 596668e6 user: drh tags: trunk)
13:58
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 post e7a939e074. Also add the datedebug() function, available only under -DSQLITE_DEBUG, for improved visibility of the DateTime object during debugging and testing. (check-in: dc569683 user: drh tags: trunk)
11:12
Fix assert() statements in date/time computations: The month and day numbers can be zero if an error has been seen. (check-in: fc773f6c user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/date.c.

69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
86
87
88
  int Y, M, D;        /* Year, month, and day */
  int h, m;           /* Hour and minutes */
  int tz;             /* Timezone offset in minutes */
  double s;           /* Seconds */
  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 */


};


/*
** Convert zDate into one or more integers according to the conversion
** specifier zFormat.
**







<


<


>
>







69
70
71
72
73
74
75

76
77

78
79
80
81
82
83
84
85
86
87
88
  int Y, M, D;        /* Year, month, and day */
  int h, m;           /* Hour and minutes */
  int tz;             /* Timezone offset in minutes */
  double s;           /* Seconds */
  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 nFloor;            /* Days to implement "floor" */
  unsigned rawS      : 1; /* Raw numeric value stored in s */

  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 */
};


/*
** Convert zDate into one or more integers according to the conversion
** specifier zFormat.
**
172
173
174
175
176
177
178


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  c = *zDate;
  if( c=='-' ){
    sgn = -1;
  }else if( c=='+' ){
    sgn = +1;
  }else if( c=='Z' || c=='z' ){
    zDate++;


    goto zulu_time;
  }else{
    return c!=0;
  }
  zDate++;
  if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
    return 1;
  }
  zDate += 5;
  p->tz = sgn*(nMn + nHr*60);
zulu_time:
  while( sqlite3Isspace(*zDate) ){ zDate++; }
  p->tzSet = 1;
  return *zDate!=0;
}

/*
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
** The HH, MM, and SS must each be exactly 2 digits.  The
** fractional seconds FFFF can be one or more digits.







>
>












<







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

193
194
195
196
197
198
199
  c = *zDate;
  if( c=='-' ){
    sgn = -1;
  }else if( c=='+' ){
    sgn = +1;
  }else if( c=='Z' || c=='z' ){
    zDate++;
    p->isLocal = 0;
    p->isUtc = 1;
    goto zulu_time;
  }else{
    return c!=0;
  }
  zDate++;
  if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
    return 1;
  }
  zDate += 5;
  p->tz = sgn*(nMn + nHr*60);
zulu_time:
  while( sqlite3Isspace(*zDate) ){ zDate++; }

  return *zDate!=0;
}

/*
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
** The HH, MM, and SS must each be exactly 2 digits.  The
** fractional seconds FFFF can be one or more digits.
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  p->validJD = 0;
  p->rawS = 0;
  p->validHMS = 1;
  p->h = h;
  p->m = m;
  p->s = s + ms;
  if( parseTimezone(zDate, p) ) return 1;
  p->validTZ = (p->tz!=0)?1:0;
  return 0;
}

/*
** Put the DateTime object into its error state.
*/
static void datetimeError(DateTime *p){







<







229
230
231
232
233
234
235

236
237
238
239
240
241
242
  p->validJD = 0;
  p->rawS = 0;
  p->validHMS = 1;
  p->h = h;
  p->m = m;
  p->s = s + ms;
  if( parseTimezone(zDate, p) ) return 1;

  return 0;
}

/*
** Put the DateTime object into its error state.
*/
static void datetimeError(DateTime *p){
275
276
277
278
279
280
281
282
283
284
285
286


287
288
289
290
291
292
293
  B = 2 - A + (A/4);
  X1 = 36525*(Y+4716)/100;
  X2 = 306001*(M+1)/10000;
  p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
  p->validJD = 1;
  if( p->validHMS ){
    p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
    if( p->validTZ ){
      p->iJD -= p->tz*60000;
      p->validYMD = 0;
      p->validHMS = 0;
      p->validTZ = 0;


    }
  }
}

/*
** 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







|



|
>
>







275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  B = 2 - A + (A/4);
  X1 = 36525*(Y+4716)/100;
  X2 = 306001*(M+1)/10000;
  p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
  p->validJD = 1;
  if( p->validHMS ){
    p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
    if( p->tz ){
      p->iJD -= p->tz*60000;
      p->validYMD = 0;
      p->validHMS = 0;
      p->tz = 0;
      p->isUtc = 1;
      p->isLocal = 0;
    }
  }
}

/*
** 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
346
347
348
349
350
351
352
353
354
355
356

357


358
359
360
361
362
363
364
365
366
367



368
369
370
371
372
373
374
  }
  p->validJD = 0;
  p->validYMD = 1;
  p->Y = neg ? -Y : Y;
  p->M = M;
  p->D = D;
  computeFloor(p);
  if( p->validTZ ){
    computeJD(p);
  }
  return 0;

}



/*
** Set the time to the current time reported by the VFS.
**
** Return the number of errors.
*/
static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
  p->iJD = sqlite3StmtCurrentTime(context);
  if( p->iJD>0 ){
    p->validJD = 1;



    return 0;
  }else{
    return 1;
  }
}

/*







|



>
|
>
>










>
>
>







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  }
  p->validJD = 0;
  p->validYMD = 1;
  p->Y = neg ? -Y : Y;
  p->M = M;
  p->D = D;
  computeFloor(p);
  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.
**
** Return the number of errors.
*/
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;
  }
}

/*
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513

/*
** Clear the YMD and HMS and the TZ
*/
static void clearYMD_HMS_TZ(DateTime *p){
  p->validYMD = 0;
  p->validHMS = 0;
  p->validTZ = 0;
}

#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to 
** localtime_r() available under most POSIX platforms, except that the 







|







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521

/*
** Clear the YMD and HMS and the TZ
*/
static void clearYMD_HMS_TZ(DateTime *p){
  p->validYMD = 0;
  p->validHMS = 0;
  p->tz = 0;
}

#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to 
** localtime_r() available under most POSIX platforms, except that the 
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
  p->h = sLocal.tm_hour;
  p->m = sLocal.tm_min;
  p->s = sLocal.tm_sec + (p->iJD%1000)*0.001;
  p->validYMD = 1;
  p->validHMS = 1;
  p->validJD = 0;
  p->rawS = 0;
  p->validTZ = 0;
  p->isError = 0;
  return SQLITE_OK;
}
#endif /* SQLITE_OMIT_LOCALTIME */

/*
** The following table defines various date transformations of the form







|







639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
  p->h = sLocal.tm_hour;
  p->m = sLocal.tm_min;
  p->s = sLocal.tm_sec + (p->iJD%1000)*0.001;
  p->validYMD = 1;
  p->validHMS = 1;
  p->validJD = 0;
  p->rawS = 0;
  p->tz = 0;
  p->isError = 0;
  return SQLITE_OK;
}
#endif /* SQLITE_OMIT_LOCALTIME */

/*
** The following table defines various date transformations of the form
789
790
791
792
793
794
795
796


797
798
799
800
801
802
803
    case 'l': {
      /*    localtime
      **
      ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
      ** show local time.
      */
      if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
        rc = toLocaltime(p, pCtx);


      }
      break;
    }
#endif
    case 'u': {
      /*
      **    unixepoch







|
>
>







797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
    case 'l': {
      /*    localtime
      **
      ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
      ** show local time.
      */
      if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
        rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx);
        p->isUtc = 0;
        p->isLocal = 1;
      }
      break;
    }
#endif
    case 'u': {
      /*
      **    unixepoch
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
          p->validJD = 1;
          p->rawS = 0;
          rc = 0;
        }
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
        if( p->tzSet==0 ){
          i64 iOrigJD;              /* Original localtime */
          i64 iGuess;               /* Guess at the corresponding utc time */
          int cnt = 0;              /* Safety to prevent infinite loop */
          i64 iErr;                 /* Guess is off by this much */

          computeJD(p);
          iGuess = iOrigJD = p->iJD;







|







824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
          p->validJD = 1;
          p->rawS = 0;
          rc = 0;
        }
      }
#ifndef SQLITE_OMIT_LOCALTIME
      else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
        if( p->isUtc==0 ){
          i64 iOrigJD;              /* Original localtime */
          i64 iGuess;               /* Guess at the corresponding utc time */
          int cnt = 0;              /* Safety to prevent infinite loop */
          i64 iErr;                 /* Guess is off by this much */

          computeJD(p);
          iGuess = iOrigJD = p->iJD;
837
838
839
840
841
842
843
844

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
            if( rc ) return rc;
            computeJD(&new);
            iErr = new.iJD - iOrigJD;
          }while( iErr && cnt++<3 );
          memset(p, 0, sizeof(*p));
          p->iJD = iGuess;
          p->validJD = 1;
          p->tzSet = 1;

        }
        rc = SQLITE_OK;
      }
#endif
      break;
    }
    case 'w': {
      /*
      **    weekday N
      **
      ** Move the date to the same time on the next occurrence of
      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
      ** date is already on the appropriate weekday, this is a no-op.
      */
      if( sqlite3_strnicmp(z, "weekday ", 8)==0
               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
               && r>=0.0 && r<7.0 && (n=(int)r)==r ){
        sqlite3_int64 Z;
        computeYMD_HMS(p);
        p->validTZ = 0;
        p->validJD = 0;
        computeJD(p);
        Z = ((p->iJD + 129600000)/86400000) % 7;
        if( Z>n ) Z -= 7;
        p->iJD += (n - Z)*86400000;
        clearYMD_HMS_TZ(p);
        rc = 0;







|
>



















|







847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
            if( rc ) return rc;
            computeJD(&new);
            iErr = new.iJD - iOrigJD;
          }while( iErr && cnt++<3 );
          memset(p, 0, sizeof(*p));
          p->iJD = iGuess;
          p->validJD = 1;
          p->isUtc = 1;
          p->isLocal = 0;
        }
        rc = SQLITE_OK;
      }
#endif
      break;
    }
    case 'w': {
      /*
      **    weekday N
      **
      ** Move the date to the same time on the next occurrence of
      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
      ** date is already on the appropriate weekday, this is a no-op.
      */
      if( sqlite3_strnicmp(z, "weekday ", 8)==0
               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
               && r>=0.0 && r<7.0 && (n=(int)r)==r ){
        sqlite3_int64 Z;
        computeYMD_HMS(p);
        p->tz = 0;
        p->validJD = 0;
        computeJD(p);
        Z = ((p->iJD + 129600000)/86400000) % 7;
        if( Z>n ) Z -= 7;
        p->iJD += (n - Z)*86400000;
        clearYMD_HMS_TZ(p);
        rc = 0;
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
      if( !p->validJD && !p->validYMD && !p->validHMS ) break;
      z += 9;
      computeYMD(p);
      p->validHMS = 1;
      p->h = p->m = 0;
      p->s = 0.0;
      p->rawS = 0;
      p->validTZ = 0;
      p->validJD = 0;
      if( sqlite3_stricmp(z,"month")==0 ){
        p->D = 1;
        rc = 0;
      }else if( sqlite3_stricmp(z,"year")==0 ){
        p->M = 1;
        p->D = 1;







|







908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
      if( !p->validJD && !p->validYMD && !p->validHMS ) break;
      z += 9;
      computeYMD(p);
      p->validHMS = 1;
      p->h = p->m = 0;
      p->s = 0.0;
      p->rawS = 0;
      p->tz = 0;
      p->validJD = 0;
      if( sqlite3_stricmp(z,"month")==0 ){
        p->D = 1;
        rc = 0;
      }else if( sqlite3_stricmp(z,"year")==0 ){
        p->M = 1;
        p->D = 1;
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
      }
      d2.validJD = 0;
      computeJD(&d2);
    }
    d1.iJD = d2.iJD - d1.iJD;
    d1.iJD += (u64)1486995408 * (u64)100000;
  }
  d1.validYMD = 0;
  d1.validHMS = 0;
  d1.validTZ = 0;
  computeYMD_HMS(&d1);
  sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
  sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
       sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
  sqlite3ResultStrAccum(context, &sRes);
}








|
<
<







1681
1682
1683
1684
1685
1686
1687
1688


1689
1690
1691
1692
1693
1694
1695
      }
      d2.validJD = 0;
      computeJD(&d2);
    }
    d1.iJD = d2.iJD - d1.iJD;
    d1.iJD += (u64)1486995408 * (u64)100000;
  }
  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",
       sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
  sqlite3ResultStrAccum(context, &sRes);
}

1740
1741
1742
1743
1744
1745
1746






























1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762



1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
#endif
  if( pTm ){
    strftime(zBuf, 20, zFormat, &sNow);
    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
  }
}
#endif































/*
** This function registered all of the above C functions as SQL
** functions.  This should be the only routine in this file with
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
  static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
    PURE_DATE(julianday,        -1, 0, 0, juliandayFunc ),
    PURE_DATE(unixepoch,        -1, 0, 0, unixepochFunc ),
    PURE_DATE(date,             -1, 0, 0, dateFunc      ),
    PURE_DATE(time,             -1, 0, 0, timeFunc      ),
    PURE_DATE(datetime,         -1, 0, 0, datetimeFunc  ),
    PURE_DATE(strftime,         -1, 0, 0, strftimeFunc  ),
    PURE_DATE(timediff,          2, 0, 0, timediffFunc  ),



    DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
    DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
    DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
#else
    STR_FUNCTION(current_time,      0, "%H:%M:%S",          0, currentTimeFunc),
    STR_FUNCTION(current_date,      0, "%Y-%m-%d",          0, currentTimeFunc),
    STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
  };
  sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
















>
>
>











1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
#endif
  if( pTm ){
    strftime(zBuf, 20, zFormat, &sNow);
    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
  }
}
#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
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
  static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
    PURE_DATE(julianday,        -1, 0, 0, juliandayFunc ),
    PURE_DATE(unixepoch,        -1, 0, 0, unixepochFunc ),
    PURE_DATE(date,             -1, 0, 0, dateFunc      ),
    PURE_DATE(time,             -1, 0, 0, timeFunc      ),
    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     ),
#else
    STR_FUNCTION(current_time,      0, "%H:%M:%S",          0, currentTimeFunc),
    STR_FUNCTION(current_date,      0, "%Y-%m-%d",          0, currentTimeFunc),
    STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
  };
  sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}

Changes to test/date.test.

258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
datetest 5.13 {datetime('1994-04-16 14:00:00Zulu')} NULL
datetest 5.14 {datetime('1994-04-16 14:00:00Z +05:00')} NULL
datetest 5.15 {datetime('1994-04-16 14:00:00 +05:00 Z')} NULL

# localtime->utc and utc->localtime conversions.
#
# Use SQLITE_TESTCTRL_LOCALTIME_FAULT=2 to set an alternative localtime_r()
# implementation that is not locale-dependent.  This testing localtime_r()
# operates as follows:
#
#     (1)  Localtime is 30 minutes earlier than (west of) UTC on
#          even days (counting from 1970-01-01)
#
#     (2)  Localtime is 30 minutes later than (east of) UTC on odd days.
#







|







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
datetest 5.13 {datetime('1994-04-16 14:00:00Zulu')} NULL
datetest 5.14 {datetime('1994-04-16 14:00:00Z +05:00')} NULL
datetest 5.15 {datetime('1994-04-16 14:00:00 +05:00 Z')} NULL

# localtime->utc and utc->localtime conversions.
#
# Use SQLITE_TESTCTRL_LOCALTIME_FAULT=2 to set an alternative localtime_r()
# implementation that is not locale-dependent.  The testing localtime_r()
# operates as follows:
#
#     (1)  Localtime is 30 minutes earlier than (west of) UTC on
#          even days (counting from 1970-01-01)
#
#     (2)  Localtime is 30 minutes later than (east of) UTC on odd days.
#
316
317
318
319
320
321
322
































323
324
325
326
327
328
329

# Modifiers work for dates that are way out of band for localtime_r()
#
local_to_utc 6.21 {1800-10-29 12:00:00} {1800-10-29 12:30:00}
utc_to_local 6.22 {1800-10-29 12:30:00} {1800-10-29 12:00:00}
local_to_utc 6.23 {3000-10-30 12:00:00} {3000-10-30 11:30:00}
utc_to_local 6.24 {3000-10-30 11:30:00} {3000-10-30 12:00:00}

































# Restore the use of the OS localtime_r() before going on...
sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

# Date-time functions that contain NULL arguments return a NULL
# result.
#







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361

# Modifiers work for dates that are way out of band for localtime_r()
#
local_to_utc 6.21 {1800-10-29 12:00:00} {1800-10-29 12:30:00}
utc_to_local 6.22 {1800-10-29 12:30:00} {1800-10-29 12:00:00}
local_to_utc 6.23 {3000-10-30 12:00:00} {3000-10-30 11:30:00}
utc_to_local 6.24 {3000-10-30 11:30:00} {3000-10-30 12:00:00}

# If the time is specified to be ZULU, or if it has an explicit
# timezone extension, then the time will already be UTC and subsequent
# 'utc' modifiers are no-ops.
#
do_execsql_test date-6.25 {
  SELECT datetime('2000-10-29 12:00Z','utc','utc');
} {{2000-10-29 12:00:00}}
do_execsql_test date-6.26 {
  SELECT datetime('2000-10-29 12:00:00+05:00');
} {{2000-10-29 07:00:00}}
do_execsql_test date-6.27 {
  SELECT datetime('2000-10-29 12:00:00+05:00', 'utc');
} {{2000-10-29 07:00:00}}

# Multiple back-and-forth UTC to LOCAL to UTC...
do_execsql_test date-6.28 {
  SELECT datetime('2000-10-29 12:00:00Z', 'localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.29 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc', 'localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.30 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc', 'localtime', 'utc');
} {{2000-10-29 12:00:00}}
do_execsql_test date-6.31 {
  SELECT datetime('2000-10-29 12:00:00Z', 'utc','localtime','utc','localtime');
} {{2000-10-29 12:30:00}}
do_execsql_test date-6.32 {
  SELECT datetime('2000-10-29 12:00:00Z', 'localtime','localtime');
} {{2000-10-29 12:30:00}}


# Restore the use of the OS localtime_r() before going on...
sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

# Date-time functions that contain NULL arguments return a NULL
# result.
#

Changes to test/tkt-bd484a090c.test.

26
27
28
29
30
31
32
33
34
35
36
37
38

sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1

do_test 2.1 {
  catchsql { SELECT datetime('now', 'localtime') }
} {1 {local time unavailable}}
do_test 2.2 {
  catchsql { SELECT datetime('now', 'utc') }
} {1 {local time unavailable}}

sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

finish_test







|





26
27
28
29
30
31
32
33
34
35
36
37
38

sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 1

do_test 2.1 {
  catchsql { SELECT datetime('now', 'localtime') }
} {1 {local time unavailable}}
do_test 2.2 {
  catchsql { SELECT datetime('2000-01-01', 'utc') }
} {1 {local time unavailable}}

sqlite3_test_control SQLITE_TESTCTRL_LOCALTIME_FAULT 0

finish_test