chiark / gitweb /
gnupg2 (2.1.17-3) unstable; urgency=medium
[gnupg2.git] / common / gettime.c
1 /* gettime.c - Wrapper for time functions
2  * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <ctype.h>
34 #ifdef HAVE_LANGINFO_H
35 #include <langinfo.h>
36 #endif
37
38 #include "util.h"
39 #include "i18n.h"
40 #include "gettime.h"
41
42 #ifdef HAVE_UNSIGNED_TIME_T
43 # define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
44 #else
45   /* Error or 32 bit time_t and value after 2038-01-19.  */
46 # define IS_INVALID_TIME_T(a) ((a) < 0)
47 #endif
48
49
50 static unsigned long timewarp;
51 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
52
53 /* Correction used to map to real Julian days. */
54 #define JD_DIFF 1721060L
55
56
57 /* Wrapper for the time(3).  We use this here so we can fake the time
58    for tests */
59 time_t
60 gnupg_get_time ()
61 {
62   time_t current = time (NULL);
63   if (current == (time_t)(-1))
64     log_fatal ("time() failed\n");
65
66   if (timemode == NORMAL)
67     return current;
68   else if (timemode == FROZEN)
69     return timewarp;
70   else if (timemode == FUTURE)
71     return current + timewarp;
72   else
73     return current - timewarp;
74 }
75
76
77 /* Wrapper around gmtime_r.
78
79    On systems without gmtime_r this implementation works within gnupg
80    because we use only one thread a time.  FIXME: An independent
81    library may use gmtime in one of its own thread (or via
82    npth_enter/npth_leave) - in this case we run into a problem.  The
83    solution would be to use a mutex here.  */
84 struct tm *
85 gnupg_gmtime (const time_t *timep, struct tm *result)
86 {
87 #ifdef HAVE_GMTIME_R
88   return gmtime_r (timep, result);
89 #else
90   struct tm *tp;
91
92   tp = gmtime (timep);
93   if (tp)
94     memcpy (result, tp, sizeof *result);
95   return tp;
96 #endif
97 }
98
99
100 /* Return the current time (possibly faked) in ISO format. */
101 void
102 gnupg_get_isotime (gnupg_isotime_t timebuf)
103 {
104   time_t atime = gnupg_get_time ();
105   struct tm *tp;
106   struct tm tmbuf;
107
108   tp = gnupg_gmtime (&atime, &tmbuf);
109   if (!tp)
110     *timebuf = 0;
111   else
112     snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
113               1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
114               tp->tm_hour, tp->tm_min, tp->tm_sec);
115 }
116
117
118 /* Set the time to NEWTIME so that gnupg_get_time returns a time
119    starting with this one.  With FREEZE set to 1 the returned time
120    will never change.  Just for completeness, a value of (time_t)-1
121    for NEWTIME gets you back to reality.  Note that this is obviously
122    not thread-safe but this is not required. */
123 void
124 gnupg_set_time (time_t newtime, int freeze)
125 {
126   time_t current = time (NULL);
127
128   if ( newtime == (time_t)-1 || current == newtime)
129     {
130       timemode = NORMAL;
131       timewarp = 0;
132     }
133   else if (freeze)
134     {
135       timemode = FROZEN;
136       timewarp = current;
137     }
138   else if (newtime > current)
139     {
140       timemode = FUTURE;
141       timewarp = newtime - current;
142     }
143   else
144     {
145       timemode = PAST;
146       timewarp = current - newtime;
147     }
148 }
149
150 /* Returns true when we are in timewarp mode */
151 int
152 gnupg_faked_time_p (void)
153 {
154   return timemode;
155 }
156
157
158 /* This function is used by gpg because OpenPGP defines the timestamp
159    as an unsigned 32 bit value. */
160 u32
161 make_timestamp (void)
162 {
163   time_t t = gnupg_get_time ();
164   return (u32)t;
165 }
166
167
168
169 /****************
170  * Scan a date string and return a timestamp.
171  * The only supported format is "yyyy-mm-dd"
172  * Returns 0 for an invalid date.
173  */
174 u32
175 scan_isodatestr( const char *string )
176 {
177     int year, month, day;
178     struct tm tmbuf;
179     time_t stamp;
180     int i;
181
182     if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
183         return 0;
184     for( i=0; i < 4; i++ )
185         if( !digitp (string+i) )
186             return 0;
187     if( !digitp (string+5) || !digitp(string+6) )
188         return 0;
189     if( !digitp(string+8) || !digitp(string+9) )
190         return 0;
191     year = atoi(string);
192     month = atoi(string+5);
193     day = atoi(string+8);
194     /* some basic checks */
195     if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
196         return 0;
197     memset( &tmbuf, 0, sizeof tmbuf );
198     tmbuf.tm_mday = day;
199     tmbuf.tm_mon = month-1;
200     tmbuf.tm_year = year - 1900;
201     tmbuf.tm_isdst = -1;
202     stamp = mktime( &tmbuf );
203     if( stamp == (time_t)-1 )
204         return 0;
205     return stamp;
206 }
207
208
209 int
210 isotime_p (const char *string)
211 {
212   const char *s;
213   int i;
214
215   if (!*string)
216     return 0;
217   for (s=string, i=0; i < 8; i++, s++)
218     if (!digitp (s))
219       return 0;
220   if (*s != 'T')
221       return 0;
222   for (s++, i=9; i < 15; i++, s++)
223     if (!digitp (s))
224       return 0;
225   if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
226     return 0;  /* Wrong delimiter.  */
227
228   return 1;
229 }
230
231
232 /* Scan a string and return true if the string represents the human
233    readable format of an ISO time.  This format is:
234       yyyy-mm-dd[ hh[:mm[:ss]]]
235    Scanning stops at the second space or at a comma.  If DATE_ONLY is
236    true the time part is not expected and the scanning stops at the
237    first space or at a comma. */
238 int
239 isotime_human_p (const char *string, int date_only)
240 {
241   const char *s;
242   int i;
243
244   if (!*string)
245     return 0;
246   for (s=string, i=0; i < 4; i++, s++)
247     if (!digitp (s))
248       return 0;
249   if (*s != '-')
250     return 0;
251   s++;
252   if (!digitp (s) || !digitp (s+1) || s[2] != '-')
253     return 0;
254   i = atoi_2 (s);
255   if (i < 1 || i > 12)
256     return 0;
257   s += 3;
258   if (!digitp (s) || !digitp (s+1))
259     return 0;
260   i = atoi_2 (s);
261   if (i < 1 || i > 31)
262     return 0;
263   s += 2;
264   if (!*s || *s == ',')
265     return 1; /* Okay; only date given.  */
266   if (!spacep (s))
267     return 0;
268   if (date_only)
269     return 1; /* Okay; only date was requested.  */
270   s++;
271   if (spacep (s))
272     return 1; /* Okay, second space stops scanning.  */
273   if (!digitp (s) || !digitp (s+1))
274     return 0;
275   i = atoi_2 (s);
276   if (i < 0 || i > 23)
277     return 0;
278   s += 2;
279   if (!*s || *s == ',')
280     return 1; /* Okay; only date and hour given.  */
281   if (*s != ':')
282     return 0;
283   s++;
284   if (!digitp (s) || !digitp (s+1))
285     return 0;
286   i = atoi_2 (s);
287   if (i < 0 || i > 59)
288     return 0;
289   s += 2;
290   if (!*s || *s == ',')
291     return 1; /* Okay; only date, hour and minute given.  */
292   if (*s != ':')
293     return 0;
294   s++;
295   if (!digitp (s) || !digitp (s+1))
296     return 0;
297   i = atoi_2 (s);
298   if (i < 0 || i > 60)
299     return 0;
300   s += 2;
301   if (!*s || *s == ',' || spacep (s))
302     return 1; /* Okay; date, hour and minute and second given.  */
303
304   return 0; /* Unexpected delimiter.  */
305 }
306
307 /* Convert a standard isotime or a human readable variant into an
308    isotime structure.  The allowed formats are those described by
309    isotime_p and isotime_human_p.  The function returns 0 on failure
310    or the length of the scanned string on success.  */
311 size_t
312 string2isotime (gnupg_isotime_t atime, const char *string)
313 {
314   gnupg_isotime_t dummyatime;
315
316   if (!atime)
317     atime = dummyatime;
318
319   atime[0] = 0;
320   if (isotime_p (string))
321     {
322       memcpy (atime, string, 15);
323       atime[15] = 0;
324       return 15;
325     }
326   if (!isotime_human_p (string, 0))
327     return 0;
328   atime[0] = string[0];
329   atime[1] = string[1];
330   atime[2] = string[2];
331   atime[3] = string[3];
332   atime[4] = string[5];
333   atime[5] = string[6];
334   atime[6] = string[8];
335   atime[7] = string[9];
336   atime[8] = 'T';
337   memset (atime+9, '0', 6);
338   atime[15] = 0;
339   if (!spacep (string+10))
340     return 10;
341   if (spacep (string+11))
342     return 11; /* As per def, second space stops scanning.  */
343   atime[9] = string[11];
344   atime[10] = string[12];
345   if (string[13] != ':')
346     return 13;
347   atime[11] = string[14];
348   atime[12] = string[15];
349   if (string[16] != ':')
350     return 16;
351   atime[13] = string[17];
352   atime[14] = string[18];
353   return 19;
354 }
355
356
357 /* Scan an ISO timestamp and return an Epoch based timestamp.  The only
358    supported format is "yyyymmddThhmmss" delimited by white space, nul, a
359    colon or a comma.  Returns (time_t)(-1) for an invalid string.  */
360 time_t
361 isotime2epoch (const char *string)
362 {
363   int year, month, day, hour, minu, sec;
364   struct tm tmbuf;
365
366   if (!isotime_p (string))
367     return (time_t)(-1);
368
369   year  = atoi_4 (string);
370   month = atoi_2 (string + 4);
371   day   = atoi_2 (string + 6);
372   hour  = atoi_2 (string + 9);
373   minu  = atoi_2 (string + 11);
374   sec   = atoi_2 (string + 13);
375
376   /* Basic checks.  */
377   if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
378       || hour > 23 || minu > 59 || sec > 61 )
379     return (time_t)(-1);
380
381   memset (&tmbuf, 0, sizeof tmbuf);
382   tmbuf.tm_sec  = sec;
383   tmbuf.tm_min  = minu;
384   tmbuf.tm_hour = hour;
385   tmbuf.tm_mday = day;
386   tmbuf.tm_mon  = month-1;
387   tmbuf.tm_year = year - 1900;
388   tmbuf.tm_isdst = -1;
389   return timegm (&tmbuf);
390 }
391
392
393 /* Convert an Epoch time to an iso time stamp. */
394 void
395 epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
396 {
397   if (atime == (time_t)(-1))
398     *timebuf = 0;
399   else
400     {
401       struct tm *tp;
402 #ifdef HAVE_GMTIME_R
403       struct tm tmbuf;
404
405       tp = gmtime_r (&atime, &tmbuf);
406 #else
407       tp = gmtime (&atime);
408 #endif
409       snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
410                 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
411                 tp->tm_hour, tp->tm_min, tp->tm_sec);
412     }
413 }
414
415
416 /* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
417    Returns 0 on success.  */
418 int
419 isodate_human_to_tm (const char *string, struct tm *t)
420 {
421   int year, month, day;
422
423   if (!isotime_human_p (string, 1))
424     return -1;
425
426   year  = atoi_4 (string);
427   month = atoi_2 (string + 5);
428   day   = atoi_2 (string + 8);
429
430   /* Basic checks.  */
431   if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
432     return -1;
433
434   memset (t, 0, sizeof *t);
435   t->tm_sec  = 0;
436   t->tm_min  = 0;
437   t->tm_hour = 0;
438   t->tm_mday = day;
439   t->tm_mon  = month-1;
440   t->tm_year = year - 1900;
441   t->tm_isdst = -1;
442   return 0;
443 }
444
445
446 /* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
447    If you change it, then update the other one too.  */
448 #ifdef HAVE_W32_SYSTEM
449 static time_t
450 _win32_timegm (struct tm *tm)
451 {
452   /* This one is thread safe.  */
453   SYSTEMTIME st;
454   FILETIME ft;
455   unsigned long long cnsecs;
456
457   st.wYear   = tm->tm_year + 1900;
458   st.wMonth  = tm->tm_mon  + 1;
459   st.wDay    = tm->tm_mday;
460   st.wHour   = tm->tm_hour;
461   st.wMinute = tm->tm_min;
462   st.wSecond = tm->tm_sec;
463   st.wMilliseconds = 0; /* Not available.  */
464   st.wDayOfWeek = 0;    /* Ignored.  */
465
466   /* System time is UTC thus the conversion is pretty easy.  */
467   if (!SystemTimeToFileTime (&st, &ft))
468     {
469       gpg_err_set_errno (EINVAL);
470       return (time_t)(-1);
471     }
472
473   cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
474             | ft.dwLowDateTime);
475   cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
476   return (time_t)(cnsecs / 10000000ULL);
477 }
478 #endif
479
480
481 /* Parse the string TIMESTAMP into a time_t.  The string may either be
482    seconds since Epoch or in the ISO 8601 format like
483    "20390815T143012".  Returns 0 for an empty string or seconds since
484    Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
485    point to the next non-parsed character in TIMESTRING.
486
487    This function is a copy of
488    gpgme/src/conversion.c:_gpgme_parse_timestamp.  If you change it,
489    then update the other one too.  */
490 time_t
491 parse_timestamp (const char *timestamp, char **endp)
492 {
493   /* Need to skip leading spaces, because that is what strtoul does
494      but not our ISO 8601 checking code. */
495   while (*timestamp && *timestamp== ' ')
496     timestamp++;
497   if (!*timestamp)
498     return 0;
499
500   if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
501     {
502       struct tm buf;
503       int year;
504
505       year = atoi_4 (timestamp);
506       if (year < 1900)
507         return (time_t)(-1);
508
509       if (endp)
510         *endp = (char*)(timestamp + 15);
511
512       /* Fixme: We would better use a configure test to see whether
513          mktime can handle dates beyond 2038. */
514       if (sizeof (time_t) <= 4 && year >= 2038)
515         return (time_t)2145914603; /* 2037-12-31 23:23:23 */
516
517       memset (&buf, 0, sizeof buf);
518       buf.tm_year = year - 1900;
519       buf.tm_mon = atoi_2 (timestamp+4) - 1;
520       buf.tm_mday = atoi_2 (timestamp+6);
521       buf.tm_hour = atoi_2 (timestamp+9);
522       buf.tm_min = atoi_2 (timestamp+11);
523       buf.tm_sec = atoi_2 (timestamp+13);
524
525 #ifdef HAVE_W32_SYSTEM
526       return _win32_timegm (&buf);
527 #else
528 #ifdef HAVE_TIMEGM
529       return timegm (&buf);
530 #else
531       {
532         time_t tim;
533
534         putenv ("TZ=UTC");
535         tim = mktime (&buf);
536 #ifdef __GNUC__
537 #warning fixme: we must somehow reset TZ here.  It is not threadsafe anyway.
538 #endif
539         return tim;
540       }
541 #endif /* !HAVE_TIMEGM */
542 #endif /* !HAVE_W32_SYSTEM */
543     }
544   else
545     return (time_t)strtoul (timestamp, endp, 10);
546 }
547
548
549
550 u32
551 add_days_to_timestamp( u32 stamp, u16 days )
552 {
553     return stamp + days*86400L;
554 }
555
556
557 /****************
558  * Return a string with a time value in the form: x Y, n D, n H
559  */
560
561 const char *
562 strtimevalue( u32 value )
563 {
564     static char buffer[30];
565     unsigned int years, days, hours, minutes;
566
567     value /= 60;
568     minutes = value % 60;
569     value /= 60;
570     hours = value % 24;
571     value /= 24;
572     days = value % 365;
573     value /= 365;
574     years = value;
575
576     sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
577     if( years )
578         return buffer;
579     if( days )
580         return strchr( buffer, 'y' ) + 1;
581     return strchr( buffer, 'd' ) + 1;
582 }
583
584
585
586 /* Return a malloced string with the time elapsed between NOW and
587    SINCE.  May return NULL on error. */
588 char *
589 elapsed_time_string (time_t since, time_t now)
590 {
591   char *result;
592   double diff;
593   unsigned long value;
594   unsigned int days, hours, minutes, seconds;
595
596   if (!now)
597     now = gnupg_get_time ();
598
599   diff = difftime (now, since);
600   if (diff < 0)
601     return xtrystrdup ("time-warp");
602
603   seconds = (unsigned long)diff % 60;
604   value = (unsigned long)(diff / 60);
605   minutes = value % 60;
606   value /= 60;
607   hours = value % 24;
608   value /= 24;
609   days = value % 365;
610
611   if (days)
612     result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds);
613   else if (hours)
614     result = xtryasprintf ("%uh%um%us", hours, minutes, seconds);
615   else if (minutes)
616     result = xtryasprintf ("%um%us", minutes, seconds);
617   else
618     result = xtryasprintf ("%us", seconds);
619
620   return result;
621 }
622
623
624 /*
625  * Note: this function returns GMT
626  */
627 const char *
628 strtimestamp (u32 stamp)
629 {
630   static char buffer[11+5];
631   struct tm *tp;
632   time_t atime = stamp;
633
634   if (IS_INVALID_TIME_T (atime))
635     {
636       strcpy (buffer, "????" "-??" "-??");
637     }
638   else
639     {
640       tp = gmtime( &atime );
641       snprintf (buffer, sizeof buffer, "%04d-%02d-%02d",
642                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
643     }
644   return buffer;
645 }
646
647
648 /*
649  * Note: this function returns GMT
650  */
651 const char *
652 isotimestamp (u32 stamp)
653 {
654   static char buffer[25+5];
655   struct tm *tp;
656   time_t atime = stamp;
657
658   if (IS_INVALID_TIME_T (atime))
659     {
660       strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
661     }
662   else
663     {
664       tp = gmtime ( &atime );
665       snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
666                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
667                 tp->tm_hour, tp->tm_min, tp->tm_sec);
668     }
669   return buffer;
670 }
671
672
673 /****************
674  * Note: this function returns local time
675  */
676 const char *
677 asctimestamp (u32 stamp)
678 {
679   static char buffer[50];
680 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
681   static char fmt[50];
682 #endif
683   struct tm *tp;
684   time_t atime = stamp;
685
686   if (IS_INVALID_TIME_T (atime))
687     {
688       strcpy (buffer, "????" "-??" "-??");
689       return buffer;
690     }
691
692   tp = localtime( &atime );
693 #ifdef HAVE_STRFTIME
694 # if defined(HAVE_NL_LANGINFO)
695   mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
696   if (!strstr( fmt, "%Z" ))
697     strcat( fmt, " %Z");
698   /* NOTE: gcc -Wformat-noliteral will complain here.  I have found no
699      way to suppress this warning.  */
700   strftime (buffer, DIM(buffer)-1, fmt, tp);
701 # elif defined(HAVE_W32CE_SYSTEM)
702   /* tzset is not available but %Z nevertheless prints a default
703      nonsense timezone ("WILDABBR").  Thus we don't print the time
704      zone at all.  */
705   strftime (buffer, DIM(buffer)-1, "%c", tp);
706 # else
707    /* FIXME: we should check whether the locale appends a " %Z" These
708     * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
709     * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN.  */
710   strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
711 # endif
712   buffer[DIM(buffer)-1] = 0;
713 #else
714   mem2str( buffer, asctime(tp), DIM(buffer) );
715 #endif
716   return buffer;
717 }
718
719
720 /* Return the timestamp STAMP in RFC-2822 format.  This is always done
721  * in the C locale.  We return the gmtime to avoid computing the
722  * timezone. The caller must release the returned string.
723  *
724  * Example: "Mon, 27 Jun 2016 1:42:00 +0000".
725  */
726 char *
727 rfctimestamp (u32 stamp)
728 {
729   time_t atime = stamp;
730   struct tm tmbuf, *tp;
731
732
733   if (IS_INVALID_TIME_T (atime))
734     {
735       gpg_err_set_errno (EINVAL);
736       return NULL;
737     }
738
739   tp = gnupg_gmtime (&atime, &tmbuf);
740   if (!tp)
741     return NULL;
742   return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000",
743                        &"SunMonTueWedThuFriSat"[(tp->tm_wday%7)*3],
744                        tp->tm_mday,
745                        &"JanFebMarAprMayJunJulAugSepOctNovDec"
746                        [(tp->tm_mon%12)*3],
747                        tp->tm_year + 1900,
748                        tp->tm_hour,
749                        tp->tm_min,
750                        tp->tm_sec);
751 }
752
753
754 static int
755 days_per_year (int y)
756 {
757   int s ;
758
759   s = !(y % 4);
760   if ( !(y % 100))
761     if ((y%400))
762       s = 0;
763   return s ? 366 : 365;
764 }
765
766 static int
767 days_per_month (int y, int m)
768 {
769   int s;
770
771   switch(m)
772     {
773     case 1: case 3: case 5: case 7: case 8: case 10: case 12:
774       return 31 ;
775     case 2:
776       s = !(y % 4);
777       if (!(y % 100))
778         if ((y % 400))
779           s = 0;
780       return s? 29 : 28 ;
781     case 4: case 6: case 9: case 11:
782       return 30;
783     }
784   BUG();
785 }
786
787
788 /* Convert YEAR, MONTH and DAY into the Julian date.  We assume that
789    it is already noon.  We do not support dates before 1582-10-15. */
790 static unsigned long
791 date2jd (int year, int month, int day)
792 {
793   unsigned long jd;
794
795   jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
796   if (month < 3)
797     year-- ;
798   else
799     jd -= (4 * month + 23) / 10;
800
801   jd += year / 4 - ((year / 100 + 1) *3) / 4;
802
803   return jd ;
804 }
805
806 /* Convert a Julian date back to YEAR, MONTH and DAY.  Return day of
807    the year or 0 on error.  This function uses some more or less
808    arbitrary limits, most important is that days before 1582 are not
809    supported. */
810 static int
811 jd2date (unsigned long jd, int *year, int *month, int *day)
812 {
813   int y, m, d;
814   long delta;
815
816   if (!jd)
817     return 0 ;
818   if (jd < 1721425 || jd > 2843085)
819     return 0;
820
821   y = (jd - JD_DIFF) / 366;
822   d = m = 1;
823
824   while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
825     y++;
826
827   m = (delta / 31) + 1;
828   while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
829     if (++m > 12)
830       {
831         m = 1;
832         y++;
833       }
834
835   d = delta + 1 ;
836   if (d > days_per_month (y, m))
837     {
838       d = 1;
839       m++;
840     }
841   if (m > 12)
842     {
843       m = 1;
844       y++;
845     }
846
847   if (year)
848     *year = y;
849   if (month)
850     *month = m;
851   if (day)
852     *day = d ;
853
854   return (jd - date2jd (y, 1, 1)) + 1;
855 }
856
857
858 /* Check that the 15 bytes in ATIME represent a valid ISO time.  Note
859    that this function does not expect a string but a plain 15 byte
860    isotime buffer. */
861 gpg_error_t
862 check_isotime (const gnupg_isotime_t atime)
863 {
864   int i;
865   const char *s;
866
867   if (!*atime)
868     return gpg_error (GPG_ERR_NO_VALUE);
869
870   for (s=atime, i=0; i < 8; i++, s++)
871     if (!digitp (s))
872       return gpg_error (GPG_ERR_INV_TIME);
873   if (*s != 'T')
874       return gpg_error (GPG_ERR_INV_TIME);
875   for (s++, i=9; i < 15; i++, s++)
876     if (!digitp (s))
877       return gpg_error (GPG_ERR_INV_TIME);
878   return 0;
879 }
880
881
882 /* Dump the ISO time T to the log stream without a LF.  */
883 void
884 dump_isotime (const gnupg_isotime_t t)
885 {
886   if (!t || !*t)
887     log_printf ("%s", _("[none]"));
888   else
889     log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
890                 t, t+4, t+6, t+9, t+11, t+13);
891 }
892
893
894 /* Copy one ISO date to another, this is inline so that we can do a
895    minimal sanity check.  A null date (empty string) is allowed.  */
896 void
897 gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
898 {
899   if (*s)
900     {
901       if ((strlen (s) != 15 || s[8] != 'T'))
902         BUG();
903       memcpy (d, s, 15);
904       d[15] = 0;
905     }
906   else
907     *d = 0;
908 }
909
910
911 /* Add SECONDS to ATIME.  SECONDS may not be negative and is limited
912    to about the equivalent of 62 years which should be more then
913    enough for our purposes. */
914 gpg_error_t
915 add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
916 {
917   gpg_error_t err;
918   int year, month, day, hour, minute, sec, ndays;
919   unsigned long jd;
920
921   err = check_isotime (atime);
922   if (err)
923     return err;
924
925   if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
926     return gpg_error (GPG_ERR_INV_VALUE);
927
928   year  = atoi_4 (atime+0);
929   month = atoi_2 (atime+4);
930   day   = atoi_2 (atime+6);
931   hour  = atoi_2 (atime+9);
932   minute= atoi_2 (atime+11);
933   sec   = atoi_2 (atime+13);
934
935   if (year <= 1582) /* The julian date functions don't support this. */
936     return gpg_error (GPG_ERR_INV_VALUE);
937
938   sec    += nseconds;
939   minute += sec/60;
940   sec    %= 60;
941   hour   += minute/60;
942   minute %= 60;
943   ndays  = hour/24;
944   hour   %= 24;
945
946   jd = date2jd (year, month, day) + ndays;
947   jd2date (jd, &year, &month, &day);
948
949   if (year > 9999 || month > 12 || day > 31
950       || year < 0 || month < 1 || day < 1)
951     return gpg_error (GPG_ERR_INV_VALUE);
952
953   snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
954             year, month, day, hour, minute, sec);
955   return 0;
956 }
957
958
959 gpg_error_t
960 add_days_to_isotime (gnupg_isotime_t atime, int ndays)
961 {
962   gpg_error_t err;
963   int year, month, day, hour, minute, sec;
964   unsigned long jd;
965
966   err = check_isotime (atime);
967   if (err)
968     return err;
969
970   if (ndays < 0 || ndays >= 9999*366 )
971     return gpg_error (GPG_ERR_INV_VALUE);
972
973   year  = atoi_4 (atime+0);
974   month = atoi_2 (atime+4);
975   day   = atoi_2 (atime+6);
976   hour  = atoi_2 (atime+9);
977   minute= atoi_2 (atime+11);
978   sec   = atoi_2 (atime+13);
979
980   if (year <= 1582) /* The julian date functions don't support this. */
981     return gpg_error (GPG_ERR_INV_VALUE);
982
983   jd = date2jd (year, month, day) + ndays;
984   jd2date (jd, &year, &month, &day);
985
986   if (year > 9999 || month > 12 || day > 31
987       || year < 0 || month < 1 || day < 1)
988     return gpg_error (GPG_ERR_INV_VALUE);
989
990   snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
991             year, month, day, hour, minute, sec);
992   return 0;
993 }