/ Check-in [ffa97193]
Login

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

Overview
Comment:Enhance date/time functions to work with negative years. Ticket #617. (CVS 1255)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ffa971934867b6bbe943c004154d5f161e0ea697
User & Date: drh 2004-02-21 03:28:18
Context
2004-02-21
13:31
More code cleanup and size reduction. (CVS 1256) check-in: 8e3eda2a user: drh tags: trunk
03:28
Enhance date/time functions to work with negative years. Ticket #617. (CVS 1255) check-in: ffa97193 user: drh tags: trunk
2004-02-20
23:34
Turn the short_column_names pragma off by default - for the time being. (CVS 1254) check-in: 6954d2c3 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/date.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
256
257
258
259
260
261
262
263
264






265
266
267
268
269
270
271
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
...
303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324
325
** This file contains the C functions that implement date and time
** functions for SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: date.c,v 1.10 2004/02/10 13:19:35 drh Exp $
**
** NOTES:
**
** SQLite processes all times and dates as Julian Day numbers.  The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system.
................................................................................
**     YYYY-MM-DD
**
** Write the result into the DateTime structure and return 0
** on success and 1 if the input string is not a well-formed
** date.
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
  int Y, M, D;







  Y = getDigits(zDate, 4);
  if( Y<0 || zDate[4]!='-' ) return 1;
  zDate += 5;
  M = getDigits(zDate, 2);
  if( M<=0 || M>12 || zDate[2]!='-' ) return 1;
  zDate += 3;
  D = getDigits(zDate, 2);
................................................................................
  }else if( *zDate==0 ){
    p->validHMS = 0;
  }else{
    return 1;
  }
  p->validJD = 0;
  p->validYMD = 1;
  p->Y = Y;
  p->M = M;
  p->D = D;
  if( p->validTZ ){
    computeJD(p);
  }
  return 0;
}
................................................................................
** In the first form, the +/-HH:MM is always optional.  The fractional
** seconds extension (the ".FFF") is optional.  The seconds portion
** (":SS.FFF") is option.  The year and date can be omitted as long
** as there is a time string.  The time string can be omitted as long
** as there is a year and date.
*/
static int parseDateOrTime(const char *zDate, DateTime *p){
  int i;
  memset(p, 0, sizeof(*p));
  for(i=0; isdigit(zDate[i]); i++){}
  if( i==4 && zDate[i]=='-' ){
    return parseYyyyMmDd(zDate, p);
  }else if( i==2 && zDate[i]==':' ){

    return parseHhMmSs(zDate, p);
    return 0;
  }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){
    double r;
    if( sqliteOsCurrentTime(&r)==0 ){
      p->rJD = r;
      p->validJD = 1;
      return 0;
    }
    return 1;







|







 







|

>
>
>
>
>
>







 







|







 







<

<
<
|
<
>
|

|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
309
310
311
312
313
314
315

316


317

318
319
320
321
322
323
324
325
326
327
328
** This file contains the C functions that implement date and time
** functions for SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: date.c,v 1.11 2004/02/21 03:28:18 drh Exp $
**
** NOTES:
**
** SQLite processes all times and dates as Julian Day numbers.  The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system.
................................................................................
**     YYYY-MM-DD
**
** Write the result into the DateTime structure and return 0
** on success and 1 if the input string is not a well-formed
** date.
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
  int Y, M, D, neg;

  if( zDate[0]=='-' ){
    zDate++;
    neg = 1;
  }else{
    neg = 0;
  }
  Y = getDigits(zDate, 4);
  if( Y<0 || zDate[4]!='-' ) return 1;
  zDate += 5;
  M = getDigits(zDate, 2);
  if( M<=0 || M>12 || zDate[2]!='-' ) return 1;
  zDate += 3;
  D = getDigits(zDate, 2);
................................................................................
  }else if( *zDate==0 ){
    p->validHMS = 0;
  }else{
    return 1;
  }
  p->validJD = 0;
  p->validYMD = 1;
  p->Y = neg ? -Y : Y;
  p->M = M;
  p->D = D;
  if( p->validTZ ){
    computeJD(p);
  }
  return 0;
}
................................................................................
** In the first form, the +/-HH:MM is always optional.  The fractional
** seconds extension (the ".FFF") is optional.  The seconds portion
** (":SS.FFF") is option.  The year and date can be omitted as long
** as there is a time string.  The time string can be omitted as long
** as there is a year and date.
*/
static int parseDateOrTime(const char *zDate, DateTime *p){

  memset(p, 0, sizeof(*p));


  if( parseYyyyMmDd(zDate,p)==0 ){

    return 0;
  }else if( parseHhMmSs(zDate, p)==0 ){
    return 0;
  }else if( sqliteStrICmp(zDate,"now")==0){
    double r;
    if( sqliteOsCurrentTime(&r)==0 ){
      p->rJD = r;
      p->validJD = 1;
      return 0;
    }
    return 1;

Changes to test/date.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
196
197
198
199
200
201
202










203
204
205
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing date and time functions.
#
# $Id: date.test,v 1.5 2004/01/07 03:29:16 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc datetest {tnum expr result} {
  do_test date-$tnum [subst {
    execsql "SELECT coalesce($expr,'NULL')"
................................................................................
datetest 8.14 {datetime('now','-13 month')} {2002-09-22 12:34:00}
datetest 8.15 {datetime('now','1.5 months')} {2003-12-07 12:34:00}
datetest 8.16 {datetime('now','-5 years')} {1998-10-22 12:34:00}
datetest 8.17 {datetime('now','+10.5 minutes')} {2003-10-22 12:44:30}
datetest 8.18 {datetime('now','-1.25 hours')} {2003-10-22 11:19:00}
datetest 8.19 {datetime('now','11.25 seconds')} {2003-10-22 12:34:11}
set sqlite_current_time 0












finish_test







|







 







>
>
>
>
>
>
>
>
>
>



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing date and time functions.
#
# $Id: date.test,v 1.6 2004/02/21 03:28:18 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc datetest {tnum expr result} {
  do_test date-$tnum [subst {
    execsql "SELECT coalesce($expr,'NULL')"
................................................................................
datetest 8.14 {datetime('now','-13 month')} {2002-09-22 12:34:00}
datetest 8.15 {datetime('now','1.5 months')} {2003-12-07 12:34:00}
datetest 8.16 {datetime('now','-5 years')} {1998-10-22 12:34:00}
datetest 8.17 {datetime('now','+10.5 minutes')} {2003-10-22 12:44:30}
datetest 8.18 {datetime('now','-1.25 hours')} {2003-10-22 11:19:00}
datetest 8.19 {datetime('now','11.25 seconds')} {2003-10-22 12:34:11}
set sqlite_current_time 0

# Negative years work.  Example:  '-4713-11-26' is JD 1.5.
#
datetest 9.1 {julianday('-4713-11-24 12:00:00')} {0}
datetest 9.2 {julianday(datetime(5))} {5}
datetest 9.3 {julianday(datetime(10))} {10}
datetest 9.4 {julianday(datetime(100))} {100}
datetest 9.5 {julianday(datetime(1000))} {1000}
datetest 9.6 {julianday(datetime(10000))} {10000}
datetest 9.7 {julianday(datetime(100000))} {100000}


finish_test