/ Check-in [06d4e883]
Login

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

Overview
Comment:Update to the date functions. (CVS 1110)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 06d4e88394217fb1390b069bad82d6ac71981f72
User & Date: drh 2003-10-10 02:09:57
Context
2003-10-18
09:37
Add sqlite_progress_handler() API for specifying an progress callback (CVS 1111) check-in: ddb36463 user: danielk1977 tags: trunk
2003-10-10
02:09
Update to the date functions. (CVS 1110) check-in: 06d4e883 user: drh tags: trunk
2003-10-03
00:13
Allow quoted trigger names. Ticket #468. (CVS 1109) check-in: 54aa0fb2 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/func.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
582
583
584
585
586
587
588






































589
590


591






592
593
594
595

596
597
598
599
600
601
602
603
604
605









606
607
608
609
610
611
612
613
614
615
616
617
...
662
663
664
665
666
667
668
669
670
671
672
673
674
675











676
677
678
679
680
681
682
683


684
685
686
687
688
689
690
...
693
694
695
696
697
698
699
700

701
702
703
704
705
706
707
...
724
725
726
727
728
729
730
731

732


733
734
735

736
737
738
739
740
741
742
...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
...
772
773
774
775
776
777
778
779

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
...
835
836
837
838
839
840
841










842
843
844
845
846
847
848
...
873
874
875
876
877
878
879


880
881
882
883
884
885
886
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.31 2003/09/06 01:10:47 drh Exp $
*/
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "sqliteInt.h"
#include "os.h"
................................................................................
    val = val*10 + *zDate - '0';
    zDate++;
  }
  return val;
}

/*






































** Parse times of the form HH:MM:SS or HH:MM.  Store the
** result (in days) in *prJD.


**






** Return 1 if there is a parsing error and 0 on success.
*/
static int parseHhMmSs(const char *zDate, double *prJD){
  int h, m, s;

  h = getDigits(zDate, 2);
  if( h<0 || zDate[2]!=':' ) return 1;
  zDate += 3;
  m = getDigits(zDate, 2);
  if( m<0 || m>59 ) return 1;
  zDate += 2;
  if( *zDate==':' ){
    s = getDigits(&zDate[1], 2);
    if( s<0 || s>59 ) return 1;
    zDate += 3;









  }else{
    s = 0;
  }
  while( isspace(*zDate) ){ zDate++; }
  *prJD = (h*3600.0 + m*60.0 + s)/86400.0;
  return 0;
}

/*
** Parse dates of the form
**
**     YYYY-MM-DD HH:MM:SS
................................................................................

/*
** Attempt to parse the given string into a Julian Day Number.  Return
** the number of errors.
**
** The following are acceptable forms for the input string:
**
**      YYYY-MM-DD
**      YYYY-MM-DD HH:MM
**      YYYY-MM-DD HH:MM:SS
**      HH:MM
**      HH:MM:SS
**      DDDD.DD 
**      now











*/
static int parseDateOrTime(const char *zDate, double *prJD){
  int i;
  for(i=0; isdigit(zDate[i]); i++){}
  if( i==4 && zDate[i]=='-' ){
    return parseYyyyMmDd(zDate, prJD);
  }else if( i==2 && zDate[i]==':' ){
    return parseHhMmSs(zDate, prJD);


  }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){
    return sqliteOsCurrentTime(prJD);
  }else if( sqliteIsNumber(zDate) ){
    *prJD = atof(zDate);
    return 0;
  }
  return 1;
................................................................................
/*
** A structure for holding date and time.
*/
typedef struct DateTime DateTime;
struct DateTime {
  double rJD;    /* The julian day number */
  int Y, M, D;   /* Year, month, and day */
  int h, m, s;   /* Hour minute and second */

};

/*
** Break up a julian day number into year, month, day, hour, minute, second.
** This function assume the Gregorian calendar - even for dates prior
** to the invention of the Gregorian calendar in 1582.
**
................................................................................
    E = (B-D)/30.6001;
    X1 = 30.6001*E;
    p->D = B - D - X1;
    p->M = E<14 ? E-1 : E-13;
    p->Y = p->M>2 ? C - 4716 : C - 4715;
  }
  if( mode & 2 ){
    p->s = (p->rJD + 0.5 - Z)*86400.0;

    p->h = p->s/3600;


    p->s -= p->h*3600;
    p->m = p->s/60;
    p->s -= p->m*60;

  }
}

/*
** Check to see that all arguments are valid date strings.  If any 
** argument is not a valid date string, return 0.  If all arguments
** are valid, return 1 and write into *p->rJD the sum of the julian day
................................................................................
*/
static int isDate(int argc, const char **argv, DateTime *p, int mode){
  double r;
  int i;
  p->rJD = 0.0;
  for(i=0; i<argc; i++){
    if( argv[i]==0 ) return 0;
    if( parseDateOrTime(argv[i], &r) ) return 0;
    p->rJD += r;
  }
  decomposeDate(p, mode);
  return 1;
}


................................................................................
    sqlite_set_result_double(context, x.rJD);
  }
}
static void timestampFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 3) ){
    char zBuf[100];
    sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m, x.s);

    sqlite_set_result_string(context, zBuf, -1);
  }
}
static void timeFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    char zBuf[100];
    sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, x.s);
    sqlite_set_result_string(context, zBuf, -1);
  }
}
static void dateFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 1) ){
    char zBuf[100];
................................................................................
  if( isDate(argc, argv, &x, 1) ){
    sqlite_set_result_int(context, x.D);
  }
}
static void secondFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_int(context, x.s);
  }
}
static void minuteFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_int(context, x.m);
  }
................................................................................
}
static void hourFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_int(context, x.h);
  }
}










#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
/***************************************************************************/

/*
** This function registered all of the above C functions as SQL
** functions.  This should be the only routine in this file with
** external linkage.
................................................................................
    { "like",       2, SQLITE_NUMERIC, likeFunc   },
    { "glob",       2, SQLITE_NUMERIC, globFunc   },
    { "nullif",     2, SQLITE_ARGS,    nullifFunc },
    { "sqlite_version",0,SQLITE_TEXT,  versionFunc},
    { "quote",      1, SQLITE_ARGS,    quoteFunc  },
#ifndef SQLITE_OMIT_DATETIME_FUNCS
    { "julianday", -1, SQLITE_NUMERIC, juliandayFunc   },


    { "timestamp", -1, SQLITE_TEXT,    timestampFunc   },
    { "time",      -1, SQLITE_TEXT,    timeFunc        },
    { "date",      -1, SQLITE_TEXT,    dateFunc        },
    { "year",      -1, SQLITE_NUMERIC, yearFunc        },
    { "month",     -1, SQLITE_NUMERIC, monthFunc       },
    { "dayofmonth",-1, SQLITE_NUMERIC, dayofmonthFunc  },
    { "dayofweek", -1, SQLITE_NUMERIC, dayofweekFunc   },







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>

>
>
>
>
>
>



|
>










>
>
>
>
>
>
>
>
>



|
|







 







<
<
|
<
<


>
>
>
>
>
>
>
>
>
>
>

|





|
>
>







 







|
>







 







|
>
|
>
>
|
|
<
>







 







|







 







|
>







|







 







|







 







>
>
>
>
>
>
>
>
>
>







 







>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627

628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
...
717
718
719
720
721
722
723


724


725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
...
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
...
789
790
791
792
793
794
795
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810
...
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
...
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
...
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
...
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.32 2003/10/10 02:09:57 drh Exp $
*/
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "sqliteInt.h"
#include "os.h"
................................................................................
    val = val*10 + *zDate - '0';
    zDate++;
  }
  return val;
}

/*
** Parse a timezone extension on the end of a datetime stamp.
** The extension is of the form:
**
**        (+/-)HH:MM
**
** If the parse is successful, write the number of minutes
** of change in *pnMin and return 0.  If a parser error occurs,
** return 0.
**
** A missing specifier is not considered an error.
*/
static int parseTimezone(const char *zDate, int *pnMin){
  int sgn = 0;
  int nHr, nMn;
  while( isspace(*zDate) ){ zDate++; }
  *pnMin = 0;
  if( *zDate=='-' ){
    sgn = -1;
  }else if( *zDate=='+' ){
    sgn = +1;
  }else{
    return *zDate!=0;
  }
  zDate++;
  nHr = getDigits(zDate, 2);
  if( nHr<0 || nHr>14 ) return 1;
  zDate += 2;
  if( zDate[0]!=':' ) return 1;
  zDate++;
  nMn = getDigits(zDate, 2);
  if( nMn<0 || nMn>59 ) return 1;
  zDate += 2;
  *pnMin = sgn*(nMn + nHr*60);
  while( isspace(*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.
**
** The time string can be followed by an optional timezone specifier
** of the following form:  (+/-)HH:MM.
**
** Whatever the format, the string is converted into a julian
** day number and stored in *prJD.
**
** Return 1 if there is a parsing error and 0 on success.
*/
static int parseHhMmSs(const char *zDate, double *prJD){
  int h, m, s, tz;
  double ms = 0.0;
  h = getDigits(zDate, 2);
  if( h<0 || zDate[2]!=':' ) return 1;
  zDate += 3;
  m = getDigits(zDate, 2);
  if( m<0 || m>59 ) return 1;
  zDate += 2;
  if( *zDate==':' ){
    s = getDigits(&zDate[1], 2);
    if( s<0 || s>59 ) return 1;
    zDate += 3;
    if( *zDate=='.' && isdigit(zDate[1]) ){
      double rScale = 1.0/864000.0;
      zDate++;
      while( isdigit(*zDate) ){
        ms += rScale * (*zDate - '0');
        rScale *= 0.1;
        zDate++;
      }
    }
  }else{
    s = 0;
  }
  if( parseTimezone(zDate, &tz) ) return 1;
  *prJD = (h*3600.0 + (m+tz)*60.0 + s)/86400.0 + ms;
  return 0;
}

/*
** Parse dates of the form
**
**     YYYY-MM-DD HH:MM:SS
................................................................................

/*
** Attempt to parse the given string into a Julian Day Number.  Return
** the number of errors.
**
** The following are acceptable forms for the input string:
**


**      YYYY-MM-DD HH:MM:SS.FFF  +/-HH:MM


**      DDDD.DD 
**      now
**
** 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.
**
** If the bRelative flag is set and the format is HH:MM or HH:MM:SS then
** make the result is relative to midnight instead of noon.  In other words,
** if bRelative is true, "00:00:00" parses to 0.0 but if bRelative is
** false, "00:00:00" parses to 0.5.
*/
static int parseDateOrTime(const char *zDate, int bRelative, double *prJD){
  int i;
  for(i=0; isdigit(zDate[i]); i++){}
  if( i==4 && zDate[i]=='-' ){
    return parseYyyyMmDd(zDate, prJD);
  }else if( i==2 && zDate[i]==':' ){
    if( parseHhMmSs(zDate, prJD) ) return 1;
    if( !bRelative ) *prJD += 2451544.5;
    return 0;
  }else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){
    return sqliteOsCurrentTime(prJD);
  }else if( sqliteIsNumber(zDate) ){
    *prJD = atof(zDate);
    return 0;
  }
  return 1;
................................................................................
/*
** A structure for holding date and time.
*/
typedef struct DateTime DateTime;
struct DateTime {
  double rJD;    /* The julian day number */
  int Y, M, D;   /* Year, month, and day */
  int h, m;      /* Hour and minutes */
  double s;      /* Seconds */
};

/*
** Break up a julian day number into year, month, day, hour, minute, second.
** This function assume the Gregorian calendar - even for dates prior
** to the invention of the Gregorian calendar in 1582.
**
................................................................................
    E = (B-D)/30.6001;
    X1 = 30.6001*E;
    p->D = B - D - X1;
    p->M = E<14 ? E-1 : E-13;
    p->Y = p->M>2 ? C - 4716 : C - 4715;
  }
  if( mode & 2 ){
    int s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
    p->s = 0.001*s;
    s = p->s;
    p->s -= s;
    p->h = s/3600;
    s -= p->h*3600;
    p->m = s/60;

    p->s += s - p->m*60;
  }
}

/*
** Check to see that all arguments are valid date strings.  If any 
** argument is not a valid date string, return 0.  If all arguments
** are valid, return 1 and write into *p->rJD the sum of the julian day
................................................................................
*/
static int isDate(int argc, const char **argv, DateTime *p, int mode){
  double r;
  int i;
  p->rJD = 0.0;
  for(i=0; i<argc; i++){
    if( argv[i]==0 ) return 0;
    if( parseDateOrTime(argv[i], i, &r) ) return 0;
    p->rJD += r;
  }
  decomposeDate(p, mode);
  return 1;
}


................................................................................
    sqlite_set_result_double(context, x.rJD);
  }
}
static void timestampFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 3) ){
    char zBuf[100];
    sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
           (int)(x.s+0.5));
    sqlite_set_result_string(context, zBuf, -1);
  }
}
static void timeFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    char zBuf[100];
    sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)(x.s+0.5));
    sqlite_set_result_string(context, zBuf, -1);
  }
}
static void dateFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 1) ){
    char zBuf[100];
................................................................................
  if( isDate(argc, argv, &x, 1) ){
    sqlite_set_result_int(context, x.D);
  }
}
static void secondFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_double(context, x.s);
  }
}
static void minuteFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_int(context, x.m);
  }
................................................................................
}
static void hourFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 2) ){
    sqlite_set_result_int(context, x.h);
  }
}
static void unixToJdFunc(sqlite_func *context, int argc, const char **argv){
  sqlite_set_result_double(context, atof(argv[0])/(24.0*3600.0)+2440587.5);
}
static void unixtimeFunc(sqlite_func *context, int argc, const char **argv){
  DateTime x;
  if( isDate(argc, argv, &x, 0) ){
    sqlite_set_result_double(context, (x.rJD-2440587.5)*24.0*3600.0);
  }
}

#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
/***************************************************************************/

/*
** This function registered all of the above C functions as SQL
** functions.  This should be the only routine in this file with
** external linkage.
................................................................................
    { "like",       2, SQLITE_NUMERIC, likeFunc   },
    { "glob",       2, SQLITE_NUMERIC, globFunc   },
    { "nullif",     2, SQLITE_ARGS,    nullifFunc },
    { "sqlite_version",0,SQLITE_TEXT,  versionFunc},
    { "quote",      1, SQLITE_ARGS,    quoteFunc  },
#ifndef SQLITE_OMIT_DATETIME_FUNCS
    { "julianday", -1, SQLITE_NUMERIC, juliandayFunc   },
    { "unixtime",  -1, SQLITE_NUMERIC, unixtimeFunc    },
    { "unix_to_jd", 1, SQLITE_NUMERIC, unixToJdFunc    },
    { "timestamp", -1, SQLITE_TEXT,    timestampFunc   },
    { "time",      -1, SQLITE_TEXT,    timeFunc        },
    { "date",      -1, SQLITE_TEXT,    dateFunc        },
    { "year",      -1, SQLITE_NUMERIC, yearFunc        },
    { "month",     -1, SQLITE_NUMERIC, monthFunc       },
    { "dayofmonth",-1, SQLITE_NUMERIC, dayofmonthFunc  },
    { "dayofweek", -1, SQLITE_NUMERIC, dayofweekFunc   },

Changes to src/vdbeaux.c.

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  sqlite_set_result_string(p, zMsg, n);
  p->isError = 1;
}

/*
** Extract the user data from a sqlite_func structure and return a
** pointer to it.
**
** This routine is defined here in vdbe.c because it depends on knowing
** the internals of the sqlite_func structure which is only defined in 
** this source file.
*/
void *sqlite_user_data(sqlite_func *p){
  assert( p && p->pFunc );
  return p->pFunc->pUserData;
}

/*







<
<
<
<







419
420
421
422
423
424
425




426
427
428
429
430
431
432
  sqlite_set_result_string(p, zMsg, n);
  p->isError = 1;
}

/*
** Extract the user data from a sqlite_func structure and return a
** pointer to it.




*/
void *sqlite_user_data(sqlite_func *p){
  assert( p && p->pFunc );
  return p->pFunc->pUserData;
}

/*