1 #include "config.h"
2 
3 #if IS_LINUX
4 /* Linux cheats AC_CHECK_FUNCS(strptime_l), sigh. */
5 #define THREAD_SAFE 0
6 #define _XOPEN_SOURCE
7 #define _BSD_SOURCE
8 #elif HAVE_STRPTIME_L
9 #define THREAD_SAFE 1
10 #define _GNU_SOURCE
11 #else
12 #define THREAD_SAFE 0
13 #endif
14 
15 #include <string.h>
16 #include <time.h>
17 #include <locale.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 
21 #if defined(_WIN32)
22 #include "win_patch.h"
23 #endif // _WIN32
24 
25 #if THREAD_SAFE
26 #if HAVE_XLOCALE_H
27 #include <xlocale.h>
28 #endif
29 
30 locale_t c_locale = NULL;
31 
init_locale()32 void init_locale() {
33     if (c_locale == NULL) c_locale = newlocale(LC_TIME_MASK, "C", NULL);
34 }
35 #else
init_locale()36 void init_locale() {
37     static int initialized = 0;
38     if (initialized == 0) {
39         setlocale(LC_TIME, "C");
40         initialized = 1;
41     }
42 }
43 #endif
44 
45 /*
46  * Set the value of the TZ environment variable to UTC
47  * and return the old value.
48  */
set_tz_utc()49 char *set_tz_utc() {
50     char *tz;
51     tz = getenv("TZ");
52 #if defined(_WIN32)
53     _patch_setenv("TZ", "UTC", 1);
54 #else
55     setenv("TZ", "", 1);
56 #endif
57     tzset();
58     return tz;
59 }
60 
61 /*
62  * Set the value of the TZ environment variable to tz or
63  * unset the variable if tz is null;
64  */
set_tz(char * local_tz)65 void set_tz(char *local_tz) {
66     if (local_tz) {
67 #if defined(_WIN32)
68       _patch_setenv("TZ", local_tz, 1);
69 #else
70       setenv("TZ", local_tz, 1);
71 #endif
72     } else {
73 #if defined(_WIN32)
74       _patch_unsetenv("TZ");
75 #else
76       unsetenv("TZ");
77 #endif
78     }
79     tzset();
80 }
81 
c_parse_unix_time(char * fmt,char * src)82 time_t c_parse_unix_time(char *fmt, char *src) {
83     struct tm dst;
84     init_locale();
85     memset(&dst, 0, sizeof(struct tm));
86 #if THREAD_SAFE
87     strptime_l(src, fmt, &dst, c_locale);
88 #else
89     strptime(src, fmt, &dst);
90 #endif
91     return mktime(&dst);
92 }
93 
94 #if !defined(HAVE_TIMEGM)
95 /* This part is for Solaris that doesn't have timegm.
96  * The copyright notice of timegm and is_leap is as below:
97  *
98  * Copyright (c) 1997 Kungliga Tekniska H.gskolan
99  * (Royal Institute of Technology, Stockholm, Sweden).
100  * All rights reserved.
101  */
102 
103 static time_t
timegm(struct tm * tm)104 timegm (struct tm *tm)
105 {
106   static const unsigned ndays[2][12] ={
107     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
108     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
109   time_t res = 0;
110   unsigned i;
111 
112   for (i = 70; i < tm->tm_year; ++i)
113     res += isleap(i + 1900) ? 366 : 365;
114 
115   for (i = 0; i < tm->tm_mon; ++i)
116     res += ndays[isleap(tm->tm_year + 1900)][i];
117   res += tm->tm_mday - 1;
118   res *= 24;
119   res += tm->tm_hour;
120   res *= 60;
121   res += tm->tm_min;
122   res *= 60;
123   res += tm->tm_sec;
124   return res;
125 }
126 #endif /* HAVE_TIMEGM */
127 
c_parse_unix_time_gmt(char * fmt,char * src)128 time_t c_parse_unix_time_gmt(char *fmt, char *src) {
129     struct tm dst;
130     char *local_tz;
131     init_locale();
132     memset(&dst, 0, sizeof(struct tm));
133     local_tz = set_tz_utc();
134 #if THREAD_SAFE
135     strptime_l(src, fmt, &dst, c_locale);
136 #else
137     strptime(src, fmt, &dst);
138 #endif
139     set_tz(local_tz);
140     return timegm(&dst);
141 }
142 
c_format_unix_time(char * fmt,time_t src,char * dst,int siz)143 size_t c_format_unix_time(char *fmt, time_t src, char* dst, int siz) {
144     struct tm tim;
145     init_locale();
146     localtime_r(&src, &tim);
147 #if THREAD_SAFE
148 #if defined(_WIN32)
149     return _patch_strftime_l(dst, siz, fmt, &tim, c_locale);
150 #else
151     return strftime_l(dst, siz, fmt, &tim, c_locale);
152 #endif // _WIN32
153 #else
154 #if defined(_WIN32)
155     return _patch_strftime(dst, siz, fmt, &tim);
156 #else
157     return strftime(dst, siz, fmt, &tim);
158 #endif // _WIN32
159 #endif
160 }
161 
c_format_unix_time_gmt(char * fmt,time_t src,char * dst,int siz)162 size_t c_format_unix_time_gmt(char *fmt, time_t src, char* dst, int siz) {
163     struct tm tim;
164     char *local_tz;
165     size_t dst_size;
166 
167     init_locale();
168     gmtime_r(&src, &tim);
169 
170     local_tz = set_tz_utc();
171 #if THREAD_SAFE
172 #if defined(_WIN32)
173     dst_size = _patch_strftime_l(dst, siz, fmt, &tim, c_locale);
174 #else
175     dst_size = strftime_l(dst, siz, fmt, &tim, c_locale);
176 #endif // _WIN32
177 #else
178 #if defined(_WIN32)
179     dst_size = _patch_strftime(dst, siz, fmt, &tim);
180 #else
181     dst_size = strftime(dst, siz, fmt, &tim);
182 #endif // _WIN32
183 #endif
184     set_tz(local_tz);
185     return dst_size;
186 }
187