xref: /illumos-gate/usr/src/lib/libsqlite/src/date.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate ** 2003 October 31
37c478bd9Sstevel@tonic-gate **
47c478bd9Sstevel@tonic-gate ** The author disclaims copyright to this source code.  In place of
57c478bd9Sstevel@tonic-gate ** a legal notice, here is a blessing:
67c478bd9Sstevel@tonic-gate **
77c478bd9Sstevel@tonic-gate **    May you do good and not evil.
87c478bd9Sstevel@tonic-gate **    May you find forgiveness for yourself and forgive others.
97c478bd9Sstevel@tonic-gate **    May you share freely, never taking more than you give.
107c478bd9Sstevel@tonic-gate **
117c478bd9Sstevel@tonic-gate *************************************************************************
127c478bd9Sstevel@tonic-gate ** This file contains the C functions that implement date and time
13*1da57d55SToomas Soome ** functions for SQLite.
147c478bd9Sstevel@tonic-gate **
157c478bd9Sstevel@tonic-gate ** There is only one exported symbol in this file - the function
167c478bd9Sstevel@tonic-gate ** sqliteRegisterDateTimeFunctions() found at the bottom of the file.
177c478bd9Sstevel@tonic-gate ** All other code has file scope.
187c478bd9Sstevel@tonic-gate **
197c478bd9Sstevel@tonic-gate ** $Id: date.c,v 1.16.2.2 2004/07/20 00:40:01 drh Exp $
207c478bd9Sstevel@tonic-gate **
217c478bd9Sstevel@tonic-gate ** NOTES:
227c478bd9Sstevel@tonic-gate **
237c478bd9Sstevel@tonic-gate ** SQLite processes all times and dates as Julian Day numbers.  The
247c478bd9Sstevel@tonic-gate ** dates and times are stored as the number of days since noon
257c478bd9Sstevel@tonic-gate ** in Greenwich on November 24, 4714 B.C. according to the Gregorian
267c478bd9Sstevel@tonic-gate ** calendar system.
277c478bd9Sstevel@tonic-gate **
287c478bd9Sstevel@tonic-gate ** 1970-01-01 00:00:00 is JD 2440587.5
297c478bd9Sstevel@tonic-gate ** 2000-01-01 00:00:00 is JD 2451544.5
307c478bd9Sstevel@tonic-gate **
317c478bd9Sstevel@tonic-gate ** This implemention requires years to be expressed as a 4-digit number
327c478bd9Sstevel@tonic-gate ** which means that only dates between 0000-01-01 and 9999-12-31 can
337c478bd9Sstevel@tonic-gate ** be represented, even though julian day numbers allow a much wider
347c478bd9Sstevel@tonic-gate ** range of dates.
357c478bd9Sstevel@tonic-gate **
367c478bd9Sstevel@tonic-gate ** The Gregorian calendar system is used for all dates and times,
377c478bd9Sstevel@tonic-gate ** even those that predate the Gregorian calendar.  Historians usually
387c478bd9Sstevel@tonic-gate ** use the Julian calendar for dates prior to 1582-10-15 and for some
397c478bd9Sstevel@tonic-gate ** dates afterwards, depending on locale.  Beware of this difference.
407c478bd9Sstevel@tonic-gate **
417c478bd9Sstevel@tonic-gate ** The conversion algorithms are implemented based on descriptions
427c478bd9Sstevel@tonic-gate ** in the following text:
437c478bd9Sstevel@tonic-gate **
447c478bd9Sstevel@tonic-gate **      Jean Meeus
457c478bd9Sstevel@tonic-gate **      Astronomical Algorithms, 2nd Edition, 1998
467c478bd9Sstevel@tonic-gate **      ISBM 0-943396-61-1
477c478bd9Sstevel@tonic-gate **      Willmann-Bell, Inc
487c478bd9Sstevel@tonic-gate **      Richmond, Virginia (USA)
497c478bd9Sstevel@tonic-gate */
507c478bd9Sstevel@tonic-gate #include "os.h"
517c478bd9Sstevel@tonic-gate #include "sqliteInt.h"
527c478bd9Sstevel@tonic-gate #include <ctype.h>
537c478bd9Sstevel@tonic-gate #include <stdlib.h>
547c478bd9Sstevel@tonic-gate #include <assert.h>
557c478bd9Sstevel@tonic-gate #include <time.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_DATETIME_FUNCS
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate ** A structure for holding a single date and time.
617c478bd9Sstevel@tonic-gate */
627c478bd9Sstevel@tonic-gate typedef struct DateTime DateTime;
637c478bd9Sstevel@tonic-gate struct DateTime {
647c478bd9Sstevel@tonic-gate   double rJD;      /* The julian day number */
657c478bd9Sstevel@tonic-gate   int Y, M, D;     /* Year, month, and day */
667c478bd9Sstevel@tonic-gate   int h, m;        /* Hour and minutes */
677c478bd9Sstevel@tonic-gate   int tz;          /* Timezone offset in minutes */
687c478bd9Sstevel@tonic-gate   double s;        /* Seconds */
697c478bd9Sstevel@tonic-gate   char validYMD;   /* True if Y,M,D are valid */
707c478bd9Sstevel@tonic-gate   char validHMS;   /* True if h,m,s are valid */
717c478bd9Sstevel@tonic-gate   char validJD;    /* True if rJD is valid */
727c478bd9Sstevel@tonic-gate   char validTZ;    /* True if tz is valid */
737c478bd9Sstevel@tonic-gate };
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate ** Convert zDate into one or more integers.  Additional arguments
787c478bd9Sstevel@tonic-gate ** come in groups of 5 as follows:
797c478bd9Sstevel@tonic-gate **
807c478bd9Sstevel@tonic-gate **       N       number of digits in the integer
817c478bd9Sstevel@tonic-gate **       min     minimum allowed value of the integer
827c478bd9Sstevel@tonic-gate **       max     maximum allowed value of the integer
837c478bd9Sstevel@tonic-gate **       nextC   first character after the integer
847c478bd9Sstevel@tonic-gate **       pVal    where to write the integers value.
857c478bd9Sstevel@tonic-gate **
867c478bd9Sstevel@tonic-gate ** Conversions continue until one with nextC==0 is encountered.
877c478bd9Sstevel@tonic-gate ** The function returns the number of successful conversions.
887c478bd9Sstevel@tonic-gate */
getDigits(const char * zDate,...)897c478bd9Sstevel@tonic-gate static int getDigits(const char *zDate, ...){
907c478bd9Sstevel@tonic-gate   va_list ap;
917c478bd9Sstevel@tonic-gate   int val;
927c478bd9Sstevel@tonic-gate   int N;
937c478bd9Sstevel@tonic-gate   int min;
947c478bd9Sstevel@tonic-gate   int max;
957c478bd9Sstevel@tonic-gate   int nextC;
967c478bd9Sstevel@tonic-gate   int *pVal;
977c478bd9Sstevel@tonic-gate   int cnt = 0;
987c478bd9Sstevel@tonic-gate   va_start(ap, zDate);
997c478bd9Sstevel@tonic-gate   do{
1007c478bd9Sstevel@tonic-gate     N = va_arg(ap, int);
1017c478bd9Sstevel@tonic-gate     min = va_arg(ap, int);
1027c478bd9Sstevel@tonic-gate     max = va_arg(ap, int);
1037c478bd9Sstevel@tonic-gate     nextC = va_arg(ap, int);
1047c478bd9Sstevel@tonic-gate     pVal = va_arg(ap, int*);
1057c478bd9Sstevel@tonic-gate     val = 0;
1067c478bd9Sstevel@tonic-gate     while( N-- ){
1077c478bd9Sstevel@tonic-gate       if( !isdigit(*zDate) ){
1087c478bd9Sstevel@tonic-gate         return cnt;
1097c478bd9Sstevel@tonic-gate       }
1107c478bd9Sstevel@tonic-gate       val = val*10 + *zDate - '0';
1117c478bd9Sstevel@tonic-gate       zDate++;
1127c478bd9Sstevel@tonic-gate     }
1137c478bd9Sstevel@tonic-gate     if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
1147c478bd9Sstevel@tonic-gate       return cnt;
1157c478bd9Sstevel@tonic-gate     }
1167c478bd9Sstevel@tonic-gate     *pVal = val;
1177c478bd9Sstevel@tonic-gate     zDate++;
1187c478bd9Sstevel@tonic-gate     cnt++;
1197c478bd9Sstevel@tonic-gate   }while( nextC );
1207c478bd9Sstevel@tonic-gate   return cnt;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate ** Read text from z[] and convert into a floating point number.  Return
1257c478bd9Sstevel@tonic-gate ** the number of digits converted.
1267c478bd9Sstevel@tonic-gate */
getValue(const char * z,double * pR)1277c478bd9Sstevel@tonic-gate static int getValue(const char *z, double *pR){
1287c478bd9Sstevel@tonic-gate   const char *zEnd;
1297c478bd9Sstevel@tonic-gate   *pR = sqliteAtoF(z, &zEnd);
1307c478bd9Sstevel@tonic-gate   return zEnd - z;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate ** Parse a timezone extension on the end of a date-time.
1357c478bd9Sstevel@tonic-gate ** The extension is of the form:
1367c478bd9Sstevel@tonic-gate **
1377c478bd9Sstevel@tonic-gate **        (+/-)HH:MM
1387c478bd9Sstevel@tonic-gate **
1397c478bd9Sstevel@tonic-gate ** If the parse is successful, write the number of minutes
1407c478bd9Sstevel@tonic-gate ** of change in *pnMin and return 0.  If a parser error occurs,
1417c478bd9Sstevel@tonic-gate ** return 0.
1427c478bd9Sstevel@tonic-gate **
1437c478bd9Sstevel@tonic-gate ** A missing specifier is not considered an error.
1447c478bd9Sstevel@tonic-gate */
parseTimezone(const char * zDate,DateTime * p)1457c478bd9Sstevel@tonic-gate static int parseTimezone(const char *zDate, DateTime *p){
1467c478bd9Sstevel@tonic-gate   int sgn = 0;
1477c478bd9Sstevel@tonic-gate   int nHr, nMn;
1487c478bd9Sstevel@tonic-gate   while( isspace(*zDate) ){ zDate++; }
1497c478bd9Sstevel@tonic-gate   p->tz = 0;
1507c478bd9Sstevel@tonic-gate   if( *zDate=='-' ){
1517c478bd9Sstevel@tonic-gate     sgn = -1;
1527c478bd9Sstevel@tonic-gate   }else if( *zDate=='+' ){
1537c478bd9Sstevel@tonic-gate     sgn = +1;
1547c478bd9Sstevel@tonic-gate   }else{
1557c478bd9Sstevel@tonic-gate     return *zDate!=0;
1567c478bd9Sstevel@tonic-gate   }
1577c478bd9Sstevel@tonic-gate   zDate++;
1587c478bd9Sstevel@tonic-gate   if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
1597c478bd9Sstevel@tonic-gate     return 1;
1607c478bd9Sstevel@tonic-gate   }
1617c478bd9Sstevel@tonic-gate   zDate += 5;
1627c478bd9Sstevel@tonic-gate   p->tz = sgn*(nMn + nHr*60);
1637c478bd9Sstevel@tonic-gate   while( isspace(*zDate) ){ zDate++; }
1647c478bd9Sstevel@tonic-gate   return *zDate!=0;
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate ** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
1697c478bd9Sstevel@tonic-gate ** The HH, MM, and SS must each be exactly 2 digits.  The
1707c478bd9Sstevel@tonic-gate ** fractional seconds FFFF can be one or more digits.
1717c478bd9Sstevel@tonic-gate **
1727c478bd9Sstevel@tonic-gate ** Return 1 if there is a parsing error and 0 on success.
1737c478bd9Sstevel@tonic-gate */
parseHhMmSs(const char * zDate,DateTime * p)1747c478bd9Sstevel@tonic-gate static int parseHhMmSs(const char *zDate, DateTime *p){
1757c478bd9Sstevel@tonic-gate   int h, m, s;
1767c478bd9Sstevel@tonic-gate   double ms = 0.0;
1777c478bd9Sstevel@tonic-gate   if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
1787c478bd9Sstevel@tonic-gate     return 1;
1797c478bd9Sstevel@tonic-gate   }
1807c478bd9Sstevel@tonic-gate   zDate += 5;
1817c478bd9Sstevel@tonic-gate   if( *zDate==':' ){
1827c478bd9Sstevel@tonic-gate     zDate++;
1837c478bd9Sstevel@tonic-gate     if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
1847c478bd9Sstevel@tonic-gate       return 1;
1857c478bd9Sstevel@tonic-gate     }
1867c478bd9Sstevel@tonic-gate     zDate += 2;
1877c478bd9Sstevel@tonic-gate     if( *zDate=='.' && isdigit(zDate[1]) ){
1887c478bd9Sstevel@tonic-gate       double rScale = 1.0;
1897c478bd9Sstevel@tonic-gate       zDate++;
1907c478bd9Sstevel@tonic-gate       while( isdigit(*zDate) ){
1917c478bd9Sstevel@tonic-gate         ms = ms*10.0 + *zDate - '0';
1927c478bd9Sstevel@tonic-gate         rScale *= 10.0;
1937c478bd9Sstevel@tonic-gate         zDate++;
1947c478bd9Sstevel@tonic-gate       }
1957c478bd9Sstevel@tonic-gate       ms /= rScale;
1967c478bd9Sstevel@tonic-gate     }
1977c478bd9Sstevel@tonic-gate   }else{
1987c478bd9Sstevel@tonic-gate     s = 0;
1997c478bd9Sstevel@tonic-gate   }
2007c478bd9Sstevel@tonic-gate   p->validJD = 0;
2017c478bd9Sstevel@tonic-gate   p->validHMS = 1;
2027c478bd9Sstevel@tonic-gate   p->h = h;
2037c478bd9Sstevel@tonic-gate   p->m = m;
2047c478bd9Sstevel@tonic-gate   p->s = s + ms;
2057c478bd9Sstevel@tonic-gate   if( parseTimezone(zDate, p) ) return 1;
2067c478bd9Sstevel@tonic-gate   p->validTZ = p->tz!=0;
2077c478bd9Sstevel@tonic-gate   return 0;
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate ** Convert from YYYY-MM-DD HH:MM:SS to julian day.  We always assume
2127c478bd9Sstevel@tonic-gate ** that the YYYY-MM-DD is according to the Gregorian calendar.
2137c478bd9Sstevel@tonic-gate **
2147c478bd9Sstevel@tonic-gate ** Reference:  Meeus page 61
2157c478bd9Sstevel@tonic-gate */
computeJD(DateTime * p)2167c478bd9Sstevel@tonic-gate static void computeJD(DateTime *p){
2177c478bd9Sstevel@tonic-gate   int Y, M, D, A, B, X1, X2;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate   if( p->validJD ) return;
2207c478bd9Sstevel@tonic-gate   if( p->validYMD ){
2217c478bd9Sstevel@tonic-gate     Y = p->Y;
2227c478bd9Sstevel@tonic-gate     M = p->M;
2237c478bd9Sstevel@tonic-gate     D = p->D;
2247c478bd9Sstevel@tonic-gate   }else{
2257c478bd9Sstevel@tonic-gate     Y = 2000;  /* If no YMD specified, assume 2000-Jan-01 */
2267c478bd9Sstevel@tonic-gate     M = 1;
2277c478bd9Sstevel@tonic-gate     D = 1;
2287c478bd9Sstevel@tonic-gate   }
2297c478bd9Sstevel@tonic-gate   if( M<=2 ){
2307c478bd9Sstevel@tonic-gate     Y--;
2317c478bd9Sstevel@tonic-gate     M += 12;
2327c478bd9Sstevel@tonic-gate   }
2337c478bd9Sstevel@tonic-gate   A = Y/100;
2347c478bd9Sstevel@tonic-gate   B = 2 - A + (A/4);
2357c478bd9Sstevel@tonic-gate   X1 = 365.25*(Y+4716);
2367c478bd9Sstevel@tonic-gate   X2 = 30.6001*(M+1);
2377c478bd9Sstevel@tonic-gate   p->rJD = X1 + X2 + D + B - 1524.5;
2387c478bd9Sstevel@tonic-gate   p->validJD = 1;
2397c478bd9Sstevel@tonic-gate   p->validYMD = 0;
2407c478bd9Sstevel@tonic-gate   if( p->validHMS ){
2417c478bd9Sstevel@tonic-gate     p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
2427c478bd9Sstevel@tonic-gate     if( p->validTZ ){
2437c478bd9Sstevel@tonic-gate       p->rJD += p->tz*60/86400.0;
2447c478bd9Sstevel@tonic-gate       p->validHMS = 0;
2457c478bd9Sstevel@tonic-gate       p->validTZ = 0;
2467c478bd9Sstevel@tonic-gate     }
2477c478bd9Sstevel@tonic-gate   }
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate ** Parse dates of the form
2527c478bd9Sstevel@tonic-gate **
2537c478bd9Sstevel@tonic-gate **     YYYY-MM-DD HH:MM:SS.FFF
2547c478bd9Sstevel@tonic-gate **     YYYY-MM-DD HH:MM:SS
2557c478bd9Sstevel@tonic-gate **     YYYY-MM-DD HH:MM
2567c478bd9Sstevel@tonic-gate **     YYYY-MM-DD
2577c478bd9Sstevel@tonic-gate **
2587c478bd9Sstevel@tonic-gate ** Write the result into the DateTime structure and return 0
2597c478bd9Sstevel@tonic-gate ** on success and 1 if the input string is not a well-formed
2607c478bd9Sstevel@tonic-gate ** date.
2617c478bd9Sstevel@tonic-gate */
parseYyyyMmDd(const char * zDate,DateTime * p)2627c478bd9Sstevel@tonic-gate static int parseYyyyMmDd(const char *zDate, DateTime *p){
2637c478bd9Sstevel@tonic-gate   int Y, M, D, neg;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate   if( zDate[0]=='-' ){
2667c478bd9Sstevel@tonic-gate     zDate++;
2677c478bd9Sstevel@tonic-gate     neg = 1;
2687c478bd9Sstevel@tonic-gate   }else{
2697c478bd9Sstevel@tonic-gate     neg = 0;
2707c478bd9Sstevel@tonic-gate   }
2717c478bd9Sstevel@tonic-gate   if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
2727c478bd9Sstevel@tonic-gate     return 1;
2737c478bd9Sstevel@tonic-gate   }
2747c478bd9Sstevel@tonic-gate   zDate += 10;
2757c478bd9Sstevel@tonic-gate   while( isspace(*zDate) ){ zDate++; }
2767c478bd9Sstevel@tonic-gate   if( parseHhMmSs(zDate, p)==0 ){
2777c478bd9Sstevel@tonic-gate     /* We got the time */
2787c478bd9Sstevel@tonic-gate   }else if( *zDate==0 ){
2797c478bd9Sstevel@tonic-gate     p->validHMS = 0;
2807c478bd9Sstevel@tonic-gate   }else{
2817c478bd9Sstevel@tonic-gate     return 1;
2827c478bd9Sstevel@tonic-gate   }
2837c478bd9Sstevel@tonic-gate   p->validJD = 0;
2847c478bd9Sstevel@tonic-gate   p->validYMD = 1;
2857c478bd9Sstevel@tonic-gate   p->Y = neg ? -Y : Y;
2867c478bd9Sstevel@tonic-gate   p->M = M;
2877c478bd9Sstevel@tonic-gate   p->D = D;
2887c478bd9Sstevel@tonic-gate   if( p->validTZ ){
2897c478bd9Sstevel@tonic-gate     computeJD(p);
2907c478bd9Sstevel@tonic-gate   }
2917c478bd9Sstevel@tonic-gate   return 0;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate ** Attempt to parse the given string into a Julian Day Number.  Return
2967c478bd9Sstevel@tonic-gate ** the number of errors.
2977c478bd9Sstevel@tonic-gate **
2987c478bd9Sstevel@tonic-gate ** The following are acceptable forms for the input string:
2997c478bd9Sstevel@tonic-gate **
3007c478bd9Sstevel@tonic-gate **      YYYY-MM-DD HH:MM:SS.FFF  +/-HH:MM
301*1da57d55SToomas Soome **      DDDD.DD
3027c478bd9Sstevel@tonic-gate **      now
3037c478bd9Sstevel@tonic-gate **
3047c478bd9Sstevel@tonic-gate ** In the first form, the +/-HH:MM is always optional.  The fractional
3057c478bd9Sstevel@tonic-gate ** seconds extension (the ".FFF") is optional.  The seconds portion
3067c478bd9Sstevel@tonic-gate ** (":SS.FFF") is option.  The year and date can be omitted as long
3077c478bd9Sstevel@tonic-gate ** as there is a time string.  The time string can be omitted as long
3087c478bd9Sstevel@tonic-gate ** as there is a year and date.
3097c478bd9Sstevel@tonic-gate */
parseDateOrTime(const char * zDate,DateTime * p)3107c478bd9Sstevel@tonic-gate static int parseDateOrTime(const char *zDate, DateTime *p){
3117c478bd9Sstevel@tonic-gate   memset(p, 0, sizeof(*p));
3127c478bd9Sstevel@tonic-gate   if( parseYyyyMmDd(zDate,p)==0 ){
3137c478bd9Sstevel@tonic-gate     return 0;
3147c478bd9Sstevel@tonic-gate   }else if( parseHhMmSs(zDate, p)==0 ){
3157c478bd9Sstevel@tonic-gate     return 0;
3167c478bd9Sstevel@tonic-gate   }else if( sqliteStrICmp(zDate,"now")==0){
3177c478bd9Sstevel@tonic-gate     double r;
3187c478bd9Sstevel@tonic-gate     if( sqliteOsCurrentTime(&r)==0 ){
3197c478bd9Sstevel@tonic-gate       p->rJD = r;
3207c478bd9Sstevel@tonic-gate       p->validJD = 1;
3217c478bd9Sstevel@tonic-gate       return 0;
3227c478bd9Sstevel@tonic-gate     }
3237c478bd9Sstevel@tonic-gate     return 1;
3247c478bd9Sstevel@tonic-gate   }else if( sqliteIsNumber(zDate) ){
3257c478bd9Sstevel@tonic-gate     p->rJD = sqliteAtoF(zDate, 0);
3267c478bd9Sstevel@tonic-gate     p->validJD = 1;
3277c478bd9Sstevel@tonic-gate     return 0;
3287c478bd9Sstevel@tonic-gate   }
3297c478bd9Sstevel@tonic-gate   return 1;
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate ** Compute the Year, Month, and Day from the julian day number.
3347c478bd9Sstevel@tonic-gate */
computeYMD(DateTime * p)3357c478bd9Sstevel@tonic-gate static void computeYMD(DateTime *p){
3367c478bd9Sstevel@tonic-gate   int Z, A, B, C, D, E, X1;
3377c478bd9Sstevel@tonic-gate   if( p->validYMD ) return;
3387c478bd9Sstevel@tonic-gate   if( !p->validJD ){
3397c478bd9Sstevel@tonic-gate     p->Y = 2000;
3407c478bd9Sstevel@tonic-gate     p->M = 1;
3417c478bd9Sstevel@tonic-gate     p->D = 1;
3427c478bd9Sstevel@tonic-gate   }else{
3437c478bd9Sstevel@tonic-gate     Z = p->rJD + 0.5;
3447c478bd9Sstevel@tonic-gate     A = (Z - 1867216.25)/36524.25;
3457c478bd9Sstevel@tonic-gate     A = Z + 1 + A - (A/4);
3467c478bd9Sstevel@tonic-gate     B = A + 1524;
3477c478bd9Sstevel@tonic-gate     C = (B - 122.1)/365.25;
3487c478bd9Sstevel@tonic-gate     D = 365.25*C;
3497c478bd9Sstevel@tonic-gate     E = (B-D)/30.6001;
3507c478bd9Sstevel@tonic-gate     X1 = 30.6001*E;
3517c478bd9Sstevel@tonic-gate     p->D = B - D - X1;
3527c478bd9Sstevel@tonic-gate     p->M = E<14 ? E-1 : E-13;
3537c478bd9Sstevel@tonic-gate     p->Y = p->M>2 ? C - 4716 : C - 4715;
3547c478bd9Sstevel@tonic-gate   }
3557c478bd9Sstevel@tonic-gate   p->validYMD = 1;
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate ** Compute the Hour, Minute, and Seconds from the julian day number.
3607c478bd9Sstevel@tonic-gate */
computeHMS(DateTime * p)3617c478bd9Sstevel@tonic-gate static void computeHMS(DateTime *p){
3627c478bd9Sstevel@tonic-gate   int Z, s;
3637c478bd9Sstevel@tonic-gate   if( p->validHMS ) return;
3647c478bd9Sstevel@tonic-gate   Z = p->rJD + 0.5;
3657c478bd9Sstevel@tonic-gate   s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
3667c478bd9Sstevel@tonic-gate   p->s = 0.001*s;
3677c478bd9Sstevel@tonic-gate   s = p->s;
3687c478bd9Sstevel@tonic-gate   p->s -= s;
3697c478bd9Sstevel@tonic-gate   p->h = s/3600;
3707c478bd9Sstevel@tonic-gate   s -= p->h*3600;
3717c478bd9Sstevel@tonic-gate   p->m = s/60;
3727c478bd9Sstevel@tonic-gate   p->s += s - p->m*60;
3737c478bd9Sstevel@tonic-gate   p->validHMS = 1;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate ** Compute both YMD and HMS
3787c478bd9Sstevel@tonic-gate */
computeYMD_HMS(DateTime * p)3797c478bd9Sstevel@tonic-gate static void computeYMD_HMS(DateTime *p){
3807c478bd9Sstevel@tonic-gate   computeYMD(p);
3817c478bd9Sstevel@tonic-gate   computeHMS(p);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate ** Clear the YMD and HMS and the TZ
3867c478bd9Sstevel@tonic-gate */
clearYMD_HMS_TZ(DateTime * p)3877c478bd9Sstevel@tonic-gate static void clearYMD_HMS_TZ(DateTime *p){
3887c478bd9Sstevel@tonic-gate   p->validYMD = 0;
3897c478bd9Sstevel@tonic-gate   p->validHMS = 0;
3907c478bd9Sstevel@tonic-gate   p->validTZ = 0;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate ** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
3957c478bd9Sstevel@tonic-gate ** for the time value p where p is in UTC.
3967c478bd9Sstevel@tonic-gate */
localtimeOffset(DateTime * p)3977c478bd9Sstevel@tonic-gate static double localtimeOffset(DateTime *p){
3987c478bd9Sstevel@tonic-gate   DateTime x, y;
3997c478bd9Sstevel@tonic-gate   time_t t;
4007c478bd9Sstevel@tonic-gate   struct tm *pTm;
4017c478bd9Sstevel@tonic-gate   x = *p;
4027c478bd9Sstevel@tonic-gate   computeYMD_HMS(&x);
4037c478bd9Sstevel@tonic-gate   if( x.Y<1971 || x.Y>=2038 ){
4047c478bd9Sstevel@tonic-gate     x.Y = 2000;
4057c478bd9Sstevel@tonic-gate     x.M = 1;
4067c478bd9Sstevel@tonic-gate     x.D = 1;
4077c478bd9Sstevel@tonic-gate     x.h = 0;
4087c478bd9Sstevel@tonic-gate     x.m = 0;
4097c478bd9Sstevel@tonic-gate     x.s = 0.0;
4107c478bd9Sstevel@tonic-gate   } else {
4117c478bd9Sstevel@tonic-gate     int s = x.s + 0.5;
4127c478bd9Sstevel@tonic-gate     x.s = s;
4137c478bd9Sstevel@tonic-gate   }
4147c478bd9Sstevel@tonic-gate   x.tz = 0;
4157c478bd9Sstevel@tonic-gate   x.validJD = 0;
4167c478bd9Sstevel@tonic-gate   computeJD(&x);
4177c478bd9Sstevel@tonic-gate   t = (x.rJD-2440587.5)*86400.0 + 0.5;
4187c478bd9Sstevel@tonic-gate   sqliteOsEnterMutex();
4197c478bd9Sstevel@tonic-gate   pTm = localtime(&t);
4207c478bd9Sstevel@tonic-gate   y.Y = pTm->tm_year + 1900;
4217c478bd9Sstevel@tonic-gate   y.M = pTm->tm_mon + 1;
4227c478bd9Sstevel@tonic-gate   y.D = pTm->tm_mday;
4237c478bd9Sstevel@tonic-gate   y.h = pTm->tm_hour;
4247c478bd9Sstevel@tonic-gate   y.m = pTm->tm_min;
4257c478bd9Sstevel@tonic-gate   y.s = pTm->tm_sec;
4267c478bd9Sstevel@tonic-gate   sqliteOsLeaveMutex();
4277c478bd9Sstevel@tonic-gate   y.validYMD = 1;
4287c478bd9Sstevel@tonic-gate   y.validHMS = 1;
4297c478bd9Sstevel@tonic-gate   y.validJD = 0;
4307c478bd9Sstevel@tonic-gate   y.validTZ = 0;
4317c478bd9Sstevel@tonic-gate   computeJD(&y);
4327c478bd9Sstevel@tonic-gate   return y.rJD - x.rJD;
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate /*
4367c478bd9Sstevel@tonic-gate ** Process a modifier to a date-time stamp.  The modifiers are
4377c478bd9Sstevel@tonic-gate ** as follows:
4387c478bd9Sstevel@tonic-gate **
4397c478bd9Sstevel@tonic-gate **     NNN days
4407c478bd9Sstevel@tonic-gate **     NNN hours
4417c478bd9Sstevel@tonic-gate **     NNN minutes
4427c478bd9Sstevel@tonic-gate **     NNN.NNNN seconds
4437c478bd9Sstevel@tonic-gate **     NNN months
4447c478bd9Sstevel@tonic-gate **     NNN years
4457c478bd9Sstevel@tonic-gate **     start of month
4467c478bd9Sstevel@tonic-gate **     start of year
4477c478bd9Sstevel@tonic-gate **     start of week
4487c478bd9Sstevel@tonic-gate **     start of day
4497c478bd9Sstevel@tonic-gate **     weekday N
4507c478bd9Sstevel@tonic-gate **     unixepoch
4517c478bd9Sstevel@tonic-gate **     localtime
4527c478bd9Sstevel@tonic-gate **     utc
4537c478bd9Sstevel@tonic-gate **
4547c478bd9Sstevel@tonic-gate ** Return 0 on success and 1 if there is any kind of error.
4557c478bd9Sstevel@tonic-gate */
parseModifier(const char * zMod,DateTime * p)4567c478bd9Sstevel@tonic-gate static int parseModifier(const char *zMod, DateTime *p){
4577c478bd9Sstevel@tonic-gate   int rc = 1;
4587c478bd9Sstevel@tonic-gate   int n;
4597c478bd9Sstevel@tonic-gate   double r;
4607c478bd9Sstevel@tonic-gate   char *z, zBuf[30];
4617c478bd9Sstevel@tonic-gate   z = zBuf;
4627c478bd9Sstevel@tonic-gate   for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
4637c478bd9Sstevel@tonic-gate     z[n] = tolower(zMod[n]);
4647c478bd9Sstevel@tonic-gate   }
4657c478bd9Sstevel@tonic-gate   z[n] = 0;
4667c478bd9Sstevel@tonic-gate   switch( z[0] ){
4677c478bd9Sstevel@tonic-gate     case 'l': {
4687c478bd9Sstevel@tonic-gate       /*    localtime
4697c478bd9Sstevel@tonic-gate       **
4707c478bd9Sstevel@tonic-gate       ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
4717c478bd9Sstevel@tonic-gate       ** show local time.
4727c478bd9Sstevel@tonic-gate       */
4737c478bd9Sstevel@tonic-gate       if( strcmp(z, "localtime")==0 ){
4747c478bd9Sstevel@tonic-gate         computeJD(p);
4757c478bd9Sstevel@tonic-gate         p->rJD += localtimeOffset(p);
4767c478bd9Sstevel@tonic-gate         clearYMD_HMS_TZ(p);
4777c478bd9Sstevel@tonic-gate         rc = 0;
4787c478bd9Sstevel@tonic-gate       }
4797c478bd9Sstevel@tonic-gate       break;
4807c478bd9Sstevel@tonic-gate     }
4817c478bd9Sstevel@tonic-gate     case 'u': {
4827c478bd9Sstevel@tonic-gate       /*
4837c478bd9Sstevel@tonic-gate       **    unixepoch
4847c478bd9Sstevel@tonic-gate       **
4857c478bd9Sstevel@tonic-gate       ** Treat the current value of p->rJD as the number of
4867c478bd9Sstevel@tonic-gate       ** seconds since 1970.  Convert to a real julian day number.
4877c478bd9Sstevel@tonic-gate       */
4887c478bd9Sstevel@tonic-gate       if( strcmp(z, "unixepoch")==0 && p->validJD ){
4897c478bd9Sstevel@tonic-gate         p->rJD = p->rJD/86400.0 + 2440587.5;
4907c478bd9Sstevel@tonic-gate         clearYMD_HMS_TZ(p);
4917c478bd9Sstevel@tonic-gate         rc = 0;
4927c478bd9Sstevel@tonic-gate       }else if( strcmp(z, "utc")==0 ){
4937c478bd9Sstevel@tonic-gate         double c1;
4947c478bd9Sstevel@tonic-gate         computeJD(p);
4957c478bd9Sstevel@tonic-gate         c1 = localtimeOffset(p);
4967c478bd9Sstevel@tonic-gate         p->rJD -= c1;
4977c478bd9Sstevel@tonic-gate         clearYMD_HMS_TZ(p);
4987c478bd9Sstevel@tonic-gate         p->rJD += c1 - localtimeOffset(p);
4997c478bd9Sstevel@tonic-gate         rc = 0;
5007c478bd9Sstevel@tonic-gate       }
5017c478bd9Sstevel@tonic-gate       break;
5027c478bd9Sstevel@tonic-gate     }
5037c478bd9Sstevel@tonic-gate     case 'w': {
5047c478bd9Sstevel@tonic-gate       /*
5057c478bd9Sstevel@tonic-gate       **    weekday N
5067c478bd9Sstevel@tonic-gate       **
5077c478bd9Sstevel@tonic-gate       ** Move the date to the same time on the next occurrance of
5087c478bd9Sstevel@tonic-gate       ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
5097c478bd9Sstevel@tonic-gate       ** date is already on the appropriate weekday, this is a no-op.
5107c478bd9Sstevel@tonic-gate       */
5117c478bd9Sstevel@tonic-gate       if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
5127c478bd9Sstevel@tonic-gate                  && (n=r)==r && n>=0 && r<7 ){
5137c478bd9Sstevel@tonic-gate         int Z;
5147c478bd9Sstevel@tonic-gate         computeYMD_HMS(p);
5157c478bd9Sstevel@tonic-gate         p->validTZ = 0;
5167c478bd9Sstevel@tonic-gate         p->validJD = 0;
5177c478bd9Sstevel@tonic-gate         computeJD(p);
5187c478bd9Sstevel@tonic-gate         Z = p->rJD + 1.5;
5197c478bd9Sstevel@tonic-gate         Z %= 7;
5207c478bd9Sstevel@tonic-gate         if( Z>n ) Z -= 7;
5217c478bd9Sstevel@tonic-gate         p->rJD += n - Z;
5227c478bd9Sstevel@tonic-gate         clearYMD_HMS_TZ(p);
5237c478bd9Sstevel@tonic-gate         rc = 0;
5247c478bd9Sstevel@tonic-gate       }
5257c478bd9Sstevel@tonic-gate       break;
5267c478bd9Sstevel@tonic-gate     }
5277c478bd9Sstevel@tonic-gate     case 's': {
5287c478bd9Sstevel@tonic-gate       /*
5297c478bd9Sstevel@tonic-gate       **    start of TTTTT
5307c478bd9Sstevel@tonic-gate       **
5317c478bd9Sstevel@tonic-gate       ** Move the date backwards to the beginning of the current day,
5327c478bd9Sstevel@tonic-gate       ** or month or year.
5337c478bd9Sstevel@tonic-gate       */
5347c478bd9Sstevel@tonic-gate       if( strncmp(z, "start of ", 9)!=0 ) break;
5357c478bd9Sstevel@tonic-gate       z += 9;
5367c478bd9Sstevel@tonic-gate       computeYMD(p);
5377c478bd9Sstevel@tonic-gate       p->validHMS = 1;
5387c478bd9Sstevel@tonic-gate       p->h = p->m = 0;
5397c478bd9Sstevel@tonic-gate       p->s = 0.0;
5407c478bd9Sstevel@tonic-gate       p->validTZ = 0;
5417c478bd9Sstevel@tonic-gate       p->validJD = 0;
5427c478bd9Sstevel@tonic-gate       if( strcmp(z,"month")==0 ){
5437c478bd9Sstevel@tonic-gate         p->D = 1;
5447c478bd9Sstevel@tonic-gate         rc = 0;
5457c478bd9Sstevel@tonic-gate       }else if( strcmp(z,"year")==0 ){
5467c478bd9Sstevel@tonic-gate         computeYMD(p);
5477c478bd9Sstevel@tonic-gate         p->M = 1;
5487c478bd9Sstevel@tonic-gate         p->D = 1;
5497c478bd9Sstevel@tonic-gate         rc = 0;
5507c478bd9Sstevel@tonic-gate       }else if( strcmp(z,"day")==0 ){
5517c478bd9Sstevel@tonic-gate         rc = 0;
5527c478bd9Sstevel@tonic-gate       }
5537c478bd9Sstevel@tonic-gate       break;
5547c478bd9Sstevel@tonic-gate     }
5557c478bd9Sstevel@tonic-gate     case '+':
5567c478bd9Sstevel@tonic-gate     case '-':
5577c478bd9Sstevel@tonic-gate     case '0':
5587c478bd9Sstevel@tonic-gate     case '1':
5597c478bd9Sstevel@tonic-gate     case '2':
5607c478bd9Sstevel@tonic-gate     case '3':
5617c478bd9Sstevel@tonic-gate     case '4':
5627c478bd9Sstevel@tonic-gate     case '5':
5637c478bd9Sstevel@tonic-gate     case '6':
5647c478bd9Sstevel@tonic-gate     case '7':
5657c478bd9Sstevel@tonic-gate     case '8':
5667c478bd9Sstevel@tonic-gate     case '9': {
5677c478bd9Sstevel@tonic-gate       n = getValue(z, &r);
5687c478bd9Sstevel@tonic-gate       if( n<=0 ) break;
5697c478bd9Sstevel@tonic-gate       if( z[n]==':' ){
5707c478bd9Sstevel@tonic-gate         /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
5717c478bd9Sstevel@tonic-gate         ** specified number of hours, minutes, seconds, and fractional seconds
5727c478bd9Sstevel@tonic-gate         ** to the time.  The ".FFF" may be omitted.  The ":SS.FFF" may be
5737c478bd9Sstevel@tonic-gate         ** omitted.
5747c478bd9Sstevel@tonic-gate         */
5757c478bd9Sstevel@tonic-gate         const char *z2 = z;
5767c478bd9Sstevel@tonic-gate         DateTime tx;
5777c478bd9Sstevel@tonic-gate         int day;
5787c478bd9Sstevel@tonic-gate         if( !isdigit(*z2) ) z2++;
5797c478bd9Sstevel@tonic-gate         memset(&tx, 0, sizeof(tx));
5807c478bd9Sstevel@tonic-gate         if( parseHhMmSs(z2, &tx) ) break;
5817c478bd9Sstevel@tonic-gate         computeJD(&tx);
5827c478bd9Sstevel@tonic-gate         tx.rJD -= 0.5;
5837c478bd9Sstevel@tonic-gate         day = (int)tx.rJD;
5847c478bd9Sstevel@tonic-gate         tx.rJD -= day;
5857c478bd9Sstevel@tonic-gate         if( z[0]=='-' ) tx.rJD = -tx.rJD;
5867c478bd9Sstevel@tonic-gate         computeJD(p);
5877c478bd9Sstevel@tonic-gate         clearYMD_HMS_TZ(p);
5887c478bd9Sstevel@tonic-gate        p->rJD += tx.rJD;
5897c478bd9Sstevel@tonic-gate         rc = 0;
5907c478bd9Sstevel@tonic-gate         break;
5917c478bd9Sstevel@tonic-gate       }
5927c478bd9Sstevel@tonic-gate       z += n;
5937c478bd9Sstevel@tonic-gate       while( isspace(z[0]) ) z++;
5947c478bd9Sstevel@tonic-gate       n = strlen(z);
5957c478bd9Sstevel@tonic-gate       if( n>10 || n<3 ) break;
5967c478bd9Sstevel@tonic-gate       if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
5977c478bd9Sstevel@tonic-gate       computeJD(p);
5987c478bd9Sstevel@tonic-gate       rc = 0;
5997c478bd9Sstevel@tonic-gate       if( n==3 && strcmp(z,"day")==0 ){
6007c478bd9Sstevel@tonic-gate         p->rJD += r;
6017c478bd9Sstevel@tonic-gate       }else if( n==4 && strcmp(z,"hour")==0 ){
6027c478bd9Sstevel@tonic-gate         p->rJD += r/24.0;
6037c478bd9Sstevel@tonic-gate       }else if( n==6 && strcmp(z,"minute")==0 ){
6047c478bd9Sstevel@tonic-gate         p->rJD += r/(24.0*60.0);
6057c478bd9Sstevel@tonic-gate       }else if( n==6 && strcmp(z,"second")==0 ){
6067c478bd9Sstevel@tonic-gate         p->rJD += r/(24.0*60.0*60.0);
6077c478bd9Sstevel@tonic-gate       }else if( n==5 && strcmp(z,"month")==0 ){
6087c478bd9Sstevel@tonic-gate         int x, y;
6097c478bd9Sstevel@tonic-gate         computeYMD_HMS(p);
6107c478bd9Sstevel@tonic-gate         p->M += r;
6117c478bd9Sstevel@tonic-gate         x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
6127c478bd9Sstevel@tonic-gate         p->Y += x;
6137c478bd9Sstevel@tonic-gate         p->M -= x*12;
6147c478bd9Sstevel@tonic-gate         p->validJD = 0;
6157c478bd9Sstevel@tonic-gate         computeJD(p);
6167c478bd9Sstevel@tonic-gate         y = r;
6177c478bd9Sstevel@tonic-gate         if( y!=r ){
6187c478bd9Sstevel@tonic-gate           p->rJD += (r - y)*30.0;
6197c478bd9Sstevel@tonic-gate         }
6207c478bd9Sstevel@tonic-gate       }else if( n==4 && strcmp(z,"year")==0 ){
6217c478bd9Sstevel@tonic-gate         computeYMD_HMS(p);
6227c478bd9Sstevel@tonic-gate         p->Y += r;
6237c478bd9Sstevel@tonic-gate         p->validJD = 0;
6247c478bd9Sstevel@tonic-gate         computeJD(p);
6257c478bd9Sstevel@tonic-gate       }else{
6267c478bd9Sstevel@tonic-gate         rc = 1;
6277c478bd9Sstevel@tonic-gate       }
6287c478bd9Sstevel@tonic-gate       clearYMD_HMS_TZ(p);
6297c478bd9Sstevel@tonic-gate       break;
6307c478bd9Sstevel@tonic-gate     }
6317c478bd9Sstevel@tonic-gate     default: {
6327c478bd9Sstevel@tonic-gate       break;
6337c478bd9Sstevel@tonic-gate     }
6347c478bd9Sstevel@tonic-gate   }
6357c478bd9Sstevel@tonic-gate   return rc;
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate ** Process time function arguments.  argv[0] is a date-time stamp.
6407c478bd9Sstevel@tonic-gate ** argv[1] and following are modifiers.  Parse them all and write
6417c478bd9Sstevel@tonic-gate ** the resulting time into the DateTime structure p.  Return 0
6427c478bd9Sstevel@tonic-gate ** on success and 1 if there are any errors.
6437c478bd9Sstevel@tonic-gate */
isDate(int argc,const char ** argv,DateTime * p)6447c478bd9Sstevel@tonic-gate static int isDate(int argc, const char **argv, DateTime *p){
6457c478bd9Sstevel@tonic-gate   int i;
6467c478bd9Sstevel@tonic-gate   if( argc==0 ) return 1;
6477c478bd9Sstevel@tonic-gate   if( argv[0]==0 || parseDateOrTime(argv[0], p) ) return 1;
6487c478bd9Sstevel@tonic-gate   for(i=1; i<argc; i++){
6497c478bd9Sstevel@tonic-gate     if( argv[i]==0 || parseModifier(argv[i], p) ) return 1;
6507c478bd9Sstevel@tonic-gate   }
6517c478bd9Sstevel@tonic-gate   return 0;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate /*
6567c478bd9Sstevel@tonic-gate ** The following routines implement the various date and time functions
6577c478bd9Sstevel@tonic-gate ** of SQLite.
6587c478bd9Sstevel@tonic-gate */
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate **    julianday( TIMESTRING, MOD, MOD, ...)
6627c478bd9Sstevel@tonic-gate **
6637c478bd9Sstevel@tonic-gate ** Return the julian day number of the date specified in the arguments
6647c478bd9Sstevel@tonic-gate */
juliandayFunc(sqlite_func * context,int argc,const char ** argv)6657c478bd9Sstevel@tonic-gate static void juliandayFunc(sqlite_func *context, int argc, const char **argv){
6667c478bd9Sstevel@tonic-gate   DateTime x;
6677c478bd9Sstevel@tonic-gate   if( isDate(argc, argv, &x)==0 ){
6687c478bd9Sstevel@tonic-gate     computeJD(&x);
6697c478bd9Sstevel@tonic-gate     sqlite_set_result_double(context, x.rJD);
6707c478bd9Sstevel@tonic-gate   }
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate /*
6747c478bd9Sstevel@tonic-gate **    datetime( TIMESTRING, MOD, MOD, ...)
6757c478bd9Sstevel@tonic-gate **
6767c478bd9Sstevel@tonic-gate ** Return YYYY-MM-DD HH:MM:SS
6777c478bd9Sstevel@tonic-gate */
datetimeFunc(sqlite_func * context,int argc,const char ** argv)6787c478bd9Sstevel@tonic-gate static void datetimeFunc(sqlite_func *context, int argc, const char **argv){
6797c478bd9Sstevel@tonic-gate   DateTime x;
6807c478bd9Sstevel@tonic-gate   if( isDate(argc, argv, &x)==0 ){
6817c478bd9Sstevel@tonic-gate     char zBuf[100];
6827c478bd9Sstevel@tonic-gate     computeYMD_HMS(&x);
6837c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
6847c478bd9Sstevel@tonic-gate            (int)(x.s));
6857c478bd9Sstevel@tonic-gate     sqlite_set_result_string(context, zBuf, -1);
6867c478bd9Sstevel@tonic-gate   }
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate /*
6907c478bd9Sstevel@tonic-gate **    time( TIMESTRING, MOD, MOD, ...)
6917c478bd9Sstevel@tonic-gate **
6927c478bd9Sstevel@tonic-gate ** Return HH:MM:SS
6937c478bd9Sstevel@tonic-gate */
timeFunc(sqlite_func * context,int argc,const char ** argv)6947c478bd9Sstevel@tonic-gate static void timeFunc(sqlite_func *context, int argc, const char **argv){
6957c478bd9Sstevel@tonic-gate   DateTime x;
6967c478bd9Sstevel@tonic-gate   if( isDate(argc, argv, &x)==0 ){
6977c478bd9Sstevel@tonic-gate     char zBuf[100];
6987c478bd9Sstevel@tonic-gate     computeHMS(&x);
6997c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
7007c478bd9Sstevel@tonic-gate     sqlite_set_result_string(context, zBuf, -1);
7017c478bd9Sstevel@tonic-gate   }
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate **    date( TIMESTRING, MOD, MOD, ...)
7067c478bd9Sstevel@tonic-gate **
7077c478bd9Sstevel@tonic-gate ** Return YYYY-MM-DD
7087c478bd9Sstevel@tonic-gate */
dateFunc(sqlite_func * context,int argc,const char ** argv)7097c478bd9Sstevel@tonic-gate static void dateFunc(sqlite_func *context, int argc, const char **argv){
7107c478bd9Sstevel@tonic-gate   DateTime x;
7117c478bd9Sstevel@tonic-gate   if( isDate(argc, argv, &x)==0 ){
7127c478bd9Sstevel@tonic-gate     char zBuf[100];
7137c478bd9Sstevel@tonic-gate     computeYMD(&x);
7147c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
7157c478bd9Sstevel@tonic-gate     sqlite_set_result_string(context, zBuf, -1);
7167c478bd9Sstevel@tonic-gate   }
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate **    strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
7217c478bd9Sstevel@tonic-gate **
7227c478bd9Sstevel@tonic-gate ** Return a string described by FORMAT.  Conversions as follows:
7237c478bd9Sstevel@tonic-gate **
7247c478bd9Sstevel@tonic-gate **   %d  day of month
7257c478bd9Sstevel@tonic-gate **   %f  ** fractional seconds  SS.SSS
7267c478bd9Sstevel@tonic-gate **   %H  hour 00-24
7277c478bd9Sstevel@tonic-gate **   %j  day of year 000-366
7287c478bd9Sstevel@tonic-gate **   %J  ** Julian day number
7297c478bd9Sstevel@tonic-gate **   %m  month 01-12
7307c478bd9Sstevel@tonic-gate **   %M  minute 00-59
7317c478bd9Sstevel@tonic-gate **   %s  seconds since 1970-01-01
7327c478bd9Sstevel@tonic-gate **   %S  seconds 00-59
7337c478bd9Sstevel@tonic-gate **   %w  day of week 0-6  sunday==0
7347c478bd9Sstevel@tonic-gate **   %W  week of year 00-53
7357c478bd9Sstevel@tonic-gate **   %Y  year 0000-9999
7367c478bd9Sstevel@tonic-gate **   %%  %
7377c478bd9Sstevel@tonic-gate */
strftimeFunc(sqlite_func * context,int argc,const char ** argv)7387c478bd9Sstevel@tonic-gate static void strftimeFunc(sqlite_func *context, int argc, const char **argv){
7397c478bd9Sstevel@tonic-gate   DateTime x;
7407c478bd9Sstevel@tonic-gate   int n, i, j;
7417c478bd9Sstevel@tonic-gate   char *z;
7427c478bd9Sstevel@tonic-gate   const char *zFmt = argv[0];
7437c478bd9Sstevel@tonic-gate   char zBuf[100];
7447c478bd9Sstevel@tonic-gate   if( argv[0]==0 || isDate(argc-1, argv+1, &x) ) return;
7457c478bd9Sstevel@tonic-gate   for(i=0, n=1; zFmt[i]; i++, n++){
7467c478bd9Sstevel@tonic-gate     if( zFmt[i]=='%' ){
7477c478bd9Sstevel@tonic-gate       switch( zFmt[i+1] ){
7487c478bd9Sstevel@tonic-gate         case 'd':
7497c478bd9Sstevel@tonic-gate         case 'H':
7507c478bd9Sstevel@tonic-gate         case 'm':
7517c478bd9Sstevel@tonic-gate         case 'M':
7527c478bd9Sstevel@tonic-gate         case 'S':
7537c478bd9Sstevel@tonic-gate         case 'W':
7547c478bd9Sstevel@tonic-gate           n++;
7557c478bd9Sstevel@tonic-gate           /* fall thru */
7567c478bd9Sstevel@tonic-gate         case 'w':
7577c478bd9Sstevel@tonic-gate         case '%':
7587c478bd9Sstevel@tonic-gate           break;
7597c478bd9Sstevel@tonic-gate         case 'f':
7607c478bd9Sstevel@tonic-gate           n += 8;
7617c478bd9Sstevel@tonic-gate           break;
7627c478bd9Sstevel@tonic-gate         case 'j':
7637c478bd9Sstevel@tonic-gate           n += 3;
7647c478bd9Sstevel@tonic-gate           break;
7657c478bd9Sstevel@tonic-gate         case 'Y':
7667c478bd9Sstevel@tonic-gate           n += 8;
7677c478bd9Sstevel@tonic-gate           break;
7687c478bd9Sstevel@tonic-gate         case 's':
7697c478bd9Sstevel@tonic-gate         case 'J':
7707c478bd9Sstevel@tonic-gate           n += 50;
7717c478bd9Sstevel@tonic-gate           break;
7727c478bd9Sstevel@tonic-gate         default:
7737c478bd9Sstevel@tonic-gate           return;  /* ERROR.  return a NULL */
7747c478bd9Sstevel@tonic-gate       }
7757c478bd9Sstevel@tonic-gate       i++;
7767c478bd9Sstevel@tonic-gate     }
7777c478bd9Sstevel@tonic-gate   }
7787c478bd9Sstevel@tonic-gate   if( n<sizeof(zBuf) ){
7797c478bd9Sstevel@tonic-gate     z = zBuf;
7807c478bd9Sstevel@tonic-gate   }else{
7817c478bd9Sstevel@tonic-gate     z = sqliteMalloc( n );
7827c478bd9Sstevel@tonic-gate     if( z==0 ) return;
7837c478bd9Sstevel@tonic-gate   }
7847c478bd9Sstevel@tonic-gate   computeJD(&x);
7857c478bd9Sstevel@tonic-gate   computeYMD_HMS(&x);
7867c478bd9Sstevel@tonic-gate   for(i=j=0; zFmt[i]; i++){
7877c478bd9Sstevel@tonic-gate     if( zFmt[i]!='%' ){
7887c478bd9Sstevel@tonic-gate       z[j++] = zFmt[i];
7897c478bd9Sstevel@tonic-gate     }else{
7907c478bd9Sstevel@tonic-gate       i++;
7917c478bd9Sstevel@tonic-gate       switch( zFmt[i] ){
7927c478bd9Sstevel@tonic-gate         case 'd':  sprintf(&z[j],"%02d",x.D); j+=2; break;
7937c478bd9Sstevel@tonic-gate         case 'f': {
7947c478bd9Sstevel@tonic-gate           int s = x.s;
7957c478bd9Sstevel@tonic-gate           int ms = (x.s - s)*1000.0;
7967c478bd9Sstevel@tonic-gate           sprintf(&z[j],"%02d.%03d",s,ms);
7977c478bd9Sstevel@tonic-gate           j += strlen(&z[j]);
7987c478bd9Sstevel@tonic-gate           break;
7997c478bd9Sstevel@tonic-gate         }
8007c478bd9Sstevel@tonic-gate         case 'H':  sprintf(&z[j],"%02d",x.h); j+=2; break;
8017c478bd9Sstevel@tonic-gate         case 'W': /* Fall thru */
8027c478bd9Sstevel@tonic-gate         case 'j': {
8037c478bd9Sstevel@tonic-gate           int n;             /* Number of days since 1st day of year */
8047c478bd9Sstevel@tonic-gate           DateTime y = x;
8057c478bd9Sstevel@tonic-gate           y.validJD = 0;
8067c478bd9Sstevel@tonic-gate           y.M = 1;
8077c478bd9Sstevel@tonic-gate           y.D = 1;
8087c478bd9Sstevel@tonic-gate           computeJD(&y);
8097c478bd9Sstevel@tonic-gate           n = x.rJD - y.rJD;
8107c478bd9Sstevel@tonic-gate           if( zFmt[i]=='W' ){
8117c478bd9Sstevel@tonic-gate             int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
8127c478bd9Sstevel@tonic-gate             wd = ((int)(x.rJD+0.5)) % 7;
8137c478bd9Sstevel@tonic-gate             sprintf(&z[j],"%02d",(n+7-wd)/7);
8147c478bd9Sstevel@tonic-gate             j += 2;
8157c478bd9Sstevel@tonic-gate           }else{
8167c478bd9Sstevel@tonic-gate             sprintf(&z[j],"%03d",n+1);
8177c478bd9Sstevel@tonic-gate             j += 3;
8187c478bd9Sstevel@tonic-gate           }
8197c478bd9Sstevel@tonic-gate           break;
8207c478bd9Sstevel@tonic-gate         }
8217c478bd9Sstevel@tonic-gate         case 'J':  sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
8227c478bd9Sstevel@tonic-gate         case 'm':  sprintf(&z[j],"%02d",x.M); j+=2; break;
8237c478bd9Sstevel@tonic-gate         case 'M':  sprintf(&z[j],"%02d",x.m); j+=2; break;
8247c478bd9Sstevel@tonic-gate         case 's': {
8257c478bd9Sstevel@tonic-gate           sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
8267c478bd9Sstevel@tonic-gate           j += strlen(&z[j]);
8277c478bd9Sstevel@tonic-gate           break;
8287c478bd9Sstevel@tonic-gate         }
8297c478bd9Sstevel@tonic-gate         case 'S':  sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
8307c478bd9Sstevel@tonic-gate         case 'w':  z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
8317c478bd9Sstevel@tonic-gate         case 'Y':  sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
8327c478bd9Sstevel@tonic-gate         case '%':  z[j++] = '%'; break;
8337c478bd9Sstevel@tonic-gate       }
8347c478bd9Sstevel@tonic-gate     }
8357c478bd9Sstevel@tonic-gate   }
8367c478bd9Sstevel@tonic-gate   z[j] = 0;
8377c478bd9Sstevel@tonic-gate   sqlite_set_result_string(context, z, -1);
8387c478bd9Sstevel@tonic-gate   if( z!=zBuf ){
8397c478bd9Sstevel@tonic-gate     sqliteFree(z);
8407c478bd9Sstevel@tonic-gate   }
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate #endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate /*
8477c478bd9Sstevel@tonic-gate ** This function registered all of the above C functions as SQL
8487c478bd9Sstevel@tonic-gate ** functions.  This should be the only routine in this file with
8497c478bd9Sstevel@tonic-gate ** external linkage.
8507c478bd9Sstevel@tonic-gate */
sqliteRegisterDateTimeFunctions(sqlite * db)8517c478bd9Sstevel@tonic-gate void sqliteRegisterDateTimeFunctions(sqlite *db){
8527c478bd9Sstevel@tonic-gate #ifndef SQLITE_OMIT_DATETIME_FUNCS
8537c478bd9Sstevel@tonic-gate   static struct {
8547c478bd9Sstevel@tonic-gate      char *zName;
8557c478bd9Sstevel@tonic-gate      int nArg;
8567c478bd9Sstevel@tonic-gate      int dataType;
8577c478bd9Sstevel@tonic-gate      void (*xFunc)(sqlite_func*,int,const char**);
8587c478bd9Sstevel@tonic-gate   } aFuncs[] = {
8597c478bd9Sstevel@tonic-gate     { "julianday", -1, SQLITE_NUMERIC, juliandayFunc   },
8607c478bd9Sstevel@tonic-gate     { "date",      -1, SQLITE_TEXT,    dateFunc        },
8617c478bd9Sstevel@tonic-gate     { "time",      -1, SQLITE_TEXT,    timeFunc        },
8627c478bd9Sstevel@tonic-gate     { "datetime",  -1, SQLITE_TEXT,    datetimeFunc    },
8637c478bd9Sstevel@tonic-gate     { "strftime",  -1, SQLITE_TEXT,    strftimeFunc    },
8647c478bd9Sstevel@tonic-gate   };
8657c478bd9Sstevel@tonic-gate   int i;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
8687c478bd9Sstevel@tonic-gate     sqlite_create_function(db, aFuncs[i].zName,
8697c478bd9Sstevel@tonic-gate            aFuncs[i].nArg, aFuncs[i].xFunc, 0);
8707c478bd9Sstevel@tonic-gate     if( aFuncs[i].xFunc ){
8717c478bd9Sstevel@tonic-gate       sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
8727c478bd9Sstevel@tonic-gate     }
8737c478bd9Sstevel@tonic-gate   }
8747c478bd9Sstevel@tonic-gate #endif
8757c478bd9Sstevel@tonic-gate }
876