]> git.ipfire.org Git - thirdparty/git.git/blame - date.c
[PATCH] Do date parsing by hand...
[thirdparty/git.git] / date.c
CommitLineData
ecee9d9e
ET
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <ctype.h>
11#include <time.h>
12
13static time_t my_mktime(struct tm *tm)
14{
15 static const int mdays[] = {
16 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
17 };
18 int year = tm->tm_year - 70;
19 int month = tm->tm_mon;
20 int day = tm->tm_mday;
21
22 if (year < 0 || year > 129) /* algo only works for 1970-2099 */
23 return -1;
24 if (month < 0 || month > 11) /* array bounds */
25 return -1;
26 if (month < 2 || (year + 2) % 4)
27 day--;
28 return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
29 tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
30}
31
32static const char *month_names[] = {
33 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
34 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
35};
36
37static const char *weekday_names[] = {
38 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
39};
40
41
42static char *skipfws(char *str)
43{
44 while (isspace(*str))
45 str++;
46 return str;
47}
48
49
50/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
51 (i.e. English) day/month names, and it doesn't work correctly with %z. */
52void parse_date(char *date, char *result, int maxlen)
53{
54 struct tm tm;
55 char *p, *tz;
56 int i, offset;
57 time_t then;
58
59 memset(&tm, 0, sizeof(tm));
60
61 /* Skip day-name */
62 p = skipfws(date);
63 if (!isdigit(*p)) {
64 for (i=0; i<7; i++) {
65 if (!strncmp(p,weekday_names[i],3) && p[3] == ',') {
66 p = skipfws(p+4);
67 goto day;
68 }
69 }
70 return;
71 }
72
73 /* day */
74 day:
75 tm.tm_mday = strtoul(p, &p, 10);
76
77 if (tm.tm_mday < 1 || tm.tm_mday > 31)
78 return;
79
80 if (!isspace(*p))
81 return;
82
83 p = skipfws(p);
84
85 /* month */
86
87 for (i=0; i<12; i++) {
88 if (!strncmp(p, month_names[i], 3) && isspace(p[3])) {
89 tm.tm_mon = i;
90 p = skipfws(p+strlen(month_names[i]));
91 goto year;
92 }
93 }
94 return; /* Error -- bad month */
95
96 /* year */
97 year:
98 tm.tm_year = strtoul(p, &p, 10);
99
100 if (!tm.tm_year && !isspace(*p))
101 return;
102
103 if (tm.tm_year > 1900)
104 tm.tm_year -= 1900;
105
106 p=skipfws(p);
107
108 /* hour */
109 if (!isdigit(*p))
110 return;
111 tm.tm_hour = strtoul(p, &p, 10);
112
113 if (tm.tm_hour > 23)
114 return;
115
116 if (*p != ':')
117 return; /* Error -- bad time */
118 p++;
119
120 /* minute */
121 if (!isdigit(*p))
122 return;
123 tm.tm_min = strtoul(p, &p, 10);
124
125 if (tm.tm_min > 59)
126 return;
127
128 if (*p != ':')
129 goto zone;
130 p++;
131
132 /* second */
133 if (!isdigit(*p))
134 return;
135 tm.tm_sec = strtoul(p, &p, 10);
136
137 if (tm.tm_sec > 60)
138 return;
139
140 zone:
141 if (!isspace(*p))
142 return;
143
144 p = skipfws(p);
145
146 if (*p == '-')
147 offset = -60;
148 else if (*p == '+')
149 offset = 60;
150 else
151 return;
152
153 if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
154 return;
155
156 tz = p;
157 i = strtoul(p+1, NULL, 10);
158 offset *= ((i % 100) + ((i / 100) * 60));
159
160 p = skipfws(p + 5);
161 if (*p && *p != '(') /* trailing comment like (EDT) is ok */
162 return;
163
164 then = my_mktime(&tm); /* mktime uses local timezone */
165 if (then == -1)
166 return;
167
168 then -= offset;
169
170 snprintf(result, maxlen, "%lu %5.5s", then, tz);
171}
172
173void datestamp(char *buf, int bufsize)
174{
175 time_t now;
176 int offset;
177
178 time(&now);
179
180 offset = my_mktime(localtime(&now)) - now;
181 offset /= 60;
182
183 snprintf(buf, bufsize, "%lu %+05d", now, offset/60*100 + offset%60);
184}