Back to index

webcit  8.12-dfsg
fmt_date.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-2012 by the citadel.org team
00003  *
00004  * This program is open source software.  You can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License, version 3.
00006  *
00007  * This program is distributed in the hope that it will be useful,
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  * GNU General Public License for more details.
00011  */
00012 
00013 #include "webcit.h"
00014 #include "webserver.h"
00015 
00016 #ifdef HAVE_USELOCALE
00017 extern locale_t *wc_locales;
00018 #endif
00019 
00020 typedef unsigned char byte;
00021 
00022 #define FALSE 0 
00023 #define TRUE 1 
00025 /*
00026  * Wrapper around strftime() or strftime_l()
00027  * depending upon how our build is configured.
00028  *
00029  * s          String target buffer
00030  * max        Maximum size of string target buffer
00031  * format     strftime() format
00032  * tm         Input date/time
00033  */
00034 size_t wc_strftime(char *s, size_t max, const char *format, const struct tm *tm)
00035 {
00036 
00037 #ifdef ENABLE_NLS
00038 #ifdef HAVE_USELOCALE
00039        if (wc_locales[WC->selected_language] == NULL) {
00040               return strftime(s, max, format, tm);
00041        }
00042        else {
00043               return strftime_l(s, max, format, tm, wc_locales[WC->selected_language]);
00044        }
00045 #else
00046        return strftime(s, max, format, tm);
00047 #endif
00048 #else
00049        return strftime(s, max, format, tm);
00050 #endif
00051 }
00052 
00053 
00054 
00055 /*
00056  * Format a date/time stamp for output 
00057  */
00058 void webcit_fmt_date(char *buf, size_t siz, time_t thetime, int Format)
00059 {
00060        struct tm tm;
00061        struct tm today_tm;
00062        time_t today_timet;
00063        int time_format;
00064 
00065        time_format = get_time_format_cached ();
00066        today_timet = time(NULL);
00067        localtime_r(&today_timet, &today_tm);
00068 
00069        localtime_r(&thetime, &tm);
00070 
00071        /*
00072         * DATEFMT_FULL:      full display 
00073         * DATEFMT_BRIEF:     if date == today, show only the time
00074         *                  otherwise, for messages up to 6 months old, 
00075         *                 show the month and day, and the time
00076         *                  older than 6 months, show only the date
00077         * DATEFMT_RAWDATE:   show full date, regardless of age 
00078         * DATEFMT_LOCALEDATE:   show full date as prefered for the locale
00079         */
00080 
00081        switch (Format) {
00082               case DATEFMT_BRIEF:
00083                      if ((tm.tm_year == today_tm.tm_year)
00084                        &&(tm.tm_mon == today_tm.tm_mon)
00085                        &&(tm.tm_mday == today_tm.tm_mday)) {
00086                             if (time_format == WC_TIMEFORMAT_24) 
00087                                    wc_strftime(buf, siz, "%k:%M", &tm);
00088                             else
00089                                    wc_strftime(buf, siz, "%l:%M%p", &tm);
00090                      }
00091                      else if (today_timet - thetime < 15552000) {
00092                             if (time_format == WC_TIMEFORMAT_24) 
00093                                    wc_strftime(buf, siz, "%b %d %k:%M", &tm);
00094                             else
00095                                    wc_strftime(buf, siz, "%b %d %l:%M%p", &tm);
00096                      }
00097                      else {
00098                             wc_strftime(buf, siz, "%b %d %Y", &tm);
00099                      }
00100                      break;
00101               case DATEFMT_FULL:
00102                      if (time_format == WC_TIMEFORMAT_24)
00103                             wc_strftime(buf, siz, "%a %b %d %Y %T %Z", &tm);
00104                      else
00105                             wc_strftime(buf, siz, "%a %b %d %Y %r %Z", &tm);
00106                      break;
00107               case DATEFMT_RAWDATE:
00108                      wc_strftime(buf, siz, "%a %b %d %Y", &tm);
00109                      break;
00110               case DATEFMT_LOCALEDATE:
00111                      wc_strftime(buf, siz, "%x", &tm);
00112                      break;
00113        }
00114 }
00115 
00116 
00117 /* 
00118  * Try to guess whether the user will prefer 12 hour or 24 hour time based on the locale.
00119  */
00120 long guess_calhourformat(void) {
00121        char buf[64];
00122        struct tm tm;
00123        memset(&tm, 0, sizeof tm);
00124        wc_strftime(buf, 64, "%X", &tm);
00125        if (buf[strlen(buf)-1] == 'M') {
00126               return 12;
00127        }
00128        return 24;
00129 }
00130 
00131 
00132 /*
00133  * learn the users timeformat preference.
00134  */
00135 int get_time_format_cached (void)
00136 {
00137        long calhourformat;
00138        int *time_format_cache;
00139        time_format_cache = &(WC->time_format_cache);
00140        if (*time_format_cache == WC_TIMEFORMAT_NONE)
00141        {
00142               get_pref_long("calhourformat", &calhourformat, 99);
00143 
00144               /* If we don't know the user's time format preference yet,
00145                * make a guess based on the locale.
00146                */
00147               if (calhourformat == 99) {
00148                      calhourformat = guess_calhourformat();
00149               }
00150 
00151               /* Now set the preference */
00152               if (calhourformat == 24) 
00153                      *time_format_cache = WC_TIMEFORMAT_24;
00154               else
00155                      *time_format_cache = WC_TIMEFORMAT_AMPM;
00156        }
00157        return *time_format_cache;
00158 }
00159 
00160 /*
00161  * Format TIME ONLY for output 
00162  * buf        the output buffer
00163  * thetime    time to format into buf
00164  */
00165 void fmt_time(char *buf, size_t siz, time_t thetime)
00166 {
00167        struct tm *tm;
00168        int hour;
00169        int time_format;
00170        
00171        time_format = get_time_format_cached ();
00172        buf[0] = 0;
00173        tm = localtime(&thetime);
00174        hour = tm->tm_hour;
00175        if (hour == 0)
00176               hour = 12;
00177        else if (hour > 12)
00178               hour = hour - 12;
00179 
00180        if (time_format == WC_TIMEFORMAT_24) {
00181               snprintf(buf, siz, "%d:%02d",
00182                      tm->tm_hour, tm->tm_min
00183               );
00184        }
00185        else {
00186               snprintf(buf, siz, "%d:%02d%s",
00187                      hour, tm->tm_min, ((tm->tm_hour > 12) ? "pm" : "am")
00188               );
00189        }
00190 }
00191 
00192 
00193 
00194 
00195 /*
00196  * Break down the timestamp used in HTTP headers
00197  * Should read rfc1123 and rfc850 dates OK
00198  * FIXME won't read asctime
00199  * Doesn't understand timezone, but we only should be using GMT/UTC anyway
00200  */
00201 time_t httpdate_to_timestamp(StrBuf *buf)
00202 {
00203        time_t t = 0;
00204        struct tm tt;
00205        const char *c;
00206 
00208        for (c = ChrPtr(buf); *c != ' '; c++)
00209               ;
00210        c++;
00211        
00212        memset(&tt, 0, sizeof(tt));
00213 
00214        /* Get day of month */
00215        tt.tm_mday = atoi(c);
00216        for (; *c != ' ' && *c != '-'; c++);
00217        c++;
00218 
00219        /* Get month */
00220        switch (*c) {
00221        case 'A':     /* April, August */
00222               tt.tm_mon = (c[1] == 'p') ? 3 : 7;
00223               break;
00224        case 'D':     /* December */
00225               tt.tm_mon = 11;
00226               break;
00227        case 'F':     /* February */
00228               tt.tm_mon = 1;
00229               break;
00230        case 'M':     /* March, May */
00231               tt.tm_mon = (c[2] == 'r') ? 2 : 4;
00232               break;
00233        case 'J':     /* January, June, July */
00234               tt.tm_mon = (c[2] == 'n') ? ((c[1] == 'a') ? 0 : 5) : 6;
00235               break;
00236        case 'N':     /* November */
00237               tt.tm_mon = 10;
00238               break;
00239        case 'O':     /* October */
00240               tt.tm_mon = 9;
00241               break;
00242        case 'S':     /* September */
00243               tt.tm_mon = 8;
00244               break;
00245        default:
00246               return 42;
00247               break; /* NOTREACHED */
00248        }
00249        c += 4;
00250 
00251        tt.tm_year = 0;
00252        /* Get year */
00253        tt.tm_year = atoi(c);
00254        for (; *c != ' '; c++);
00255        c++;
00256        if (tt.tm_year >= 1900)
00257               tt.tm_year -= 1900;
00258 
00259        /* Get hour */
00260        tt.tm_hour = atoi(c);
00261        for (; *c != ':'; c++);
00262        c++;
00263 
00264        /* Get minute */
00265        tt.tm_min = atoi(c);
00266        for (; *c != ':'; c++);
00267        c++;
00268 
00269        /* Get second */
00270        tt.tm_sec = atoi(c);
00271        for (; *c && *c != ' '; c++);
00272 
00273        /* Got everything; let's go.  The global 'timezone' variable contains the
00274         * local timezone's offset from UTC, in seconds, so we apply that to tm_sec.
00275         * This produces an illegal value for tm_sec, but mktime() will normalize
00276         * it for us.  This eliminates the need to temporarily switch the environment
00277         * variable TZ to UTC, which is good because it fails to switch back on
00278         * some systems.
00279         */
00280        tzset();
00281        tt.tm_sec = tt.tm_sec - (int)timezone;
00282        t = mktime(&tt);
00283        return t;
00284 }
00285 
00286 
00287 void LoadTimeformatSettingsCache(StrBuf *Preference, long lvalue)
00288 {
00289        int *time_format_cache;
00290        
00291         time_format_cache = &(WC->time_format_cache);
00292         if (lvalue == 24) 
00293                *time_format_cache = WC_TIMEFORMAT_24;
00294         else
00295                *time_format_cache = WC_TIMEFORMAT_AMPM;
00296 }
00297 
00298 
00299 
00300 void 
00301 InitModule_DATETIME
00302 (void)
00303 {
00304        RegisterPreference("calhourformat", _("Time format"), PRF_INT, LoadTimeformatSettingsCache);
00305 
00306 
00307 }