[PATCH] compat: replace AF_LOCAL with AF_UNIX
[git/gitweb.git] / date.c
blob1e43936f8ebb9c7462347ab3a8b192a973b36195
1 /*
2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <time.h>
13 static time_t my_mktime(struct tm *tm)
15 static const int mdays[] = {
16 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
18 int year = tm->tm_year - 70;
19 int month = tm->tm_mon;
20 int day = tm->tm_mday;
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;
32 static const char *month_names[] = {
33 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
34 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
37 static const char *weekday_names[] = {
38 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
42 static char *skipfws(char *str)
44 while (isspace(*str))
45 str++;
46 return str;
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. */
52 void parse_date(char *date, char *result, int maxlen)
54 struct tm tm;
55 char *p, *tz;
56 int i, offset;
57 time_t then;
59 memset(&tm, 0, sizeof(tm));
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;
70 return;
73 /* day */
74 day:
75 tm.tm_mday = strtoul(p, &p, 10);
77 if (tm.tm_mday < 1 || tm.tm_mday > 31)
78 return;
80 if (!isspace(*p))
81 return;
83 p = skipfws(p);
85 /* month */
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;
94 return; /* Error -- bad month */
96 /* year */
97 year:
98 tm.tm_year = strtoul(p, &p, 10);
100 if (!tm.tm_year && !isspace(*p))
101 return;
103 if (tm.tm_year > 1900)
104 tm.tm_year -= 1900;
106 p=skipfws(p);
108 /* hour */
109 if (!isdigit(*p))
110 return;
111 tm.tm_hour = strtoul(p, &p, 10);
113 if (tm.tm_hour > 23)
114 return;
116 if (*p != ':')
117 return; /* Error -- bad time */
118 p++;
120 /* minute */
121 if (!isdigit(*p))
122 return;
123 tm.tm_min = strtoul(p, &p, 10);
125 if (tm.tm_min > 59)
126 return;
128 if (*p != ':')
129 goto zone;
130 p++;
132 /* second */
133 if (!isdigit(*p))
134 return;
135 tm.tm_sec = strtoul(p, &p, 10);
137 if (tm.tm_sec > 60)
138 return;
140 zone:
141 if (!isspace(*p))
142 return;
144 p = skipfws(p);
146 if (*p == '-')
147 offset = -60;
148 else if (*p == '+')
149 offset = 60;
150 else
151 return;
153 if (!isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]) || !isdigit(p[4]))
154 return;
156 tz = p;
157 i = strtoul(p+1, NULL, 10);
158 offset *= ((i % 100) + ((i / 100) * 60));
160 p = skipfws(p + 5);
161 if (*p && *p != '(') /* trailing comment like (EDT) is ok */
162 return;
164 then = my_mktime(&tm); /* mktime uses local timezone */
165 if (then == -1)
166 return;
168 then -= offset;
170 snprintf(result, maxlen, "%lu %5.5s", then, tz);
173 void datestamp(char *buf, int bufsize)
175 time_t now;
176 int offset;
178 time(&now);
180 offset = my_mktime(localtime(&now)) - now;
181 offset /= 60;
183 snprintf(buf, bufsize, "%lu %+05d", now, offset/60*100 + offset%60);