1 /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 #include <config.h>
3 
4 #include <glib.h>
5 #include <glib/gi18n.h>
6 
7 #include <string.h>
8 
9 #include "e_date.h"
10 
11 /*
12   all this code comes from evolution
13   - e-util.c
14   - message-list.c
15 */
16 
17 
18 static size_t e_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
19 {
20 #ifdef HAVE_LKSTRFTIME
21     return strftime(s, max, fmt, tm);
22 #else
23     char *c, *ffmt, *ff;
24     size_t ret;
25 
26     ffmt = g_strdup(fmt);
27     ff = ffmt;
28     while ((c = strstr(ff, "%l")) != NULL) {
29         c[1] = 'I';
30         ff = c;
31     }
32 
33     ff = ffmt;
34     while ((c = strstr(ff, "%k")) != NULL) {
35         c[1] = 'H';
36         ff = c;
37     }
38 
39     ret = strftime(s, max, ffmt, tm);
40     g_free(ffmt);
41     return ret;
42 #endif
43 }
44 
45 
46 /**
47  * Function to do a last minute fixup of the AM/PM stuff if the locale
48  * and gettext haven't done it right. Most English speaking countries
49  * except the USA use the 24 hour clock (UK, Australia etc). However
50  * since they are English nobody bothers to write a language
51  * translation (gettext) file. So the locale turns off the AM/PM, but
52  * gettext does not turn on the 24 hour clock. Leaving a mess.
53  *
54  * This routine checks if AM/PM are defined in the locale, if not it
55  * forces the use of the 24 hour clock.
56  *
57  * The function itself is a front end on strftime and takes exactly
58  * the same arguments.
59  *
60  * TODO: Actually remove the '%p' from the fixed up string so that
61  * there isn't a stray space.
62  **/
63 
64 static size_t e_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
65 {
66     char buf[10];
67     char *sp;
68     char *ffmt;
69     size_t ret;
70 
71     if (strstr(fmt, "%p")==NULL && strstr(fmt, "%P")==NULL) {
72         /* No AM/PM involved - can use the fmt string directly */
73         ret=e_strftime(s, max, fmt, tm);
74     } else {
75         /* Get the AM/PM symbol from the locale */
76         e_strftime (buf, 10, "%p", tm);
77 
78         if (buf[0]) {
79             /**
80              * AM/PM have been defined in the locale
81              * so we can use the fmt string directly
82              **/
83             ret=e_strftime(s, max, fmt, tm);
84         } else {
85             /**
86              * No AM/PM defined by locale
87              * must change to 24 hour clock
88              **/
89             ffmt=g_strdup(fmt);
90             for (sp=ffmt; (sp=strstr(sp, "%l")); sp++) {
91                 /**
92                  * Maybe this should be 'k', but I have never
93                  * seen a 24 clock actually use that format
94                  **/
95                 sp[1]='H';
96             }
97             for (sp=ffmt; (sp=strstr(sp, "%I")); sp++) {
98                 sp[1]='H';
99             }
100             ret=e_strftime(s, max, ffmt, tm);
101             g_free(ffmt);
102         }
103     }
104     return(ret);
105 }
106 
107 static size_t
108 e_utf8_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct tm *tm)
109 {
110     size_t sz, ret;
111     char *locale_fmt, *buf;
112 
113     locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
114     if (!locale_fmt)
115         return 0;
116 
117     ret = e_strftime_fix_am_pm(s, max, locale_fmt, tm);
118     if (!ret) {
119         g_free (locale_fmt);
120         return 0;
121     }
122 
123     buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
124     if (!buf) {
125         g_free (locale_fmt);
126         return 0;
127     }
128 
129     if (sz >= max) {
130         char *tmp = buf + max - 1;
131         tmp = g_utf8_find_prev_char(buf, tmp);
132         if (tmp)
133             sz = tmp - buf;
134         else
135             sz = 0;
136     }
137     memcpy(s, buf, sz);
138     s[sz] = '\0';
139     g_free(locale_fmt);
140     g_free(buf);
141     return sz;
142 }
143 
144 
145 static char *
146 filter_date (time_t date)
147 {
148     time_t nowdate = time(NULL);
149     time_t yesdate;
150     struct tm then, now, yesterday;
151     char buf[26];
152     gboolean done = FALSE;
153 
154     if (date == 0)
155         // xgettext: ? stands for unknown
156         return g_strdup (_("?"));
157 
158     localtime_r (&date, &then);
159     localtime_r (&nowdate, &now);
160     if (then.tm_mday == now.tm_mday &&
161         then.tm_mon == now.tm_mon &&
162         then.tm_year == now.tm_year) {
163         e_utf8_strftime_fix_am_pm (buf, 26, _("Today %l∶%M %p"), &then);
164         done = TRUE;
165     }
166     if (!done) {
167         yesdate = nowdate - 60 * 60 * 24;
168         localtime_r (&yesdate, &yesterday);
169         if (then.tm_mday == yesterday.tm_mday &&
170             then.tm_mon == yesterday.tm_mon &&
171             then.tm_year == yesterday.tm_year) {
172             e_utf8_strftime_fix_am_pm (buf, 26, _("Yesterday %l∶%M %p"), &then);
173             done = TRUE;
174         }
175     }
176     if (!done) {
177         int i;
178         for (i = 2; i < 7; i++) {
179             yesdate = nowdate - 60 * 60 * 24 * i;
180             localtime_r (&yesdate, &yesterday);
181             if (then.tm_mday == yesterday.tm_mday &&
182                 then.tm_mon == yesterday.tm_mon &&
183                 then.tm_year == yesterday.tm_year) {
184                 e_utf8_strftime_fix_am_pm (buf, 26, _("%a %l∶%M %p"), &then);
185                 done = TRUE;
186                 break;
187             }
188         }
189     }
190     if (!done) {
191         if (then.tm_year == now.tm_year) {
192             e_utf8_strftime_fix_am_pm (buf, 26, _("%b %d %l∶%M %p"), &then);
193         } else {
194             e_utf8_strftime_fix_am_pm (buf, 26, _("%b %d %Y"), &then);
195         }
196     }
197 #if 0
198 #ifdef CTIME_R_THREE_ARGS
199     ctime_r (&date, buf, 26);
200 #else
201     ctime_r (&date, buf);
202 #endif
203 #endif
204 
205     return g_strdup (buf);
206 }
207 
208 
209 
210 
211 char *
212 procman_format_date_for_display(time_t d)
213 {
214     return filter_date(d);
215 }
216