c37756d44f72adef6b79922d49c2b192141671fa
[claws.git] / src / plugins / rssyl / libfeed / date.c
1 /**
2  * @file common.c common routines for Liferea
3  * 
4  * Copyright (C) 2003-2005  Lars Lindner <lars.lindner@gmx.net>
5  * Copyright (C) 2004,2005  Nathan J. Conrad <t98502@users.sourceforge.net>
6  * Copyright (C) 2004       Karl Soderstrom <ks@xanadunet.net>
7  *
8  * parts of the RFC822 timezone decoding were taken from the gmime 
9  * source written by 
10  *
11  * Authors: Michael Zucchi <notzed@helixcode.com>
12  *          Jeffrey Stedfast <fejj@helixcode.com>
13  *
14  * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #  include <config.h>
33 #endif
34
35 /* this is needed for strptime() */
36 #define _XOPEN_SOURCE /* glibc2 needs this */
37
38 #include <time.h>
39 #include <glib.h>
40 #include <locale.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <stdlib.h>
44
45 /* converts a ISO 8601 time string to a time_t value */
46 time_t parseISO8601Date(gchar *date) {
47         struct tm       tm;
48         time_t          t, t2, offset = 0;
49         gboolean        success = FALSE;
50         gchar *pos;
51
52         if (date == NULL)
53                 return -1;
54         
55         memset(&tm, 0, sizeof(struct tm));
56         
57         /* we expect at least something like "2003-08-07T15:28:19" and
58            don't require the second fractions and the timezone info
59
60            the most specific format:   YYYY-MM-DDThh:mm:ss.sTZD
61          */
62          
63         /* full specified variant */
64         if(NULL != (pos = strptime((const char *)date, "%Y-%m-%dT%H:%M:%SZ", &tm))) {
65                 /* Parse seconds */
66                 if (*pos == ':')
67                         pos++;
68                 if (isdigit(pos[0]) && !isdigit(pos[1])) {
69                         tm.tm_sec = pos[0] - '0';
70                         pos++;
71                 } else if (isdigit(pos[0]) && isdigit(pos[1])) {
72                         tm.tm_sec = 10*(pos[0]-'0') + pos[1] - '0';
73                         pos +=2;
74                 }
75                 /* Parse timezone */
76                 if (*pos == 'Z')
77                         offset = 0;
78                 else if ((*pos == '+' || *pos == '-') && isdigit(pos[1]) && isdigit(pos[2]) && strlen(pos) >= 3) {
79                         offset = (10*(pos[1] - '0') + (pos[2] - '0')) * 60 * 60;
80                         
81                         if (pos[3] == ':' && isdigit(pos[4]) && isdigit(pos[5]))
82                                 offset +=  (10*(pos[4] - '0') + (pos[5] - '0')) * 60;
83                         else if (isdigit(pos[3]) && isdigit(pos[4]))
84                                 offset +=  (10*(pos[3] - '0') + (pos[4] - '0')) * 60;
85                         
86                         offset *= (pos[0] == '+') ? 1 : -1;
87
88                 }
89                 success = TRUE;
90         /* only date */
91         } else if(NULL != strptime((const char *)date, "%t%Y-%m-%d", &tm))
92                 success = TRUE;
93         /* there were others combinations too... */
94
95         if(TRUE == success) {
96                 if((time_t)(-1) != (t = mktime(&tm))) {
97                         /* Correct for the local timezone*/
98                         t = t - offset;
99                         t2 = mktime(gmtime(&t));
100                         t = t - (t2 - t);
101                         
102                         return t;
103                 } else {
104                         g_warning("internal error! time conversion error! mktime failed!\n");
105                 }
106         } else {
107                 g_warning("Invalid ISO8601 date format! Ignoring <dc:date> information!\n");
108         }
109         
110         return 0;
111 }
112
113 gchar *dayofweek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
114 gchar *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
115
116 gchar *createRFC822Date(const time_t *time) {
117         struct tm *tm;
118
119         tm = gmtime(time); /* No need to free because it is statically allocated */
120         return g_strdup_printf("%s, %2d %s %4d %02d:%02d:%02d GMT", dayofweek[tm->tm_wday], tm->tm_mday,
121                                            months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
122 }
123
124 time_t parseRFC822Date(gchar *date)
125 {
126         struct tm t;
127         memset(&t, 0, sizeof(struct tm));
128         const char *c = setlocale(LC_TIME, NULL);
129
130         /* Adjust the LC_TIME locale to standard C in order for strptime()
131          * to work reliably. */
132         if (c != NULL)
133                 setlocale(LC_TIME, "C");
134
135         if (!strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) &&
136                 !strptime(date, "%a, %d %b %Y %H:%M %Z", &t)) {
137                 g_warning("Invalid RFC822 date!\n");
138                 if (c != NULL)
139                         setlocale(LC_TIME, c);
140                 return 0;
141         }
142
143         /* Restore the original LC_TIME locale. */
144         if (c != NULL)
145                 setlocale(LC_TIME, c);
146
147         return mktime(&t);
148 }