Began making changes to do better handling of character sets.
[citadel.git] / webcit / fmt_date.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup FormatDates Miscellaneous routines formating dates
6  * \ingroup Calendaring
7  */
8 /*@{*/
9 #include "webcit.h"
10 #include "webserver.h"
11
12 typedef unsigned char byte; /**< a byte. */
13
14 #define FALSE 0 /**< no. */
15 #define TRUE 1 /**< yes. */
16
17 /**
18  * \brief       Wrapper around strftime() or strftime_l()
19  *              depending upon how our build is configured.
20  *
21  * \param       s       String target buffer
22  * \param       max     Maximum size of string target buffer
23  * \param       format  strftime() format
24  * \param       tm      Input date/time
25  */
26 size_t wc_strftime(char *s, size_t max, const char *format, const struct tm *tm)
27 {
28 #ifdef ENABLE_NLS
29         if (wc_locales[WC->selected_language] == NULL) {
30                 return strftime(s, max, format, tm);
31         }
32         else {
33                 return strftime_l(s, max, format, tm, wc_locales[WC->selected_language]);
34         }
35 #else
36         return strftime(s, max, format, tm);
37 #endif
38 }
39
40
41 /**
42  * \brief Format a date/time stamp for output 
43  * \param buf the output buffer
44  * \param thetime time to convert to string 
45  * \param brief do we want compact view?????
46  */
47 void fmt_date(char *buf, time_t thetime, int brief)
48 {
49         struct tm tm;
50         struct tm today_tm;
51         time_t today_timet;
52         int hour;
53         char calhourformat[16];
54
55         get_preference("calhourformat", calhourformat, sizeof calhourformat);
56
57         today_timet = time(NULL);
58         localtime_r(&today_timet, &today_tm);
59
60         localtime_r(&thetime, &tm);
61         hour = tm.tm_hour;
62         if (hour == 0)
63                 hour = 12;
64         else if (hour > 12)
65                 hour = hour - 12;
66
67         buf[0] = 0;
68
69         if (brief) {
70
71                 /** If date == today, show only the time */
72                 if ((tm.tm_year == today_tm.tm_year)
73                   &&(tm.tm_mon == today_tm.tm_mon)
74                   &&(tm.tm_mday == today_tm.tm_mday)) {
75                         wc_strftime(buf, 32, "%l:%M%p", &tm);
76                 }
77                 /** Otherwise, for messages up to 6 months old, show the
78                  * month and day, and the time */
79                 else if (today_timet - thetime < 15552000) {
80                         wc_strftime(buf, 32, "%b %d %l:%M%p", &tm);
81                 }
82                 /** older than 6 months, show only the date */
83                 else {
84                         wc_strftime(buf, 32, "%b %d %Y", &tm);
85                 }
86         }
87         else {
88                 wc_strftime(buf, 32, "%c", &tm);
89         }
90 }
91
92
93 /**
94  * \brief Format TIME ONLY for output 
95  * \param buf the output buffer
96  * \param thetime time to format into buf
97  */
98 void fmt_time(char *buf, time_t thetime)
99 {
100         struct tm *tm;
101         int hour;
102         char calhourformat[16];
103
104         get_preference("calhourformat", calhourformat, sizeof calhourformat);
105
106         buf[0] = 0;
107         tm = localtime(&thetime);
108         hour = tm->tm_hour;
109         if (hour == 0)
110                 hour = 12;
111         else if (hour > 12)
112                 hour = hour - 12;
113
114         if (!strcasecmp(calhourformat, "24")) {
115                 sprintf(buf, "%2d:%02d",
116                         tm->tm_hour, tm->tm_min
117                 );
118         }
119         else {
120                 sprintf(buf, "%d:%02d%s",
121                         hour, tm->tm_min, ((tm->tm_hour > 12) ? "pm" : "am")
122                 );
123         }
124 }
125
126
127
128
129 /**
130  * \brief Break down the timestamp used in HTTP headers
131  * Should read rfc1123 and rfc850 dates OK
132  * \todo FIXME won't read asctime
133  * Doesn't understand timezone, but we only should be using GMT/UTC anyway
134  * \param buf time to parse
135  * \return the time found in buf
136  */
137 time_t httpdate_to_timestamp(char *buf)
138 {
139         time_t t = 0;
140         struct tm tt;
141         char *c;
142         char tz[256];
143
144         /** Skip day of week, to number */
145         for (c = buf; *c != ' '; c++)
146                 ;
147         c++;
148
149         /* Get day of month */
150         tt.tm_mday = atoi(c);
151         for (; *c != ' ' && *c != '-'; c++);
152         c++;
153
154         /** Get month */
155         switch (*c) {
156         case 'A':       /** April, August */
157                 tt.tm_mon = (c[1] == 'p') ? 3 : 7;
158                 break;
159         case 'D':       /** December */
160                 tt.tm_mon = 11;
161                 break;
162         case 'F':       /** February */
163                 tt.tm_mon = 1;
164                 break;
165         case 'M':       /** March, May */
166                 tt.tm_mon = (c[2] == 'r') ? 2 : 4;
167                 break;
168         case 'J':       /** January, June, July */
169                 tt.tm_mon = (c[2] == 'n') ? ((c[1] == 'a') ? 0 : 5) : 6;
170                 break;
171         case 'N':       /** November */
172                 tt.tm_mon = 10;
173                 break;
174         case 'O':       /** October */
175                 tt.tm_mon = 9;
176                 break;
177         case 'S':       /** September */
178                 tt.tm_mon = 8;
179                 break;
180         default:
181                 return 42;
182                 break;  /** NOTREACHED */
183         }
184         c += 4;
185
186         tt.tm_year = 0;
187         /** Get year */
188         tt.tm_year = atoi(c);
189         for (; *c != ' '; c++);
190         c++;
191         if (tt.tm_year >= 1900)
192                 tt.tm_year -= 1900;
193
194         /** Get hour */
195         tt.tm_hour = atoi(c);
196         for (; *c != ':'; c++);
197         c++;
198
199         /** Get minute */
200         tt.tm_min = atoi(c);
201         for (; *c != ':'; c++);
202         c++;
203
204         /** Get second */
205         tt.tm_sec = atoi(c);
206         for (; *c && *c != ' '; c++);
207
208         /** Got everything; let's go */
209         /** First, change to UTC */
210         if (getenv("TZ"))
211                 sprintf(tz, "TZ=%s", getenv("TZ"));
212         else
213                 strcpy(tz, "TZ=");
214         putenv("TZ=UTC");
215         tzset();
216         t = mktime(&tt);
217         putenv(tz);
218         tzset();
219         return t;
220 }
221
222
223
224
225 /*@}*/