Added preliminary Symbian support.
[silc.git] / lib / silcutil / silctime.c
1 /*
2
3   silctime.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2003 - 2006 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21
22 /* Fills the SilcTime structure with correct values */
23
24 static SilcBool silc_time_fill(SilcTime time,
25                                unsigned int year,
26                                unsigned int month,
27                                unsigned int day,
28                                unsigned int hour,
29                                unsigned int minute,
30                                unsigned int second,
31                                unsigned int msec)
32 {
33   if (year > (1 << 15))
34     return FALSE;
35   if (month < 1 || month > 12)
36     return FALSE;
37   if (day < 1 || day > 31)
38     return FALSE;
39   if (hour > 23)
40     return FALSE;
41   if (minute > 60)
42     return FALSE;
43   if (second > 61)
44     return FALSE;
45   if (msec > 1000)
46     return FALSE;
47
48   time->year = year;
49   time->month = month;
50   time->day = day;
51   time->hour = hour;
52   time->minute = minute;
53   time->second = second;
54   time->msecond = msec;
55
56   return TRUE;
57 }
58
59 /* Return time since Epoch */
60
61 SilcInt64 silc_time(void)
62 {
63   return (SilcInt64)time(NULL);
64 }
65
66 /* Return time since Epoch in milliseconds */
67
68 SilcInt64 silc_time_msec(void)
69 {
70   struct timeval curtime;
71   silc_gettimeofday(&curtime);
72   return (curtime.tv_sec * 1000) + (curtime.tv_usec / 1000);
73 }
74
75 /* Return time since Epoch in microseconds */
76
77 SilcInt64 silc_time_usec(void)
78 {
79   struct timeval curtime;
80   silc_gettimeofday(&curtime);
81   return (curtime.tv_sec * 1000000) + curtime.tv_usec;
82 }
83
84 /* Returns time as string */
85
86 const char *silc_time_string(SilcInt64 time_val)
87 {
88   time_t curtime;
89   char *return_time;
90
91   if (!time_val)
92     curtime = silc_time();
93   else
94     curtime = (time_t)time_val;
95   return_time = ctime(&curtime);
96   if (!return_time)
97     return NULL;
98   return_time[strlen(return_time) - 1] = '\0';
99
100   return (const char *)return_time;
101 }
102
103 /* Returns time as SilcTime structure */
104
105 SilcBool silc_time_value(SilcInt64 time_val, SilcTime ret_time)
106 {
107   struct tm *time;
108   unsigned int msec = 0;
109
110   if (!ret_time)
111     return TRUE;
112
113   if (!time_val)
114     time_val = silc_time_msec();
115
116   msec = time_val % 1000;
117   time_val /= 1000;
118
119   time = localtime((time_t *)&time_val);
120   if (!time)
121     return FALSE;
122
123   memset(ret_time, 0, sizeof(*ret_time));
124   if (!silc_time_fill(ret_time, time->tm_year + 1900, time->tm_mon + 1,
125                       time->tm_mday, time->tm_hour, time->tm_min,
126                       time->tm_sec, msec))
127     return FALSE;
128
129   ret_time->dst        = time->tm_isdst ? 1 : 0;
130 #ifdef SILC_WIN32
131   ret_time->utc_east   = _timezone < 0 ? 1 : 0;
132   ret_time->utc_hour   = (ret_time->utc_east ? (-(_timezone)) / 3600 :
133                           _timezone / 3600);
134   ret_time->utc_minute = (ret_time->utc_east ? (-(_timezone)) % 3600 :
135                           _timezone % 3600);
136 #else
137 #if defined(HAVE_TZSET)
138   ret_time->utc_east   = timezone < 0 ? 1 : 0;
139   ret_time->utc_hour   = (ret_time->utc_east ? (-(timezone)) / 3600 :
140                           timezone / 3600);
141   ret_time->utc_minute = (ret_time->utc_east ? (-(timezone)) % 3600 :
142                           timezone % 3600);
143 #endif /* HAVE_TZSET */
144 #endif /* SILC_WIN32 */
145
146   return TRUE;
147 }
148
149 /* Returns time from universal time string into SilcTime */
150
151 SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time)
152 {
153   int ret;
154   unsigned int year, month, day, hour = 0, minute = 0, second = 0;
155   unsigned char z = 0;
156
157   if (!ret_time)
158     return TRUE;
159   memset(ret_time, 0, sizeof(*ret_time));
160
161   /* Parse the time string */
162   ret = sscanf(universal_time, "%02u%02u%02u%02u%02u%02u%c", &year, &month,
163                &day, &hour, &minute, &second, &z);
164   if (ret < 3) {
165     SILC_LOG_DEBUG(("Invalid UTC time string"));
166     return FALSE;
167   }
168
169   /* Fill the SilcTime structure */
170   ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
171   if (!ret) {
172     SILC_LOG_DEBUG(("Incorrect values in UTC time string"));
173     return FALSE;
174   }
175
176   /* Check timezone */
177   if (z == '-' || z == '+') {
178     ret = sscanf(universal_time + (ret * 2) + 1, "%02u%02u", &hour, &minute);
179     if (ret != 2) {
180       SILC_LOG_DEBUG(("Malformed UTC time string"));
181       return FALSE;
182     }
183
184     if (hour < 0 || hour > 23)
185       return FALSE;
186     if (minute < 0 || minute > 60)
187       return FALSE;
188
189     ret_time->utc_hour   = hour;
190     ret_time->utc_minute = minute;
191     ret_time->utc_east   = (z == '-') ? 0 : 1;
192   } else if (z != 'Z') {
193     SILC_LOG_DEBUG(("Invalid timezone"));
194     return FALSE;
195   }
196
197   /* UTC year must be fixed since it's represented only as YY not YYYY. */
198   ret_time->year += 1900;
199   if (ret_time->year < 1950)
200     ret_time->year += 100;
201
202   return TRUE;
203 }
204
205 /* Encode universal time string. */
206
207 SilcBool silc_time_universal_string(SilcTime time_val, char *ret_string,
208                                     SilcUInt32 ret_string_size)
209 {
210   int ret, len = 0;
211   memset(ret_string, 0, ret_string_size);
212   ret = silc_silc_snprintf(ret_string, ret_string_size - 1,
213                  "%02u%02u%02u%02u%02u%02u",
214                  time_val->year % 100, time_val->month, time_val->day,
215                  time_val->hour, time_val->minute, time_val->second);
216   if (ret < 0)
217     return FALSE;
218   len += ret;
219
220   if (!time_val->utc_hour && !time_val->utc_minute) {
221     ret = silc_silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
222     if (ret < 0)
223       return FALSE;
224     len += ret;
225   } else {
226     ret = silc_silc_snprintf(ret_string + len, ret_string_size - 1 - len,
227                    "%c%02u%02u", time_val->utc_east ? '+' : '-',
228                    time_val->utc_hour, time_val->utc_minute);
229     if (ret < 0)
230       return FALSE;
231     len += ret;
232   }
233
234   return TRUE;
235 }
236
237 /* Returns time from generalized time string into SilcTime */
238
239 SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time)
240 {
241   int ret, i;
242   unsigned int year, month, day, hour = 0, minute = 0, second = 0;
243   unsigned int msecond = 0;
244   unsigned char z = 0;
245
246   if (!ret_time)
247     return TRUE;
248   memset(ret_time, 0, sizeof(*ret_time));
249
250   /* Parse the time string */
251   ret = sscanf(generalized_time, "%04u%02u%02u%02u%02u%02u", &year, &month,
252                &day, &hour, &minute, &second);
253   if (ret < 3) {
254     SILC_LOG_DEBUG(("Invalid generalized time string"));
255     return FALSE;
256   }
257
258   /* Fill the SilcTime structure */
259   ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
260   if (!ret) {
261     SILC_LOG_DEBUG(("Incorrect values in generalized time string"));
262     return FALSE;
263   }
264
265   /* Check fractions of second and/or timezone */
266   i = ret * 4;
267   ret = sscanf(generalized_time + i, "%c", &z);
268   if (ret != 1) {
269     SILC_LOG_DEBUG(("Malformed generalized time string"));
270     return FALSE;
271   }
272
273   if (z == '.') {
274     /* Take fractions of second */
275     int l;
276     i++;
277     ret = sscanf(generalized_time + i, "%u%n", &msecond, &l);
278     if (ret != 1) {
279       SILC_LOG_DEBUG(("Malformed generalized time string"));
280       return FALSE;
281     }
282     while (l > 4) {
283       msecond /= 10;
284       l--;
285     }
286     ret_time->msecond = msecond;
287     i += l;
288
289     /* Read optional timezone */
290     if (strlen(generalized_time) < i)
291       sscanf(generalized_time + i, "%c", &z);
292   }
293
294   /* Check timezone if present */
295   if (z == '-' || z == '+') {
296     ret = sscanf(generalized_time + i + 1, "%02u%02u", &hour, &minute);
297     if (ret != 2) {
298       SILC_LOG_DEBUG(("Malformed UTC time string"));
299       return FALSE;
300     }
301
302     if (hour < 0 || hour > 23)
303       return FALSE;
304     if (minute < 0 || minute > 60)
305       return FALSE;
306
307     ret_time->utc_hour   = hour;
308     ret_time->utc_minute = minute;
309     ret_time->utc_east   = (z == '-') ? 0 : 1;
310   }
311
312   return TRUE;
313 }
314
315 /* Encode generalized time string */
316
317 SilcBool silc_time_generalized_string(SilcTime time_val, char *ret_string,
318                                       SilcUInt32 ret_string_size)
319 {
320   int len = 0, ret;
321   memset(ret_string, 0, ret_string_size);
322   ret = silc_silc_snprintf(ret_string, ret_string_size - 1,
323                  "%04u%02u%02u%02u%02u%02u",
324                  time_val->year, time_val->month, time_val->day, time_val->hour,
325                  time_val->minute, time_val->second);
326   if (ret < 0)
327     return FALSE;
328   len += ret;
329
330   if (time_val->msecond) {
331     ret = silc_silc_snprintf(ret_string + len, ret_string_size - 1 - len,
332                    ".%lu", (unsigned long)time_val->msecond);
333     if (ret < 0)
334       return FALSE;
335     len += ret;
336   }
337
338   if (!time_val->utc_hour && !time_val->utc_minute) {
339     ret = silc_silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
340     if (ret < 0)
341       return FALSE;
342     len += ret;
343   } else {
344     ret = silc_silc_snprintf(ret_string + len, ret_string_size - 1 - len,
345                    "%c%02u%02u", time_val->utc_east ? '+' : '-',
346                    time_val->utc_hour, time_val->utc_minute);
347     if (ret < 0)
348       return FALSE;
349     len += ret;
350   }
351
352   return TRUE;
353 }
354
355 /* Return TRUE if `smaller' is smaller than `bigger'. */
356
357 SilcBool silc_compare_timeval(struct timeval *smaller,
358                               struct timeval *bigger)
359 {
360   if ((smaller->tv_sec < bigger->tv_sec) ||
361       ((smaller->tv_sec == bigger->tv_sec) &&
362        (smaller->tv_usec < bigger->tv_usec)))
363     return TRUE;
364
365   return FALSE;
366 }