a93e75f827883860e32e5462733b45774e7d03ba
[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 { // TODO: this gives empty strings on debian.
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 time_format;
53         
54         time_format = get_time_format_cached ();
55         today_timet = time(NULL);
56         localtime_r(&today_timet, &today_tm);
57
58         localtime_r(&thetime, &tm);
59
60         if (brief) {
61
62                 /** If date == today, show only the time */
63                 if ((tm.tm_year == today_tm.tm_year)
64                   &&(tm.tm_mon == today_tm.tm_mon)
65                   &&(tm.tm_mday == today_tm.tm_mday)) {
66                         if (time_format == WC_TIMEFORMAT_24) 
67                                 wc_strftime(buf, 32, "%k:%M", &tm);
68                         else
69                                 wc_strftime(buf, 32, "%l:%M%p", &tm);
70                 }
71                 /** Otherwise, for messages up to 6 months old, show the month and day, and the time */
72                 else if (today_timet - thetime < 15552000) {
73                         if (time_format == WC_TIMEFORMAT_24) 
74                                 wc_strftime(buf, 32, "%b %d %k:%M", &tm);
75                         else
76                                 wc_strftime(buf, 32, "%b %d %l:%M%p", &tm);
77                 }
78                 /** older than 6 months, show only the date */
79                 else {
80                         wc_strftime(buf, 32, "%b %d %Y", &tm);
81                 }
82         }
83         else {
84                 if (time_format == WC_TIMEFORMAT_24)
85                         wc_strftime(buf, 32, "%a %b %d %Y %T %Z", &tm);
86                 else
87                         wc_strftime(buf, 32, "%a %b %d %Y %r %Z", &tm);
88         }
89 }
90
91
92 /**
93  * \brief learn the users timeformat preference.
94  */
95 int get_time_format_cached (void)
96 {
97         char calhourformat[16];
98         int *time_format_cache;
99         time_format_cache = &(WC->time_format_cache);
100         if (*time_format_cache == WC_TIMEFORMAT_NONE)
101         {
102                 get_preference("calhourformat", calhourformat, sizeof calhourformat);
103                 if (!strcasecmp(calhourformat, "24")) 
104                         *time_format_cache = WC_TIMEFORMAT_24;
105                 else
106                         *time_format_cache = WC_TIMEFORMAT_AMPM;
107         }
108         return *time_format_cache;
109 }
110
111 /**
112  * \brief Format TIME ONLY for output 
113  * \param buf the output buffer
114  * \param thetime time to format into buf
115  */
116 void fmt_time(char *buf, time_t thetime)
117 {
118         struct tm *tm;
119         int hour;
120         int time_format;
121         
122         time_format = get_time_format_cached ();
123         buf[0] = 0;
124         tm = localtime(&thetime);
125         hour = tm->tm_hour;
126         if (hour == 0)
127                 hour = 12;
128         else if (hour > 12)
129                 hour = hour - 12;
130
131         if (time_format == WC_TIMEFORMAT_24) {
132                 sprintf(buf, "%2d:%02d",
133                         tm->tm_hour, tm->tm_min
134                 );
135         }
136         else {
137                 sprintf(buf, "%d:%02d%s",
138                         hour, tm->tm_min, ((tm->tm_hour > 12) ? "pm" : "am")
139                 );
140         }
141 }
142
143
144
145
146 /**
147  * \brief Break down the timestamp used in HTTP headers
148  * Should read rfc1123 and rfc850 dates OK
149  * \todo FIXME won't read asctime
150  * Doesn't understand timezone, but we only should be using GMT/UTC anyway
151  * \param buf time to parse
152  * \return the time found in buf
153  */
154 time_t httpdate_to_timestamp(char *buf)
155 {
156         time_t t = 0;
157         struct tm tt;
158         char *c;
159         char tz[256];
160
161         /** Skip day of week, to number */
162         for (c = buf; *c != ' '; c++)
163                 ;
164         c++;
165
166         /* Get day of month */
167         tt.tm_mday = atoi(c);
168         for (; *c != ' ' && *c != '-'; c++);
169         c++;
170
171         /** Get month */
172         switch (*c) {
173         case 'A':       /** April, August */
174                 tt.tm_mon = (c[1] == 'p') ? 3 : 7;
175                 break;
176         case 'D':       /** December */
177                 tt.tm_mon = 11;
178                 break;
179         case 'F':       /** February */
180                 tt.tm_mon = 1;
181                 break;
182         case 'M':       /** March, May */
183                 tt.tm_mon = (c[2] == 'r') ? 2 : 4;
184                 break;
185         case 'J':       /** January, June, July */
186                 tt.tm_mon = (c[2] == 'n') ? ((c[1] == 'a') ? 0 : 5) : 6;
187                 break;
188         case 'N':       /** November */
189                 tt.tm_mon = 10;
190                 break;
191         case 'O':       /** October */
192                 tt.tm_mon = 9;
193                 break;
194         case 'S':       /** September */
195                 tt.tm_mon = 8;
196                 break;
197         default:
198                 return 42;
199                 break;  /** NOTREACHED */
200         }
201         c += 4;
202
203         tt.tm_year = 0;
204         /** Get year */
205         tt.tm_year = atoi(c);
206         for (; *c != ' '; c++);
207         c++;
208         if (tt.tm_year >= 1900)
209                 tt.tm_year -= 1900;
210
211         /** Get hour */
212         tt.tm_hour = atoi(c);
213         for (; *c != ':'; c++);
214         c++;
215
216         /** Get minute */
217         tt.tm_min = atoi(c);
218         for (; *c != ':'; c++);
219         c++;
220
221         /** Get second */
222         tt.tm_sec = atoi(c);
223         for (; *c && *c != ' '; c++);
224
225         /** Got everything; let's go */
226         /** First, change to UTC */
227         if (getenv("TZ"))
228                 sprintf(tz, "TZ=%s", getenv("TZ"));
229         else
230                 strcpy(tz, "TZ=");
231         putenv("TZ=UTC");
232         tzset();
233         t = mktime(&tt);
234         putenv(tz);
235         tzset();
236         return t;
237 }
238
239
240
241
242 /*@}*/