From: drh Date: Sun, 10 Aug 2003 01:50:54 +0000 (+0000) Subject: tighter coding of the date and time functions. Better comments. A bug fix. (CVS... X-Git-Tag: version-3.6.10~4998 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=87adaa9a99553fa736e1d483a847f016c4b7e333;p=thirdparty%2Fsqlite.git tighter coding of the date and time functions. Better comments. A bug fix. (CVS 1070) FossilOrigin-Name: 94243edac14b90ef898093b85e1959c20fa23ae9 --- diff --git a/manifest b/manifest index 2ed24abefa..1137fa12c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sexperimental\sdate\sand\stime\sfunctions\sbased\son\sjulian\sday\snumber.\s(CVS\s1069) -D 2003-08-09T21:32:28 +C tighter\scoding\sof\sthe\sdate\sand\stime\sfunctions.\s\sBetter\scomments.\s\sA\sbug\sfix.\s(CVS\s1070) +D 2003-08-10T01:50:55 F Makefile.in 9ad23ed4ca97f9670c4496432e3fbd4b3760ebde F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -29,7 +29,7 @@ F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73 F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc F src/encode.c 25ea901a9cefb3d93774afa4a06b57cb58acf544 F src/expr.c 03c321ac66c1e998c2e0faf22184b5a808b559ca -F src/func.c 67b66803d8a8b33dfea64ef54835d8b1d43c9f20 +F src/func.c 2b196fdca328838c0c02f290ec833d05d63d7a32 F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c dc200ae04a36bd36e575272a069e20c528b7fbdf @@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 086aa1c9922b7bf399b3ee8b73ba7353d126b119 -R b633d80bd522667187e3193065550fbf +P a6197e2075fdf9db862484255ac16b2855bbef0a +R 2c17b8788ba63ebf744e79cd8d1dc806 U drh -Z 4776791846cfff06b30527d77321657f +Z 001852bd03c4d150dde8de11d7257985 diff --git a/manifest.uuid b/manifest.uuid index eaf7f93b2f..bf0489fb58 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a6197e2075fdf9db862484255ac16b2855bbef0a \ No newline at end of file +94243edac14b90ef898093b85e1959c20fa23ae9 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 10f0e08905..1eb24436dc 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.27 2003/08/09 21:32:28 drh Exp $ +** $Id: func.c,v 1.28 2003/08/10 01:50:55 drh Exp $ */ #include #include @@ -503,14 +503,16 @@ static void minMaxFinalize(sqlite_func *context){ ** ** 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 January 01, 4713 B.C. (a.k.a -4713-01-01 12:00:00) +** in Greenwich on November 24, 4714 B.C. according to the Gregorian +** calendar system. +** ** This implement requires years to be expressed as a 4-digit number ** which means that only dates between 0000-01-01 and 9999-12-31 can ** be represented, even though julian day numbers allow a much wider ** range of dates. ** ** The Gregorian calendar system is used for all dates and times, -** even those that predate the Gregorian calendar. Historians often +** even those that predate the Gregorian calendar. Historians usually ** use the Julian calendar for dates prior to 1582-10-15 and for some ** dates afterwards, depending on locale. Beware of this difference. ** @@ -540,7 +542,7 @@ static int getDigits(const char *zDate, int N){ } /* -** Parse dates of the form HH:MM:SS or HH:MM. Store the +** 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. @@ -645,160 +647,152 @@ static int parseDateOrTime(const char *zDate, double *prJD){ } /* -** Break up a julian day number into year, month, day, and seconds. +** 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. ** ** See Meeus page 63. +** +** If mode==1 only the year, month, and day are computed. If mode==2 +** then only the hour, minute, and second are computed. If mode==3 then +** everything is computed. If mode==0, this routine is a no-op. +*/ +static void decomposeDate(DateTime *p, int mode){ + int Z; + Z = p->rJD + 0.5; + if( mode & 1 ){ + int A, B, C, D, E, X1; + A = (Z - 1867216.25)/36524.25; + A = Z + 1 + A - (A/4); + B = A + 1524; + C = (B - 122.1)/365.25; + D = 365.25*C; + 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 +** numbers for all date strings. +** +** A "valid" date string is one that is accepted by parseDateOrTime(). +** +** The mode argument is passed through to decomposeDate() in order to +** fill in the year, month, day, hour, minute, and second of the *p +** structure, if desired. */ -static void decomposeDate(double JD, int *pY, int *pM, int *pD, int *pS){ - int Z, A, B, C, D, E, X1; - Z = JD + 0.5; - A = (Z - 1867216.25)/36524.25; - A = Z + 1 + A - (A/4); - B = A + 1524; - C = (B - 122.1)/365.25; - D = 365.25*C; - E = (B-D)/30.6001; - X1 = 30.6001*E; - *pD = B - D - X1; - *pM = E<14 ? E-1 : E-13; - *pY = *pD>2 ? C - 4716 : C - 4715; - *pS = (JD + 0.5 - Z)*86400.0; -} - -/* -** Check to see that all arguments are valid date strings. If any is -** not a valid date string, return 0. If all are valid, return 1. -** Write into *prJD the sum of the julian day numbers for all date -** strings. -*/ -static int isDate( - sqlite_func *context, - int argc, - const char **argv, - double *prJD -){ +static int isDate(int argc, const char **argv, DateTime *p, int mode){ double r; int i; - *prJD = 0.0; + p->rJD = 0.0; for(i=0; irJD += r; } + decomposeDate(p, mode); return 1; } + /* ** The following routines implement the various date and time functions ** of SQLite. */ static void juliandayFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - sqlite_set_result_double(context, JD); + DateTime x; + if( isDate(argc, argv, &x, 0) ){ + sqlite_set_result_double(context, x.rJD); } } static void timestampFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, h, m, s; + DateTime x; + if( isDate(argc, argv, &x, 3) ){ char zBuf[100]; - decomposeDate(JD, &Y, &M, &D, &s); - h = s/3600; - s -= h*3600; - m = s/60; - s -= m*60; - sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d", Y, M, D, h, m, s); + 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){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, h, m, s; + DateTime x; + if( isDate(argc, argv, &x, 2) ){ char zBuf[100]; - decomposeDate(JD, &Y, &M, &D, &s); - h = s/3600; - s -= h*3600; - m = s/60; - s -= m*60; - sprintf(zBuf, "%02d:%02d:%02d", h, m, s); + 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){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, s; + DateTime x; + if( isDate(argc, argv, &x, 1) ){ char zBuf[100]; - decomposeDate(JD, &Y, &M, &D, &s); - sprintf(zBuf, "%04d-%02d-%02d", Y, M, D); + sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); sqlite_set_result_string(context, zBuf, -1); } } static void yearFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, s; - decomposeDate(JD, &Y, &M, &D, &s); - sqlite_set_result_int(context, Y); + DateTime x; + if( isDate(argc, argv, &x, 1) ){ + sqlite_set_result_int(context, x.Y); } } static void monthFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, s; - decomposeDate(JD, &Y, &M, &D, &s); - sqlite_set_result_int(context, M); + DateTime x; + if( isDate(argc, argv, &x, 1) ){ + sqlite_set_result_int(context, x.M); } } static void dayofweekFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Z = JD + 1.5; + DateTime x; + if( isDate(argc, argv, &x, 0) ){ + int Z = x.rJD + 1.5; sqlite_set_result_int(context, Z % 7); } } static void dayofmonthFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, s; - decomposeDate(JD, &Y, &M, &D, &s); - sqlite_set_result_int(context, D); + DateTime x; + if( isDate(argc, argv, &x, 1) ){ + sqlite_set_result_int(context, x.D); } } static void secondFunc(sqlite_func *context, int argc, const char **argv){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, h, m, s; - decomposeDate(JD, &Y, &M, &D, &s); - h = s/3600; - s -= h*3600; - m = s/60; - s -= m*60; - sqlite_set_result_int(context, s); + 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){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, h, m, s; - decomposeDate(JD, &Y, &M, &D, &s); - h = s/3600; - s -= h*3600; - m = s/60; - sqlite_set_result_int(context, m); + 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){ - double JD; - if( isDate(context, argc, argv, &JD) ){ - int Y, M, D, h, s; - decomposeDate(JD, &Y, &M, &D, &s); - h = s/3600; - sqlite_set_result_int(context, h); + DateTime x; + if( isDate(argc, argv, &x, 2) ){ + sqlite_set_result_int(context, x.h); } } #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */