1 /* gettime.c - Wrapper for time functions
2 * Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #ifdef HAVE_LANGINFO_H
32 static unsigned long timewarp;
33 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
35 /* Correction used to map to real Julian days. */
36 #define JD_DIFF 1721060L
39 /* Wrapper for the time(3). We use this here so we can fake the time
44 time_t current = time (NULL);
45 if (timemode == NORMAL)
47 else if (timemode == FROZEN)
49 else if (timemode == FUTURE)
50 return current + timewarp;
52 return current - timewarp;
56 /* Return the current time (possibly faked) in ISO format. */
58 gnupg_get_isotime (gnupg_isotime_t timebuf)
60 time_t atime = gnupg_get_time ();
70 tp = gmtime_r (&atime, &tmbuf);
74 snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
75 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
76 tp->tm_hour, tp->tm_min, tp->tm_sec);
81 /* Set the time to NEWTIME so that gnupg_get_time returns a time
82 starting with this one. With FREEZE set to 1 the returned time
83 will never change. Just for completeness, a value of (time_t)-1
84 for NEWTIME gets you back to reality. Note that this is obviously
85 not thread-safe but this is not required. */
87 gnupg_set_time (time_t newtime, int freeze)
89 time_t current = time (NULL);
91 if ( newtime == (time_t)-1 || current == newtime)
101 else if (newtime > current)
104 timewarp = newtime - current;
109 timewarp = current - newtime;
113 /* Returns true when we are in timewarp mode */
115 gnupg_faked_time_p (void)
121 /* This function is used by gpg because OpenPGP defines the timestamp
122 as an unsigned 32 bit value. */
124 make_timestamp (void)
126 time_t t = gnupg_get_time ();
129 log_fatal ("gnupg_get_time() failed\n");
136 * Scan a date string and return a timestamp.
137 * The only supported format is "yyyy-mm-dd"
138 * Returns 0 for an invalid date.
141 scan_isodatestr( const char *string )
143 int year, month, day;
148 if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
150 for( i=0; i < 4; i++ )
151 if( !digitp (string+i) )
153 if( !digitp (string+5) || !digitp(string+6) )
155 if( !digitp(string+8) || !digitp(string+9) )
158 month = atoi(string+5);
159 day = atoi(string+8);
160 /* some basic checks */
161 if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
163 memset( &tmbuf, 0, sizeof tmbuf );
165 tmbuf.tm_mon = month-1;
166 tmbuf.tm_year = year - 1900;
168 stamp = mktime( &tmbuf );
169 if( stamp == (time_t)-1 )
174 /* Scan am ISO timestamp and return an Epoch based timestamp. The only
175 supported format is "yyyymmddThhmmss" delimited by white space, nul, a
176 colon or a comma. Returns (time_t)(-1) for an invalid string. */
178 isotime2epoch (const char *string)
181 int year, month, day, hour, minu, sec;
187 for (s=string, i=0; i < 8; i++, s++)
192 for (s++, i=9; i < 15; i++, s++)
195 if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
196 return (time_t)(-1); /* Wrong delimiter. */
198 year = atoi_4 (string);
199 month = atoi_2 (string + 4);
200 day = atoi_2 (string + 6);
201 hour = atoi_2 (string + 9);
202 minu = atoi_2 (string + 11);
203 sec = atoi_2 (string + 13);
206 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
207 || hour > 23 || minu > 59 || sec > 61 )
210 memset (&tmbuf, 0, sizeof tmbuf);
213 tmbuf.tm_hour = hour;
215 tmbuf.tm_mon = month-1;
216 tmbuf.tm_year = year - 1900;
218 return timegm (&tmbuf);
222 /* Convert an Epoch time to an iso time stamp. */
224 epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
234 tp = gmtime_r (&atime, &tmbuf);
236 tp = gmtime (&atime);
238 snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
239 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
240 tp->tm_hour, tp->tm_min, tp->tm_sec);
248 add_days_to_timestamp( u32 stamp, u16 days )
250 return stamp + days*86400L;
255 * Return a string with a time value in the form: x Y, n D, n H
259 strtimevalue( u32 value )
261 static char buffer[30];
262 unsigned int years, days, hours, minutes;
265 minutes = value % 60;
273 sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
277 return strchr( buffer, 'y' ) + 1;
278 return strchr( buffer, 'd' ) + 1;
283 * Note: this function returns GMT
286 strtimestamp( u32 stamp )
288 static char buffer[11+5];
290 time_t atime = stamp;
293 strcpy (buffer, "????" "-??" "-??");
296 tp = gmtime( &atime );
297 sprintf(buffer,"%04d-%02d-%02d",
298 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
305 * Note: this function returns GMT
308 isotimestamp (u32 stamp)
310 static char buffer[25+5];
312 time_t atime = stamp;
316 strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
320 tp = gmtime ( &atime );
321 sprintf (buffer,"%04d-%02d-%02d %02d:%02d:%02d",
322 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
323 tp->tm_hour, tp->tm_min, tp->tm_sec);
330 * Note: this function returns local time
333 asctimestamp (u32 stamp)
335 static char buffer[50];
336 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
340 time_t atime = stamp;
344 strcpy (buffer, "????" "-??" "-??");
348 tp = localtime( &atime );
350 # if defined(HAVE_NL_LANGINFO)
351 mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
352 if (!strstr( fmt, "%Z" ))
354 /* NOTE: gcc -Wformat-noliteral will complain here. I have found no
355 way to suppress this warning. */
356 strftime (buffer, DIM(buffer)-1, fmt, tp);
357 # elif defined(HAVE_W32CE_SYSTEM)
358 /* tzset is not available but %Z nevertheless prints a default
359 nonsense timezone ("WILDABBR"). Thus we don't print the time
361 strftime (buffer, DIM(buffer)-1, "%c", tp);
363 /* FIXME: we should check whether the locale appends a " %Z" These
364 * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
365 * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN. */
366 strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
368 buffer[DIM(buffer)-1] = 0;
370 mem2str( buffer, asctime(tp), DIM(buffer) );
378 days_per_year (int y)
386 return s ? 366 : 365;
390 days_per_month (int y, int m)
396 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
404 case 4: case 6: case 9: case 11:
411 /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
412 it is already noon. We do not support dates before 1582-10-15. */
414 date2jd (int year, int month, int day)
418 jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
422 jd -= (4 * month + 23) / 10;
424 jd += year / 4 - ((year / 100 + 1) *3) / 4;
429 /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
430 the year or 0 on error. This function uses some more or less
431 arbitrary limits, most important is that days before 1582 are not
434 jd2date (unsigned long jd, int *year, int *month, int *day)
441 if (jd < 1721425 || jd > 2843085)
444 y = (jd - JD_DIFF) / 366;
447 while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
450 m = (delta / 31) + 1;
451 while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
459 if (d > days_per_month (y, m))
477 return (jd - date2jd (y, 1, 1)) + 1;
481 /* Check that the 15 bytes in ATIME represent a valid ISO time. Note
482 that this function does not expect a string but a plain 15 byte
485 check_isotime (const gnupg_isotime_t atime)
491 return gpg_error (GPG_ERR_NO_VALUE);
493 for (s=atime, i=0; i < 8; i++, s++)
495 return gpg_error (GPG_ERR_INV_TIME);
497 return gpg_error (GPG_ERR_INV_TIME);
498 for (s++, i=9; i < 15; i++, s++)
500 return gpg_error (GPG_ERR_INV_TIME);
505 /* Dump the ISO time T to the log stream without a LF. */
507 dump_isotime (const gnupg_isotime_t t)
510 log_printf ("%s", _("[none]"));
512 log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
513 t, t+4, t+6, t+9, t+11, t+13);
517 /* Copy one ISO date to another, this is inline so that we can do a
518 minimal sanity check. A null date (empty string) is allowed. */
520 gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
524 if ((strlen (s) != 15 || s[8] != 'T'))
534 /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
535 to about the equivalent of 62 years which should be more then
536 enough for our purposes. */
538 add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
541 int year, month, day, hour, minute, sec, ndays;
544 err = check_isotime (atime);
548 if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
549 return gpg_error (GPG_ERR_INV_VALUE);
551 year = atoi_4 (atime+0);
552 month = atoi_2 (atime+4);
553 day = atoi_2 (atime+6);
554 hour = atoi_2 (atime+9);
555 minute= atoi_2 (atime+11);
556 sec = atoi_2 (atime+13);
558 if (year <= 1582) /* The julian date functions don't support this. */
559 return gpg_error (GPG_ERR_INV_VALUE);
569 jd = date2jd (year, month, day) + ndays;
570 jd2date (jd, &year, &month, &day);
572 if (year > 9999 || month > 12 || day > 31
573 || year < 0 || month < 1 || day < 1)
574 return gpg_error (GPG_ERR_INV_VALUE);
576 snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
577 year, month, day, hour, minute, sec);
583 add_days_to_isotime (gnupg_isotime_t atime, int ndays)
586 int year, month, day, hour, minute, sec;
589 err = check_isotime (atime);
593 if (ndays < 0 || ndays >= 9999*366 )
594 return gpg_error (GPG_ERR_INV_VALUE);
596 year = atoi_4 (atime+0);
597 month = atoi_2 (atime+4);
598 day = atoi_2 (atime+6);
599 hour = atoi_2 (atime+9);
600 minute= atoi_2 (atime+11);
601 sec = atoi_2 (atime+13);
603 if (year <= 1582) /* The julian date functions don't support this. */
604 return gpg_error (GPG_ERR_INV_VALUE);
606 jd = date2jd (year, month, day) + ndays;
607 jd2date (jd, &year, &month, &day);
609 if (year > 9999 || month > 12 || day > 31
610 || year < 0 || month < 1 || day < 1)
611 return gpg_error (GPG_ERR_INV_VALUE);
613 snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
614 year, month, day, hour, minute, sec);