Some build fixes for platforms like OSX where we use the built-in libintl.
[gnupg.git] / common / gettime.c
1 /* gettime.c - Wrapper for time functions
2  *      Copyright (C) 1998, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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 2 of the License, or
9  * (at your option) any later version.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #ifdef HAVE_LANGINFO_H
26 #include <langinfo.h>
27 #endif
28
29 #include "util.h"
30
31 static unsigned long timewarp;
32 static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
33
34 /* Wrapper for the time(3).  We use this here so we can fake the time
35    for tests */
36 time_t 
37 gnupg_get_time () 
38 {
39   time_t current = time (NULL);
40   if (timemode == NORMAL)
41     return current;
42   else if (timemode == FROZEN)
43     return timewarp;
44   else if (timemode == FUTURE)
45     return current + timewarp;
46   else
47     return current - timewarp;
48 }
49
50
51 /* Return the current time (possibly faked) in ISO format. */
52 void
53 gnupg_get_isotime (gnupg_isotime_t timebuf)
54 {
55   time_t atime = gnupg_get_time ();
56     
57   if (atime < 0)
58     *timebuf = 0;
59   else 
60     {
61       struct tm *tp;
62 #ifdef HAVE_GMTIME_R
63       struct tm tmbuf;
64       
65       tp = gmtime_r (&atime, &tmbuf);
66 #else
67       tp = gmtime (&atime);
68 #endif
69       sprintf (timebuf,"%04d%02d%02dT%02d%02d%02d",
70                1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
71                tp->tm_hour, tp->tm_min, tp->tm_sec);
72     }
73 }
74
75
76 /* set the time to NEWTIME so that gnupg_get_time returns a time
77    starting with this one.  With FREEZE set to 1 the returned time
78    will never change.  Just for completeness, a value of (time_t)-1
79    for NEWTIME gets you back to rality. Note that this is obviously
80    not thread-safe but this is not required. */
81 void
82 gnupg_set_time (time_t newtime, int freeze)
83 {
84   time_t current = time (NULL);
85
86   if ( newtime == (time_t)-1 || current == newtime)
87     {
88       timemode = NORMAL;
89       timewarp = 0;
90     }
91   else if (freeze)
92     {
93       timemode = FROZEN;
94       timewarp = current;
95     }
96   else if (newtime > current)
97     {
98       timemode = FUTURE;
99       timewarp = newtime - current;
100     }
101   else
102     {
103       timemode = PAST;
104       timewarp = current - newtime;
105     }
106 }
107
108 /* Returns true when we are in timewarp mode */
109 int
110 gnupg_faked_time_p (void)
111 {
112   return timemode;
113 }
114
115
116 /* This function is used by gpg because OpenPGP defines the timestamp
117    as an unsigned 32 bit value. */
118 u32 
119 make_timestamp (void)
120 {
121   time_t t = gnupg_get_time ();
122
123   if (t == (time_t)-1)
124     log_fatal ("gnupg_get_time() failed\n");
125   return (u32)t;
126 }
127
128
129
130 /****************
131  * Scan a date string and return a timestamp.
132  * The only supported format is "yyyy-mm-dd"
133  * Returns 0 for an invalid date.
134  */
135 u32
136 scan_isodatestr( const char *string )
137 {
138     int year, month, day;
139     struct tm tmbuf;
140     time_t stamp;
141     int i;
142
143     if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
144         return 0;
145     for( i=0; i < 4; i++ )
146         if( !digitp (string+i) )
147             return 0;
148     if( !digitp (string+5) || !digitp(string+6) )
149         return 0;
150     if( !digitp(string+8) || !digitp(string+9) )
151         return 0;
152     year = atoi(string);
153     month = atoi(string+5);
154     day = atoi(string+8);
155     /* some basic checks */
156     if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
157         return 0;
158     memset( &tmbuf, 0, sizeof tmbuf );
159     tmbuf.tm_mday = day;
160     tmbuf.tm_mon = month-1;
161     tmbuf.tm_year = year - 1900;
162     tmbuf.tm_isdst = -1;
163     stamp = mktime( &tmbuf );
164     if( stamp == (time_t)-1 )
165         return 0;
166     return stamp;
167 }
168
169
170 u32
171 add_days_to_timestamp( u32 stamp, u16 days )
172 {
173     return stamp + days*86400L;
174 }
175
176
177 /****************
178  * Return a string with a time value in the form: x Y, n D, n H
179  */
180
181 const char *
182 strtimevalue( u32 value )
183 {
184     static char buffer[30];
185     unsigned int years, days, hours, minutes;
186
187     value /= 60;
188     minutes = value % 60;
189     value /= 60;
190     hours = value % 24;
191     value /= 24;
192     days = value % 365;
193     value /= 365;
194     years = value;
195
196     sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
197     if( years )
198         return buffer;
199     if( days )
200         return strchr( buffer, 'y' ) + 1;
201     return strchr( buffer, 'd' ) + 1;
202 }
203
204
205 /*
206  * Note: this function returns GMT
207  */
208 const char *
209 strtimestamp( u32 stamp )
210 {
211     static char buffer[11+5];
212     struct tm *tp;
213     time_t atime = stamp;
214     
215     if (atime < 0) {
216         strcpy (buffer, "????" "-??" "-??");
217     }
218     else {
219         tp = gmtime( &atime );
220         sprintf(buffer,"%04d-%02d-%02d",
221                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
222     }
223     return buffer;
224 }
225
226
227 /*
228  * Note: this function returns GMT
229  */
230 const char *
231 isotimestamp (u32 stamp)
232 {
233   static char buffer[25+5];
234   struct tm *tp;
235   time_t atime = stamp;
236   
237   if (atime < 0)
238     {
239       strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
240     }
241   else
242     {
243       tp = gmtime ( &atime );
244       sprintf (buffer,"%04d-%02d-%02d %02d:%02d:%02d",
245                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
246                tp->tm_hour, tp->tm_min, tp->tm_sec);
247     }
248   return buffer;
249 }
250
251
252 /****************
253  * Note: this function returns local time
254  */
255 const char *
256 asctimestamp( u32 stamp )
257 {
258     static char buffer[50];
259 #if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
260       static char fmt[50];
261 #endif
262     struct tm *tp;
263     time_t atime = stamp;
264
265     if (atime < 0) {
266         strcpy (buffer, "????" "-??" "-??");
267         return buffer;
268     }
269
270     tp = localtime( &atime );
271 #ifdef HAVE_STRFTIME
272 #if defined(HAVE_NL_LANGINFO)
273       mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
274       if( strstr( fmt, "%Z" ) == NULL )
275         strcat( fmt, " %Z");
276       /* NOTE: gcc -Wformat-noliteral will complain here.  I have
277          found no way to suppress this warning .*/
278       strftime (buffer, DIM(buffer)-1, fmt, tp);
279 #else
280       /* FIXME: we should check whether the locale appends a " %Z"
281        * These locales from glibc don't put the " %Z":
282        * fi_FI hr_HR ja_JP lt_LT lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN
283        */
284       strftime( buffer, DIM(buffer)-1, "%c %Z", tp );
285 #endif
286     buffer[DIM(buffer)-1] = 0;
287 #else
288     mem2str( buffer, asctime(tp), DIM(buffer) );
289 #endif
290     return buffer;
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305