New version of mu_tm2time function.
The previous version of mu_tm2time incorrectly handled dates within the DST period.
Showing
1 changed file
with
235 additions
and
0 deletions
mailbox/date.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #include <mailutils/mutil.h> | ||
19 | |||
20 | #define SECS_PER_DAY 86400 | ||
21 | #define ADJUSTMENT -719162L | ||
22 | |||
23 | static time_t | ||
24 | jan1st (int year) | ||
25 | { | ||
26 | year--; /* Do not consider the current year */ | ||
27 | return year*365L | ||
28 | + year/4L /* Years divisible by 4 are leap years */ | ||
29 | + year/400L /* Years divisible by 400 are always leap years */ | ||
30 | - year/100L; /* Years divisible by 100 but not 400 aren't */ | ||
31 | } | ||
32 | |||
33 | static int month_start[]= | ||
34 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; | ||
35 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec | ||
36 | 31 28 31 30 31 30 31 31 30 31 30 31 | ||
37 | */ | ||
38 | |||
39 | #define leap_year(y) ((y) % 4 == 0 && (y) % 100 != 0 || (y) % 400 == 0) | ||
40 | |||
41 | static int | ||
42 | dayofyear (time_t *pday, int year, int month, int day) | ||
43 | { | ||
44 | int leap, month_days; | ||
45 | |||
46 | if (year < 0 || month < 0 || month > 11) | ||
47 | return -1; | ||
48 | |||
49 | leap = leap_year (year); | ||
50 | |||
51 | month_days = month_start[month + 1] - month_start[month] | ||
52 | + ((month == 2) ? leap : 0); | ||
53 | |||
54 | if (day < 0 || day > month_days) | ||
55 | return -1; /* Illegal Date */ | ||
56 | |||
57 | if (month <= 2) | ||
58 | leap = 0; | ||
59 | |||
60 | *pday = month_start[month] + day + leap; | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | |||
65 | /* Convert struct tm into time_t, taking into account timezone offset. */ | ||
66 | /* FIXME: It does not take DST into account */ | ||
67 | time_t | ||
68 | mu_tm2time (struct tm *tm, mu_timezone *tz) | ||
69 | { | ||
70 | time_t t; | ||
71 | |||
72 | if (dayofyear (&t, tm->tm_year, tm->tm_mon, tm->tm_mday - 1)) | ||
73 | return -1; | ||
74 | t = (t + ADJUSTMENT + jan1st (1900 + tm->tm_year)) * SECS_PER_DAY | ||
75 | + (tm->tm_hour * 60 + tm->tm_min) * 60 + tm->tm_sec | ||
76 | - tz->utc_offset; | ||
77 | return t; | ||
78 | } | ||
79 | |||
80 | /* Convert time 0 at UTC to our localtime, that tells us the offset | ||
81 | of our current timezone from UTC. */ | ||
82 | time_t | ||
83 | mu_utc_offset (void) | ||
84 | { | ||
85 | time_t t = 0; | ||
86 | struct tm *tm = gmtime (&t); | ||
87 | |||
88 | return - mktime (tm); | ||
89 | } | ||
90 | |||
91 | static const char *months[] = | ||
92 | { | ||
93 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", | ||
94 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL | ||
95 | }; | ||
96 | |||
97 | static const char *wdays[] = | ||
98 | { | ||
99 | "Sun", "Mon", "Teu", "Wed", "Thr", "Fri", "Sat", NULL | ||
100 | }; | ||
101 | |||
102 | int | ||
103 | mu_parse_imap_date_time (const char **p, struct tm *tm, mu_timezone *tz) | ||
104 | { | ||
105 | int year, mon, day, hour, min, sec; | ||
106 | char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */ | ||
107 | char month[5] = ""; | ||
108 | int hh = 0; | ||
109 | int mm = 0; | ||
110 | int sign = 1; | ||
111 | int scanned = 0, scanned3; | ||
112 | int i; | ||
113 | int tzoffset; | ||
114 | |||
115 | day = mon = year = hour = min = sec = 0; | ||
116 | |||
117 | memset (tm, 0, sizeof (*tm)); | ||
118 | |||
119 | switch (sscanf (*p, | ||
120 | "%2d-%3s-%4d%n %2d:%2d:%2d %5s%n", | ||
121 | &day, month, &year, &scanned3, &hour, &min, &sec, zone, | ||
122 | &scanned)) | ||
123 | { | ||
124 | case 3: | ||
125 | scanned = scanned3; | ||
126 | break; | ||
127 | case 7: | ||
128 | break; | ||
129 | default: | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | tm->tm_sec = sec; | ||
134 | tm->tm_min = min; | ||
135 | tm->tm_hour = hour; | ||
136 | tm->tm_mday = day; | ||
137 | |||
138 | for (i = 0; i < 12; i++) | ||
139 | { | ||
140 | if (strncasecmp (month, months[i], 3) == 0) | ||
141 | { | ||
142 | mon = i; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | tm->tm_mon = mon; | ||
147 | tm->tm_year = (year > 1900) ? year - 1900 : year; | ||
148 | tm->tm_yday = 0; /* unknown. */ | ||
149 | tm->tm_wday = 0; /* unknown. */ | ||
150 | #if HAVE_STRUCT_TM_TM_ISDST | ||
151 | tm->tm_isdst = -1; /* unknown. */ | ||
152 | #endif | ||
153 | |||
154 | hh = (zone[1] - '0') * 10 + (zone[2] - '0'); | ||
155 | mm = (zone[3] - '0') * 10 + (zone[4] - '0'); | ||
156 | sign = (zone[0] == '-') ? -1 : +1; | ||
157 | tzoffset = sign * (hh * 60 * 60 + mm * 60); | ||
158 | |||
159 | #if HAVE_STRUCT_TM_TM_GMTOFF | ||
160 | tm->tm_gmtoff = tzoffset; | ||
161 | #endif | ||
162 | |||
163 | if (tz) | ||
164 | { | ||
165 | tz->utc_offset = tzoffset; | ||
166 | tz->tz_name = NULL; | ||
167 | } | ||
168 | |||
169 | *p += scanned; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* "ctime" format is: Thu Jul 01 15:58:27 1999, with no trailing \n. */ | ||
175 | int | ||
176 | mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone * tz) | ||
177 | { | ||
178 | int wday = 0; | ||
179 | int year = 0; | ||
180 | int mon = 0; | ||
181 | int day = 0; | ||
182 | int hour = 0; | ||
183 | int min = 0; | ||
184 | int sec = 0; | ||
185 | int n = 0; | ||
186 | int i; | ||
187 | char weekday[5] = ""; | ||
188 | char month[5] = ""; | ||
189 | |||
190 | if (sscanf (*p, "%3s %3s %2d %2d:%2d:%2d %d%n\n", | ||
191 | weekday, month, &day, &hour, &min, &sec, &year, &n) != 7) | ||
192 | return -1; | ||
193 | |||
194 | *p += n; | ||
195 | |||
196 | for (i = 0; i < 7; i++) | ||
197 | { | ||
198 | if (strncasecmp (weekday, wdays[i], 3) == 0) | ||
199 | { | ||
200 | wday = i; | ||
201 | break; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | for (i = 0; i < 12; i++) | ||
206 | { | ||
207 | if (strncasecmp (month, months[i], 3) == 0) | ||
208 | { | ||
209 | mon = i; | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | if (tm) | ||
215 | { | ||
216 | memset (tm, 0, sizeof (struct tm)); | ||
217 | |||
218 | tm->tm_sec = sec; | ||
219 | tm->tm_min = min; | ||
220 | tm->tm_hour = hour; | ||
221 | tm->tm_mday = day; | ||
222 | tm->tm_wday = wday; | ||
223 | tm->tm_mon = mon; | ||
224 | tm->tm_year = (year > 1900) ? year - 1900 : year; | ||
225 | #ifdef HAVE_STRUCT_TM_TM_ISDST | ||
226 | tm->tm_isdst = -1; /* unknown. */ | ||
227 | #endif | ||
228 | } | ||
229 | |||
230 | /* ctime has no timezone information, set tz to UTC if they ask. */ | ||
231 | if (tz) | ||
232 | memset (tz, 0, sizeof (struct mu_timezone)); | ||
233 | |||
234 | return 0; | ||
235 | } |
-
Please register or sign in to post a comment