2 $Header: /cvs/src/tdl/dates.c,v 1.5.2.1 2004/01/07 00:09:05 richard Exp $
4 tdl - A console program for managing to-do lists
5 Copyright (C) 2001-2004 Richard P. Curnow
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.
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.
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
22 /* This file deals with parsing dates and relative time expressions. */
28 static time_t tm_to_time_t (struct tm *stm)/*{{{*/
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
36 struct tm temp1, temp2;
42 temp2 = *localtime(&t1);
49 static int parse_time(char *d, int *hour, int *min, int *sec)/*{{{*/
52 *hour = *min = *sec = 0;
55 n = sscanf(d, "%2d", hour);
57 fprintf(stderr, "Can't parse hour from %s\n", d);
62 n = sscanf(d, "%2d%2d", hour, min);
64 fprintf(stderr, "Can't parse hour and minute from %s\n", d);
69 n = sscanf(d, "%2d%2d%2d", hour, min, sec);
71 fprintf(stderr, "Can't parse hour, minute and second from %s\n", d);
76 fprintf(stderr, "Cannot parse time\n");
84 time_t parse_date(char *d, time_t ref, int default_positive, int *error)/*{{{*/
91 *error = 0; /* default : success */
93 d0 = (*d == '-') ? d+1 : d;
94 hyphenpos = strchr(d0, '-');
96 if (hyphenpos) *hyphenpos = 0;
100 if (!strcmp(d, ".")) {
103 } else if (isalpha(d[0]) ||
104 (((d[0] == '+')|| (d[0] == '-')) && isalpha(d[1]))) {
106 /* Look for dayname, +dayname, or -dayname */
112 if (*dd == '+') posneg = 1, dd++;
113 else if (*dd == '-') posneg = 0, dd++;
114 else posneg = default_positive;
116 /* This really needs to be internationalized properly. Somebody who
117 * understands how to make locales work properly needs to fix that. */
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;
128 fprintf(stderr, "Cannot understand day of week\n");
131 stm = *localtime(&ref);
132 diff = dow - stm.tm_wday;
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);
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);
148 stm = *localtime(&result);
153 result = tm_to_time_t(&stm);
155 } else if ((len > 1) && isalpha(d[len-1])) {
161 if (*d == '+') posneg = 1, d++;
162 else if (*d == '-') posneg = 0, d++;
163 else posneg = default_positive;
165 if (sscanf(d, "%ld%n", &interval, &nc) != 1) {
166 fprintf(stderr, "Cannot recognize interval '%s'\n", d);
168 return (time_t) 0; /* arbitrary */
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 */
180 fprintf(stderr, "Can't understand interval multiplier '%s'\n", d);
182 return (time_t) 0; /* arbitrary */
184 if (!posneg) interval = -interval;
186 result = ref + interval;
189 int year, month, day, n;
192 stm = *localtime(&ref);
194 /* Try to parse absolute date.
195 * Formats allowed : dd, mmdd, yymmdd, yyyymmdd.
196 * Time is assumed to be noon on the specified day */
200 month = stm.tm_mon + 1;
204 n = sscanf(d, "%2d", &day);
206 fprintf(stderr, "Can't parse day from %s\n", d);
208 return (time_t) 0; /* arbitrary */
210 month = stm.tm_mon + 1;
214 n = sscanf(d, "%2d%2d", &month, &day);
216 fprintf(stderr, "Can't parse month and day from %s\n", d);
218 return (time_t) 0; /* arbitrary */
223 n = sscanf(d, "%2d%2d%2d", &year, &month, &day);
225 fprintf(stderr, "Can't parse year, month and day from %s\n", d);
227 return (time_t) 0; /* arbitrary */
229 if (year < 70) year += 100;
232 n = sscanf(d, "%4d%2d%2d", &year, &month, &day);
234 fprintf(stderr, "Can't parse year, month and day from %s\n", d);
236 return (time_t) 0; /* arbitrary */
241 fprintf(stderr, "Can't parse date from %s\n", d);
243 return (time_t) 0; /* arbitrary */
247 stm.tm_mon = month - 1;
252 result = tm_to_time_t(&stm);
259 parse_time(hyphenpos+1, &hour, &min, &sec);
260 stm = *localtime(&result);
264 result = tm_to_time_t(&stm);
276 int main (int argc, char **argv)
281 setlocale(LC_ALL, "");
286 fprintf(stderr, "Require an argument\n");
290 newtime = parse_date(argv[1], ref, (argc > 2));
292 strftime(buffer, sizeof(buffer), "%a %A %d %b %B %Y %H:%M:%S", localtime(&newtime));
293 printf("%s\n", buffer);