Return the balance of a Geldkarte.
[gnupg.git] / common / gettime.c
blobc4a9d48449acf5a187e2d9be879144cc97fdb3d2
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/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <ctype.h>
24 #ifdef HAVE_LANGINFO_H
25 #include <langinfo.h>
26 #endif
28 #include "util.h"
30 static unsigned long timewarp;
31 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
33 /* Correction used to map to real Julian days. */
34 #define JD_DIFF 1721060L
37 /* Wrapper for the time(3). We use this here so we can fake the time
38 for tests */
39 time_t
40 gnupg_get_time ()
42 time_t current = time (NULL);
43 if (timemode == NORMAL)
44 return current;
45 else if (timemode == FROZEN)
46 return timewarp;
47 else if (timemode == FUTURE)
48 return current + timewarp;
49 else
50 return current - timewarp;
54 /* Return the current time (possibly faked) in ISO format. */
55 void
56 gnupg_get_isotime (gnupg_isotime_t timebuf)
58 time_t atime = gnupg_get_time ();
60 if (atime < 0)
61 *timebuf = 0;
62 else
64 struct tm *tp;
65 #ifdef HAVE_GMTIME_R
66 struct tm tmbuf;
68 tp = gmtime_r (&atime, &tmbuf);
69 #else
70 tp = gmtime (&atime);
71 #endif
72 snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
73 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
74 tp->tm_hour, tp->tm_min, tp->tm_sec);
79 /* Set the time to NEWTIME so that gnupg_get_time returns a time
80 starting with this one. With FREEZE set to 1 the returned time
81 will never change. Just for completeness, a value of (time_t)-1
82 for NEWTIME gets you back to reality. Note that this is obviously
83 not thread-safe but this is not required. */
84 void
85 gnupg_set_time (time_t newtime, int freeze)
87 time_t current = time (NULL);
89 if ( newtime == (time_t)-1 || current == newtime)
91 timemode = NORMAL;
92 timewarp = 0;
94 else if (freeze)
96 timemode = FROZEN;
97 timewarp = current;
99 else if (newtime > current)
101 timemode = FUTURE;
102 timewarp = newtime - current;
104 else
106 timemode = PAST;
107 timewarp = current - newtime;
111 /* Returns true when we are in timewarp mode */
113 gnupg_faked_time_p (void)
115 return timemode;
119 /* This function is used by gpg because OpenPGP defines the timestamp
120 as an unsigned 32 bit value. */
121 u32
122 make_timestamp (void)
124 time_t t = gnupg_get_time ();
126 if (t == (time_t)-1)
127 log_fatal ("gnupg_get_time() failed\n");
128 return (u32)t;
133 /****************
134 * Scan a date string and return a timestamp.
135 * The only supported format is "yyyy-mm-dd"
136 * Returns 0 for an invalid date.
139 scan_isodatestr( const char *string )
141 int year, month, day;
142 struct tm tmbuf;
143 time_t stamp;
144 int i;
146 if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
147 return 0;
148 for( i=0; i < 4; i++ )
149 if( !digitp (string+i) )
150 return 0;
151 if( !digitp (string+5) || !digitp(string+6) )
152 return 0;
153 if( !digitp(string+8) || !digitp(string+9) )
154 return 0;
155 year = atoi(string);
156 month = atoi(string+5);
157 day = atoi(string+8);
158 /* some basic checks */
159 if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
160 return 0;
161 memset( &tmbuf, 0, sizeof tmbuf );
162 tmbuf.tm_mday = day;
163 tmbuf.tm_mon = month-1;
164 tmbuf.tm_year = year - 1900;
165 tmbuf.tm_isdst = -1;
166 stamp = mktime( &tmbuf );
167 if( stamp == (time_t)-1 )
168 return 0;
169 return stamp;
172 /* Scan am ISO timestamp and return an Epoch based timestamp. The only
173 supported format is "yyyymmddThhmmss" delimited by white space, nul, a
174 colon or a comma. Returns (time_t)(-1) for an invalid string. */
175 time_t
176 isotime2epoch (const char *string)
178 const char *s;
179 int year, month, day, hour, minu, sec;
180 struct tm tmbuf;
181 int i;
183 if (!*string)
184 return (time_t)(-1);
185 for (s=string, i=0; i < 8; i++, s++)
186 if (!digitp (s))
187 return (time_t)(-1);
188 if (*s != 'T')
189 return (time_t)(-1);
190 for (s++, i=9; i < 15; i++, s++)
191 if (!digitp (s))
192 return (time_t)(-1);
193 if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
194 return (time_t)(-1); /* Wrong delimiter. */
196 year = atoi_4 (string);
197 month = atoi_2 (string + 4);
198 day = atoi_2 (string + 6);
199 hour = atoi_2 (string + 9);
200 minu = atoi_2 (string + 11);
201 sec = atoi_2 (string + 13);
203 /* Basic checks. */
204 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
205 || hour > 23 || minu > 59 || sec > 61 )
206 return (time_t)(-1);
208 memset (&tmbuf, 0, sizeof tmbuf);
209 tmbuf.tm_sec = sec;
210 tmbuf.tm_min = minu;
211 tmbuf.tm_hour = hour;
212 tmbuf.tm_mday = day;
213 tmbuf.tm_mon = month-1;
214 tmbuf.tm_year = year - 1900;
215 tmbuf.tm_isdst = -1;
216 return timegm (&tmbuf);
220 /* Convert an Epoch time to an iso time stamp. */
221 void
222 epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
224 if (atime < 0)
225 *timebuf = 0;
226 else
228 struct tm *tp;
229 #ifdef HAVE_GMTIME_R
230 struct tm tmbuf;
232 tp = gmtime_r (&atime, &tmbuf);
233 #else
234 tp = gmtime (&atime);
235 #endif
236 snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
237 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
238 tp->tm_hour, tp->tm_min, tp->tm_sec);
246 add_days_to_timestamp( u32 stamp, u16 days )
248 return stamp + days*86400L;
252 /****************
253 * Return a string with a time value in the form: x Y, n D, n H
256 const char *
257 strtimevalue( u32 value )
259 static char buffer[30];
260 unsigned int years, days, hours, minutes;
262 value /= 60;
263 minutes = value % 60;
264 value /= 60;
265 hours = value % 24;
266 value /= 24;
267 days = value % 365;
268 value /= 365;
269 years = value;
271 sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
272 if( years )
273 return buffer;
274 if( days )
275 return strchr( buffer, 'y' ) + 1;
276 return strchr( buffer, 'd' ) + 1;
281 * Note: this function returns GMT
283 const char *
284 strtimestamp( u32 stamp )
286 static char buffer[11+5];
287 struct tm *tp;
288 time_t atime = stamp;
290 if (atime < 0) {
291 strcpy (buffer, "????" "-??" "-??");
293 else {
294 tp = gmtime( &atime );
295 sprintf(buffer,"%04d-%02d-%02d",
296 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
298 return buffer;
303 * Note: this function returns GMT
305 const char *
306 isotimestamp (u32 stamp)
308 static char buffer[25+5];
309 struct tm *tp;
310 time_t atime = stamp;
312 if (atime < 0)
314 strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
316 else
318 tp = gmtime ( &atime );
319 sprintf (buffer,"%04d-%02d-%02d %02d:%02d:%02d",
320 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
321 tp->tm_hour, tp->tm_min, tp->tm_sec);
323 return buffer;
327 /****************
328 * Note: this function returns local time
330 const char *
331 asctimestamp( u32 stamp )
333 static char buffer[50];
334 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
335 static char fmt[50];
336 #endif
337 struct tm *tp;
338 time_t atime = stamp;
340 if (atime < 0) {
341 strcpy (buffer, "????" "-??" "-??");
342 return buffer;
345 tp = localtime( &atime );
346 #ifdef HAVE_STRFTIME
347 #if defined(HAVE_NL_LANGINFO)
348 mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
349 if( strstr( fmt, "%Z" ) == NULL )
350 strcat( fmt, " %Z");
351 /* NOTE: gcc -Wformat-noliteral will complain here. I have
352 found no way to suppress this warning .*/
353 strftime (buffer, DIM(buffer)-1, fmt, tp);
354 #else
355 /* FIXME: we should check whether the locale appends a " %Z"
356 * These locales from glibc don't put the " %Z":
357 * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN
359 strftime( buffer, DIM(buffer)-1, "%c %Z", tp );
360 #endif
361 buffer[DIM(buffer)-1] = 0;
362 #else
363 mem2str( buffer, asctime(tp), DIM(buffer) );
364 #endif
365 return buffer;
370 static int
371 days_per_year (int y)
373 int s ;
375 s = !(y % 4);
376 if ( !(y % 100))
377 if ((y%400))
378 s = 0;
379 return s ? 366 : 365;
382 static int
383 days_per_month (int y, int m)
385 int s;
387 switch(m)
389 case 1: case 3: case 5: case 7: case 8: case 10: case 12:
390 return 31 ;
391 case 2:
392 s = !(y % 4);
393 if (!(y % 100))
394 if ((y % 400))
395 s = 0;
396 return s? 29 : 28 ;
397 case 4: case 6: case 9: case 11:
398 return 30;
400 BUG();
404 /* Convert YEAR, MONTH and DAY into the Julian date. We assume that
405 it is already noon. We do not support dates before 1582-10-15. */
406 static unsigned long
407 date2jd (int year, int month, int day)
409 unsigned long jd;
411 jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
412 if (month < 3)
413 year-- ;
414 else
415 jd -= (4 * month + 23) / 10;
417 jd += year / 4 - ((year / 100 + 1) *3) / 4;
419 return jd ;
422 /* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
423 the year or 0 on error. This function uses some more or less
424 arbitrary limits, most important is that days before 1582 are not
425 supported. */
426 static int
427 jd2date (unsigned long jd, int *year, int *month, int *day)
429 int y, m, d;
430 long delta;
432 if (!jd)
433 return 0 ;
434 if (jd < 1721425 || jd > 2843085)
435 return 0;
437 y = (jd - JD_DIFF) / 366;
438 d = m = 1;
440 while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
441 y++;
443 m = (delta / 31) + 1;
444 while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
445 if (++m > 12)
447 m = 1;
448 y++;
451 d = delta + 1 ;
452 if (d > days_per_month (y, m))
454 d = 1;
455 m++;
457 if (m > 12)
459 m = 1;
460 y++;
463 if (year)
464 *year = y;
465 if (month)
466 *month = m;
467 if (day)
468 *day = d ;
470 return (jd - date2jd (y, 1, 1)) + 1;
474 /* Check that the 15 bytes in ATIME represent a valid ISO time. Note
475 that this function does not expect a string but a plain 15 byte
476 isotime buffer. */
477 gpg_error_t
478 check_isotime (const gnupg_isotime_t atime)
480 int i;
481 const char *s;
483 if (!*atime)
484 return gpg_error (GPG_ERR_NO_VALUE);
486 for (s=atime, i=0; i < 8; i++, s++)
487 if (!digitp (s))
488 return gpg_error (GPG_ERR_INV_TIME);
489 if (*s != 'T')
490 return gpg_error (GPG_ERR_INV_TIME);
491 for (s++, i=9; i < 15; i++, s++)
492 if (!digitp (s))
493 return gpg_error (GPG_ERR_INV_TIME);
494 return 0;
499 /* Add SECONDS to ATIME. SECONDS may not be negative and is limited
500 to about the equivalent of 62 years which should be more then
501 enough for our purposes. */
502 gpg_error_t
503 add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
505 gpg_error_t err;
506 int year, month, day, hour, minute, sec, ndays;
507 unsigned long jd;
509 err = check_isotime (atime);
510 if (err)
511 return err;
513 if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
514 return gpg_error (GPG_ERR_INV_VALUE);
516 year = atoi_4 (atime+0);
517 month = atoi_2 (atime+4);
518 day = atoi_2 (atime+6);
519 hour = atoi_2 (atime+9);
520 minute= atoi_2 (atime+11);
521 sec = atoi_2 (atime+13);
523 if (year <= 1582) /* The julian date functions don't support this. */
524 return gpg_error (GPG_ERR_INV_VALUE);
526 sec += nseconds;
527 minute += sec/60;
528 sec %= 60;
529 hour += minute/60;
530 minute %= 60;
531 ndays = hour/24;
532 hour %= 24;
534 jd = date2jd (year, month, day) + ndays;
535 jd2date (jd, &year, &month, &day);
537 if (year > 9999 || month > 12 || day > 31
538 || year < 0 || month < 1 || day < 1)
539 return gpg_error (GPG_ERR_INV_VALUE);
541 snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
542 year, month, day, hour, minute, sec);
543 return 0;
547 gpg_error_t
548 add_days_to_isotime (gnupg_isotime_t atime, int ndays)
550 gpg_error_t err;
551 int year, month, day, hour, minute, sec;
552 unsigned long jd;
554 err = check_isotime (atime);
555 if (err)
556 return err;
558 if (ndays < 0 || ndays >= 9999*366 )
559 return gpg_error (GPG_ERR_INV_VALUE);
561 year = atoi_4 (atime+0);
562 month = atoi_2 (atime+4);
563 day = atoi_2 (atime+6);
564 hour = atoi_2 (atime+9);
565 minute= atoi_2 (atime+11);
566 sec = atoi_2 (atime+13);
568 if (year <= 1582) /* The julian date functions don't support this. */
569 return gpg_error (GPG_ERR_INV_VALUE);
571 jd = date2jd (year, month, day) + ndays;
572 jd2date (jd, &year, &month, &day);
574 if (year > 9999 || month > 12 || day > 31
575 || year < 0 || month < 1 || day < 1)
576 return gpg_error (GPG_ERR_INV_VALUE);
578 snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
579 year, month, day, hour, minute, sec);
580 return 0;