]> Joshua Wise's Git repositories - tdl.git/blame - dates.c
Sort list by a priority function in 'tdll'.
[tdl.git] / dates.c
CommitLineData
7024e37b
JW
1/*
2 $Header: /cvs/src/tdl/dates.c,v 1.5.2.1 2004/01/07 00:09:05 richard Exp $
3
4 tdl - A console program for managing to-do lists
5 Copyright (C) 2001-2004 Richard P. Curnow
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 */
21
22/* This file deals with parsing dates and relative time expressions. */
23
24#include "tdl.h"
25#include <string.h>
26#include <ctype.h>
27
28static time_t tm_to_time_t (struct tm *stm)/*{{{*/
29{
30 /* Convert from (struct tm) to time_t. This has to be an inverse of
31 * localtime(). It's not obvious that mktime() does this right, especially
32 * with daylight saving time, on all systems (as I found out writing the RTC
33 * support for chrony!). This function will apply any compensation that is
34 * needed. */
35
36 struct tm temp1, temp2;
37 long diff;
38 time_t t1, t2;
39 temp1 = *stm;
40 temp1.tm_isdst = 0;
41 t1 = mktime(&temp1);
42 temp2 = *localtime(&t1);
43 temp2.tm_isdst = 0;
44 t2 = mktime(&temp2);
45 diff = t2 - t1;
46 return t1 - diff;
47}
48/*}}}*/
49static int parse_time(char *d, int *hour, int *min, int *sec)/*{{{*/
50{
51 int n;
52 *hour = *min = *sec = 0;
53 switch (strlen(d)) {
54 case 2:
55 n = sscanf(d, "%2d", hour);
56 if (n != 1) {
57 fprintf(stderr, "Can't parse hour from %s\n", d);
58 return -1;
59 }
60 break;
61 case 4:
62 n = sscanf(d, "%2d%2d", hour, min);
63 if (n != 2) {
64 fprintf(stderr, "Can't parse hour and minute from %s\n", d);
65 return -1;
66 }
67 break;
68 case 6:
69 n = sscanf(d, "%2d%2d%2d", hour, min, sec);
70 if (n != 3) {
71 fprintf(stderr, "Can't parse hour, minute and second from %s\n", d);
72 return -1;
73 }
74 break;
75 default:
76 fprintf(stderr, "Cannot parse time\n");
77 return -1;
78 break;
79 }
80
81 return 0;
82}
83/*}}}*/
84time_t parse_date(char *d, time_t ref, int default_positive, int *error)/*{{{*/
85{
86 int len;
87 char *hyphenpos;
88 char *d0;
89 time_t result;
90
91 *error = 0; /* default : success */
92
93 d0 = (*d == '-') ? d+1 : d;
94 hyphenpos = strchr(d0, '-');
95
96 if (hyphenpos) *hyphenpos = 0;
97
98 len = strlen(d);
99
100 if (!strcmp(d, ".")) {
101 result = ref;
102
103 } else if (isalpha(d[0]) ||
104 (((d[0] == '+')|| (d[0] == '-')) && isalpha(d[1]))) {
105
106 /* Look for dayname, +dayname, or -dayname */
107 int dow = -1;
108 int posneg, diff;
109 char *dd = d;
110 struct tm stm;
111
112 if (*dd == '+') posneg = 1, dd++;
113 else if (*dd == '-') posneg = 0, dd++;
114 else posneg = default_positive;
115
116 /* This really needs to be internationalized properly. Somebody who
117 * understands how to make locales work properly needs to fix that. */
118
119 if (!strncasecmp(dd, "sun", 3)) dow = 0;
120 else if (!strncasecmp(dd, "mon", 3)) dow = 1;
121 else if (!strncasecmp(dd, "tue", 3)) dow = 2;
122 else if (!strncasecmp(dd, "wed", 3)) dow = 3;
123 else if (!strncasecmp(dd, "thu", 3)) dow = 4;
124 else if (!strncasecmp(dd, "fri", 3)) dow = 5;
125 else if (!strncasecmp(dd, "sat", 3)) dow = 6;
126
127 if (dow < 0) {
128 fprintf(stderr, "Cannot understand day of week\n");
129 }
130
131 stm = *localtime(&ref);
132 diff = dow - stm.tm_wday;
133
134 if (diff == 0) {
135 /* If the day specified is the same day of the week as today, step a
136 * whole week in the required direction. */
137 if (posneg) result = ref + (7*86400);
138 else result = ref - (7*86400);
139
140 } else if (diff > 0) {
141 if (posneg) result = ref + (diff * 86400);
142 else result = ref - ((7-diff) * 86400);
143 } else { /* diff < 0 */
144 if (posneg) result = ref + ((7+diff) * 86400);
145 else result = ref + (diff * 86400);
146 }
147
148 stm = *localtime(&result);
149
150 stm.tm_hour = 12;
151 stm.tm_min = 0;
152 stm.tm_sec = 0;
153 result = tm_to_time_t(&stm);
154
155 } else if ((len > 1) && isalpha(d[len-1])) {
156 /* Relative time */
157 long interval;
158 int nc;
159 int posneg;
160
161 if (*d == '+') posneg = 1, d++;
162 else if (*d == '-') posneg = 0, d++;
163 else posneg = default_positive;
164
165 if (sscanf(d, "%ld%n", &interval, &nc) != 1) {
166 fprintf(stderr, "Cannot recognize interval '%s'\n", d);
167 *error = -1;
168 return (time_t) 0; /* arbitrary */
169 }
170
171 d += nc;
172 switch (d[0]) {
173 case 'h': interval *= 3600; break;
174 case 'd': interval *= 86400; break;
175 case 'w': interval *= 7 * 86400; break;
176 case 'm': interval *= 30 * 86400; break;
177 case 'y': interval *= 365 * 86400; break;
178 case 's': break; /* use seconds */
179 default:
180 fprintf(stderr, "Can't understand interval multiplier '%s'\n", d);
181 *error = -1;
182 return (time_t) 0; /* arbitrary */
183 }
184 if (!posneg) interval = -interval;
185
186 result = ref + interval;
187
188 } else {
189 int year, month, day, n;
190 struct tm stm;
191
192 stm = *localtime(&ref);
193
194 /* Try to parse absolute date.
195 * Formats allowed : dd, mmdd, yymmdd, yyyymmdd.
196 * Time is assumed to be noon on the specified day */
197 switch (len) {
198 case 0:
199 day = stm.tm_mday;
200 month = stm.tm_mon + 1;
201 year = stm.tm_year;
202 break;
203 case 2:
204 n = sscanf(d, "%2d", &day);
205 if (n != 1) {
206 fprintf(stderr, "Can't parse day from %s\n", d);
207 *error = -1;
208 return (time_t) 0; /* arbitrary */
209 }
210 month = stm.tm_mon + 1;
211 year = stm.tm_year;
212 break;
213 case 4:
214 n = sscanf(d, "%2d%2d", &month, &day);
215 if (n != 2) {
216 fprintf(stderr, "Can't parse month and day from %s\n", d);
217 *error = -1;
218 return (time_t) 0; /* arbitrary */
219 }
220 year = stm.tm_year;
221 break;
222 case 6:
223 n = sscanf(d, "%2d%2d%2d", &year, &month, &day);
224 if (n != 3) {
225 fprintf(stderr, "Can't parse year, month and day from %s\n", d);
226 *error = -1;
227 return (time_t) 0; /* arbitrary */
228 }
229 if (year < 70) year += 100;
230 break;
231 case 8:
232 n = sscanf(d, "%4d%2d%2d", &year, &month, &day);
233 if (n != 3) {
234 fprintf(stderr, "Can't parse year, month and day from %s\n", d);
235 *error = -1;
236 return (time_t) 0; /* arbitrary */
237 }
238 year -= 1900;
239 break;
240 default:
241 fprintf(stderr, "Can't parse date from %s\n", d);
242 *error = -2;
243 return (time_t) 0; /* arbitrary */
244 break;
245 }
246 stm.tm_year = year;
247 stm.tm_mon = month - 1;
248 stm.tm_mday = day;
249 stm.tm_hour = 12;
250 stm.tm_min = 0;
251 stm.tm_sec = 0;
252 result = tm_to_time_t(&stm);
253 }
254
255 if (hyphenpos) {
256 int hour, min, sec;
257 struct tm stm;
258
259 parse_time(hyphenpos+1, &hour, &min, &sec);
260 stm = *localtime(&result);
261 stm.tm_hour = hour;
262 stm.tm_min = min;
263 stm.tm_sec = sec;
264 result = tm_to_time_t(&stm);
265 }
266
267 return result;
268
269}/*}}}*/
270
271/*{{{ Test code*/
272#ifdef TEST
273
274#include <locale.h>
275
276int main (int argc, char **argv)
277{
278 time_t ref, newtime;
279 char buffer[64];
280
281 setlocale(LC_ALL, "");
282
283 ref = time(NULL);
284
285 if (argc < 2) {
286 fprintf(stderr, "Require an argument\n");
287 return 1;
288 }
289
290 newtime = parse_date(argv[1], ref, (argc > 2));
291
292 strftime(buffer, sizeof(buffer), "%a %A %d %b %B %Y %H:%M:%S", localtime(&newtime));
293 printf("%s\n", buffer);
294
295 return 0;
296
297}
298#endif
299
300/*}}}*/
301
This page took 0.037288 seconds and 4 git commands to generate.