Remove build warning
[platform/upstream/libsoup.git] / libsoup / soup-date.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-date.c: Date/time handling
4  *
5  * Copyright (C) 2005, Novell, Inc.
6  * Copyright (C) 2007, Red Hat, Inc.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "soup-date.h"
17 #include "soup.h"
18 #include "TIZEN.h"
19
20 #if ENABLE(TIZEN_TV_ADJUST_TIME)
21 #include <time.h>
22 #endif
23 /**
24  * SoupDate:
25  * @year: the year, 1 to 9999
26  * @month: the month, 1 to 12
27  * @day: day of the month, 1 to 31
28  * @hour: hour of the day, 0 to 23
29  * @minute: minute, 0 to 59
30  * @second: second, 0 to 59 (or up to 61 in the case of leap seconds)
31  * @utc: %TRUE if the date is in UTC
32  * @offset: offset from UTC
33
34  * A date and time. The date is assumed to be in the (proleptic)
35  * Gregorian calendar. The time is in UTC if @utc is %TRUE. Otherwise,
36  * the time is a local time, and @offset gives the offset from UTC in
37  * minutes (such that adding @offset to the time would give the
38  * correct UTC time). If @utc is %FALSE and @offset is 0, then the
39  * %SoupDate represents a "floating" time with no associated timezone
40  * information.
41  **/
42
43 /* Do not internationalize */
44 static const char *const months[] = {
45         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
46         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
47 };
48
49 /* Do not internationalize */
50 static const char *const days[] = {
51         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
52 };
53
54 static const int nonleap_days_in_month[] = {
55         0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
56 };
57
58 static const int nonleap_days_before[] = {
59         0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
60 };
61
62 static inline gboolean
63 is_leap_year (int year)
64 {
65         return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
66 }
67
68 /* Computes the number of days since proleptic Gregorian 0000-12-31.
69  * (That is, 0001-01-01 is "1", and 1970-01-01 is 719163.
70  */
71 static int
72 rata_die_day (SoupDate *date)
73 {
74         int day;
75
76         day = (date->year - 1) * 365 + ((date->year - 1) / 4) -
77                 ((date->year - 1) / 100) + ((date->year - 1) / 400);
78         day += nonleap_days_before[date->month] + date->day;
79         if (is_leap_year (date->year) && date->month > 2)
80                 day++;
81         return day;
82 }
83
84 #define TIME_T_EPOCH_RATA_DIE_DAY 719163
85
86 static inline int
87 days_in_month (int month, int year)
88 {
89         if (month == 2 && is_leap_year (year))
90                 return 29;
91         else
92                 return nonleap_days_in_month[month];
93 }
94
95 G_DEFINE_BOXED_TYPE (SoupDate, soup_date, soup_date_copy, soup_date_free)
96
97 static void
98 soup_date_fixup (SoupDate *date)
99 {
100         /* We only correct date->second if it's negative or too high
101          * to be a leap second.
102          */
103         if (date->second < 0 || date->second > 61) {
104                 date->minute += date->second / 60;
105                 date->second %= 60;
106                 if (date->second < 0)
107                         date->second += 60;
108         }
109
110         if (date->minute < 0 || date->minute > 59) {
111                 date->hour += date->minute / 60;
112                 date->minute %= 60;
113                 if (date->minute < 0)
114                         date->minute += 60;
115         }
116
117         if (date->hour < 0 || date->hour > 23) {
118                 date->day += date->hour / 24;
119                 date->hour %= 24;
120                 if (date->hour < 0)
121                         date->hour += 24;
122         }
123
124         /* Have to make sure month is valid before we can look at the
125          * day.
126          */
127         if (date->month < 1 || date->month > 12) {
128                 date->year += ((date->month - 1) / 12) + 1;
129                 date->month = ((date->month - 1) % 12) + 1;
130                 if (date->month < 1)
131                         date->month += 12;
132         }
133
134         if (date->day < 0) {
135                 while (date->day < 0) {
136                         if (date->month == 1) {
137                                 date->month = 12;
138                                 date->year--;
139                         } else
140                                 date->month--;
141                         date->day += days_in_month (date->month, date->year);
142                 }
143         } else {
144                 while (date->day > days_in_month (date->month, date->year)) {
145                         date->day -= days_in_month (date->month, date->year);
146                         if (date->month == 12) {
147                                 date->month = 1;
148                                 date->year++;
149                         } else
150                                 date->month++;
151                 }
152         }
153 }
154
155 /**
156  * soup_date_new:
157  * @year: the year (1-9999)
158  * @month: the month (1-12)
159  * @day: the day of the month (1-31, as appropriate for @month)
160  * @hour: the hour (0-23)
161  * @minute: the minute (0-59)
162  * @second: the second (0-59, or up to 61 for leap seconds)
163  *
164  * Creates a #SoupDate representing the indicated time, UTC.
165  *
166  * Return value: a new #SoupDate
167  **/
168 SoupDate *
169 soup_date_new (int year, int month, int day, 
170                int hour, int minute, int second)
171 {
172         SoupDate *date = g_slice_new (SoupDate);
173
174         date->year   = year;
175         date->month  = month;
176         date->day    = day;
177         date->hour   = hour;
178         date->minute = minute;
179         date->second = second;
180         date->utc    = TRUE;
181         date->offset = 0;
182
183         return date;
184 }
185
186 /**
187  * soup_date_new_from_now:
188  * @offset_seconds: offset from current time
189  *
190  * Creates a #SoupDate representing a time @offset_seconds after the
191  * current time (or before it, if @offset_seconds is negative). If
192  * offset_seconds is 0, returns the current time.
193  *
194  * If @offset_seconds would indicate a time not expressible as a
195  * <type>time_t</type>, the return value will be clamped into range.
196  *
197  * Return value: a new #SoupDate
198  **/
199 SoupDate *
200 soup_date_new_from_now (int offset_seconds)
201 {
202         time_t now = time (NULL);
203         time_t then = now + offset_seconds;
204
205         if (sizeof (time_t) == 4) {
206                 if (offset_seconds < 0 && then > now)
207                         return soup_date_new_from_time_t (-G_MAXINT);
208                 else if (offset_seconds > 0 && then < now)
209                         return soup_date_new_from_time_t (G_MAXINT);
210         }
211         return soup_date_new_from_time_t (then);
212 }
213
214 static gboolean
215 parse_iso8601_date (SoupDate *date, const char *date_string)
216 {
217         gulong val;
218
219         if (strlen (date_string) < 15)
220                 return FALSE;
221         if (date_string[4] == '-' &&
222             date_string[7] == '-' &&
223             date_string[10] == 'T') {
224                 /* YYYY-MM-DD */
225                 date->year  = atoi (date_string);
226                 date->month = atoi (date_string + 5);
227                 date->day   = atoi (date_string + 8);
228                 date_string += 11;
229         } else if (date_string[8] == 'T') {
230                 /* YYYYMMDD */
231                 val = atoi (date_string);
232                 date->year = val / 10000;
233                 date->month = (val % 10000) / 100;
234                 date->day = val % 100;
235                 date_string += 9;
236         } else
237                 return FALSE;
238
239         if (strlen (date_string) >= 8 &&
240             date_string[2] == ':' && date_string[5] == ':') {
241                 /* HH:MM:SS */
242                 date->hour   = atoi (date_string);
243                 date->minute = atoi (date_string + 3);
244                 date->second = atoi (date_string + 6);
245                 date_string += 8;
246         } else if (strlen (date_string) >= 6) {
247                 /* HHMMSS */
248                 val = strtoul (date_string, (char **)&date_string, 10);
249                 date->hour   = val / 10000;
250                 date->minute = (val % 10000) / 100;
251                 date->second = val % 100;
252         } else
253                 return FALSE;
254
255         if (*date_string == '.' || *date_string == ',')
256                 (void) strtoul (date_string + 1, (char **)&date_string, 10);
257
258         if (*date_string == 'Z') {
259                 date_string++;
260                 date->utc = TRUE;
261                 date->offset = 0;
262         } else if (*date_string == '+' || *date_string == '-') {
263                 int sign = (*date_string == '+') ? -1 : 1;
264                 val = strtoul (date_string + 1, (char **)&date_string, 10);
265                 if (*date_string == ':')
266                         val = 60 * val + strtoul (date_string + 1, (char **)&date_string, 10);
267                 else
268                         val = 60 * (val / 100) + (val % 100);
269                 date->offset = sign * val;
270                 date->utc = !val;
271         } else {
272                 date->offset = 0;
273                 date->utc = FALSE;
274         }
275
276         return !*date_string;
277 }
278
279 static inline gboolean
280 parse_day (SoupDate *date, const char **date_string)
281 {
282         char *end;
283
284         date->day = strtoul (*date_string, &end, 10);
285         if (end == (char *)*date_string)
286                 return FALSE;
287
288         while (*end == ' ' || *end == '-')
289                 end++;
290         *date_string = end;
291         return TRUE;
292 }
293
294 static inline gboolean
295 parse_month (SoupDate *date, const char **date_string)
296 {
297         int i;
298
299         for (i = 0; i < G_N_ELEMENTS (months); i++) {
300                 if (!g_ascii_strncasecmp (*date_string, months[i], 3)) {
301                         date->month = i + 1;
302                         *date_string += 3;
303                         while (**date_string == ' ' || **date_string == '-')
304                                 (*date_string)++;
305                         return TRUE;
306                 }
307         }
308         return FALSE;
309 }
310
311 static inline gboolean
312 parse_year (SoupDate *date, const char **date_string)
313 {
314         char *end;
315
316         date->year = strtoul (*date_string, &end, 10);
317         if (end == (char *)*date_string)
318                 return FALSE;
319
320         if (end == (char *)*date_string + 2) {
321                 if (date->year < 70)
322                         date->year += 2000;
323                 else
324                         date->year += 1900;
325         } else if (end == (char *)*date_string + 3)
326                 date->year += 1900;
327
328         while (*end == ' ' || *end == '-')
329                 end++;
330         *date_string = end;
331         return TRUE;
332 }
333
334 static inline gboolean
335 parse_time (SoupDate *date, const char **date_string)
336 {
337         char *p, *end;
338
339         date->hour = strtoul (*date_string, &end, 10);
340         if (end == (char *)*date_string || *end++ != ':')
341                 return FALSE;
342         p = end;
343         date->minute = strtoul (p, &end, 10);
344         if (end == p || *end++ != ':')
345                 return FALSE;
346         p = end;
347         date->second = strtoul (p, &end, 10);
348         if (end == p)
349                 return FALSE;
350         p = end;
351
352         while (*p == ' ')
353                 p++;
354         *date_string = p;
355         return TRUE;
356 }
357
358 static inline gboolean
359 parse_timezone (SoupDate *date, const char **date_string)
360 {
361         if (!**date_string) {
362                 date->utc = FALSE;
363                 date->offset = 0;
364         } else if (**date_string == '+' || **date_string == '-') {
365                 gulong val;
366                 int sign = (**date_string == '+') ? -1 : 1;
367                 val = strtoul (*date_string + 1, (char **)date_string, 10);
368                 if (**date_string == ':')
369                         val = 60 * val + strtoul (*date_string + 1, (char **)date_string, 10);
370                 else
371                         val =  60 * (val / 100) + (val % 100);
372                 date->offset = sign * val;
373                 date->utc = (sign == -1) && !val;
374         } else if (**date_string == 'Z') {
375                 date->offset = 0;
376                 date->utc = TRUE;
377                 (*date_string)++;
378         } else if (!strcmp (*date_string, "GMT") ||
379                    !strcmp (*date_string, "UTC")) {
380                 date->offset = 0;
381                 date->utc = TRUE;
382                 (*date_string) += 3;
383         } else if (strchr ("ECMP", **date_string) &&
384                    ((*date_string)[1] == 'D' || (*date_string)[1] == 'S') &&
385                    (*date_string)[2] == 'T') {
386                 date->offset = -60 * (5 * strcspn ("ECMP", *date_string));
387                 if ((*date_string)[1] == 'D')
388                         date->offset += 60;
389                 date->utc = FALSE;
390         } else
391                 return FALSE;
392         return TRUE;
393 }
394
395 static gboolean
396 parse_textual_date (SoupDate *date, const char *date_string)
397 {
398         /* If it starts with a word, it must be a weekday, which we skip */
399         if (g_ascii_isalpha (*date_string)) {
400                 while (g_ascii_isalpha (*date_string))
401                         date_string++;
402                 if (*date_string == ',')
403                         date_string++;
404                 while (g_ascii_isspace (*date_string))
405                         date_string++;
406         }
407
408         /* If there's now another word, this must be an asctime-date */
409         if (g_ascii_isalpha (*date_string)) {
410                 /* (Sun) Nov  6 08:49:37 1994 */
411                 if (!parse_month (date, &date_string) ||
412                     !parse_day (date, &date_string) ||
413                     !parse_time (date, &date_string) ||
414                     !parse_year (date, &date_string))
415                         return FALSE;
416
417                 /* There shouldn't be a timezone, but check anyway */
418                 parse_timezone (date, &date_string);
419         } else {
420                 /* Non-asctime date, so some variation of
421                  * (Sun,) 06 Nov 1994 08:49:37 GMT
422                  */
423                 if (!parse_day (date, &date_string) ||
424                     !parse_month (date, &date_string) ||
425                     !parse_year (date, &date_string) ||
426                     !parse_time (date, &date_string))
427                         return FALSE;
428
429                 /* This time there *should* be a timezone, but we
430                  * survive if there isn't.
431                  */
432                 parse_timezone (date, &date_string);
433         }
434         return TRUE;
435 }
436
437 /**
438  * SoupDateFormat:
439  * @SOUP_DATE_HTTP: RFC 1123 format, used by the HTTP "Date" header. Eg
440  * "Sun, 06 Nov 1994 08:49:37 GMT"
441  * @SOUP_DATE_COOKIE: The format for the "Expires" timestamp in the
442  * Netscape cookie specification. Eg, "Sun, 06-Nov-1994 08:49:37 GMT".
443  * @SOUP_DATE_RFC2822: RFC 2822 format, eg "Sun, 6 Nov 1994 09:49:37 -0100"
444  * @SOUP_DATE_ISO8601_COMPACT: ISO 8601 date/time with no optional
445  * punctuation. Eg, "19941106T094937-0100".
446  * @SOUP_DATE_ISO8601_FULL: ISO 8601 date/time with all optional
447  * punctuation. Eg, "1994-11-06T09:49:37-01:00".
448  * @SOUP_DATE_ISO8601_XMLRPC: ISO 8601 date/time as used by XML-RPC.
449  * Eg, "19941106T09:49:37".
450  * @SOUP_DATE_ISO8601: An alias for @SOUP_DATE_ISO8601_FULL.
451  *
452  * Date formats that soup_date_to_string() can use.
453  *
454  * @SOUP_DATE_HTTP and @SOUP_DATE_COOKIE always coerce the time to
455  * UTC. @SOUP_DATE_ISO8601_XMLRPC uses the time as given, ignoring the
456  * offset completely. @SOUP_DATE_RFC2822 and the other ISO 8601
457  * variants use the local time, appending the offset information if
458  * available.
459  *
460  * This enum may be extended with more values in future releases.
461  **/
462
463 /**
464  * soup_date_new_from_string:
465  * @date_string: the date in some plausible format
466  *
467  * Parses @date_string and tries to extract a date from it. This
468  * recognizes all of the "HTTP-date" formats from RFC 2616, all ISO
469  * 8601 formats containing both a time and a date, RFC 2822 dates,
470  * and reasonable approximations thereof. (Eg, it is lenient about
471  * whitespace, leading "0"s, etc.)
472  *
473  * Return value: a new #SoupDate, or %NULL if @date_string could not
474  * be parsed.
475  **/
476 SoupDate *
477 soup_date_new_from_string (const char *date_string)
478 {
479         SoupDate *date;
480         gboolean success;
481
482         g_return_val_if_fail (date_string != NULL, NULL);
483
484         date = g_slice_new (SoupDate);
485
486         while (g_ascii_isspace (*date_string))
487                 date_string++;
488
489         /* If it starts with a digit, it's either an ISO 8601 date, or
490          * an RFC2822 date without the optional weekday; in the later
491          * case, there will be a month name later on, so look for one
492          * of the month-start letters.
493          */
494         if (g_ascii_isdigit (*date_string) &&
495             !strpbrk (date_string, "JFMASOND"))
496                 success = parse_iso8601_date (date, date_string);
497         else
498                 success = parse_textual_date (date, date_string);
499
500         if (!success) {
501                 g_slice_free (SoupDate, date);
502                 return NULL;
503         }
504
505         if (date->year < 1 || date->year > 9999 ||
506             date->month < 1 || date->month > 12 ||
507             date->day < 1 ||
508             date->day > days_in_month (date->month, date->year) ||
509             date->hour < 0 || date->hour > 24 ||
510             date->minute < 0 || date->minute > 59 ||
511             date->second < 0 || date->second > 61) {
512                 soup_date_free (date);
513                 return NULL;
514         }
515         if (date->hour == 24) {
516                 /* ISO8601 allows this explicitly. We allow it for
517                  * other types as well just for simplicity.
518                  */
519                 if (date->minute == 0 && date->second == 0)
520                         soup_date_fixup (date);
521                 else {
522                         soup_date_free (date);
523                         return NULL;
524                 }
525         }
526
527         return date;
528 }
529
530 /**
531  * soup_date_new_from_time_t:
532  * @when: a <type>time_t</type>
533  *
534  * Creates a #SoupDate corresponding to @when
535  *
536  * Return value: a new #SoupDate
537  **/
538 SoupDate *
539 soup_date_new_from_time_t (time_t when)
540 {
541         struct tm tm;
542
543 #ifdef HAVE_GMTIME_R
544         gmtime_r (&when, &tm);
545 #else
546         tm = *gmtime (&when);
547 #endif
548
549         return soup_date_new (tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
550                               tm.tm_hour, tm.tm_min, tm.tm_sec);
551 }
552
553 static const char *
554 soup_date_weekday (SoupDate *date)
555 {
556         /* Proleptic Gregorian 0001-01-01 was a Monday, which
557          * corresponds to 1 in the days[] array.
558          */
559         return days[rata_die_day (date) % 7];
560 }
561
562 /**
563  * soup_date_to_string:
564  * @date: a #SoupDate
565  * @format: the format to generate the date in
566  *
567  * Converts @date to a string in the format described by @format.
568  *
569  * Return value: @date as a string
570  **/
571 char *
572 soup_date_to_string (SoupDate *date, SoupDateFormat format)
573 {
574         g_return_val_if_fail (date != NULL, NULL);
575
576         if (format == SOUP_DATE_HTTP || format == SOUP_DATE_COOKIE) {
577                 /* HTTP and COOKIE formats require UTC timestamp, so coerce
578                  * @date if it's non-UTC.
579                  */
580                 SoupDate utcdate;
581
582                 if (date->offset != 0) {
583                         memcpy (&utcdate, date, sizeof (SoupDate));
584                         utcdate.minute += utcdate.offset;
585                         utcdate.offset = 0;
586                         utcdate.utc = TRUE;
587                         soup_date_fixup (&utcdate);
588                         date = &utcdate;
589                 }
590
591                 switch (format) {
592                 case SOUP_DATE_HTTP:
593                         /* "Sun, 06 Nov 1994 08:49:37 GMT" */
594                         return g_strdup_printf (
595                                 "%s, %02d %s %04d %02d:%02d:%02d GMT",
596                                 soup_date_weekday (date), date->day,
597                                 months[date->month - 1], date->year,
598                                 date->hour, date->minute, date->second);
599
600                 case SOUP_DATE_COOKIE:
601                         /* "Sun, 06-Nov-1994 08:49:37 GMT" */
602                         return g_strdup_printf (
603                                 "%s, %02d-%s-%04d %02d:%02d:%02d GMT",
604                                 soup_date_weekday (date), date->day,
605                                 months[date->month - 1], date->year,
606                                 date->hour, date->minute, date->second);
607
608                 default:
609                         g_return_val_if_reached (NULL);
610                 }
611         } else if (format == SOUP_DATE_ISO8601_XMLRPC) {
612                 /* Always "floating", ignore offset */
613                 return g_strdup_printf ("%04d%02d%02dT%02d:%02d:%02d",
614                                         date->year, date->month, date->day,
615                                         date->hour, date->minute, date->second);
616         } else {
617                 int hour_offset, minute_offset;
618                 char zone[8], sign;
619
620                 /* For other ISO8601 formats or RFC2822, use the
621                  * offset given in @date. For ISO8601 formats, use "Z"
622                  * for UTC, +-offset for non-UTC, and nothing for
623                  * floating. For RFC2822, use +-offset for UTC or
624                  * non-UTC, and -0000 for floating.
625                  */
626                 hour_offset = abs (date->offset) / 60;
627                 minute_offset = abs (date->offset) - hour_offset * 60;
628
629                 switch (format) {
630                 case SOUP_DATE_ISO8601_COMPACT:
631                         /* "19941106T084937[zone]" */
632                         if (date->utc)
633                                 strcpy (zone, "Z");
634                         else if (date->offset) {
635                                 g_snprintf (zone, sizeof (zone), "%c%02d%02d",
636                                             date->offset > 0 ? '-' : '+',
637                                             hour_offset, minute_offset);
638                         } else
639                                 *zone = '\0';                   
640
641                         return g_strdup_printf (
642                                 "%04d%02d%02dT%02d%02d%02d%s",
643                                 date->year, date->month, date->day,
644                                 date->hour, date->minute, date->second,
645                                 zone);
646
647                 case SOUP_DATE_ISO8601_FULL:
648                         /* "1994-11-06T08:49:37[zone]" */
649                         if (date->utc)
650                                 strcpy (zone, "Z");
651                         else if (date->offset) {
652                                 g_snprintf (zone, sizeof (zone), "%c%02d:%02d",
653                                             date->offset > 0 ? '-' : '+',
654                                             hour_offset, minute_offset);
655                         } else
656                                 *zone = '\0';                   
657
658                         return g_strdup_printf (
659                                 "%04d-%02d-%02dT%02d:%02d:%02d%s",
660                                 date->year, date->month, date->day,
661                                 date->hour, date->minute, date->second,
662                                 zone);
663
664                 case SOUP_DATE_RFC2822:
665                         /* "Sun, 6 Nov 1994 09:49:37 -0100" */
666                         if (date->offset)
667                                 sign = (date->offset > 0) ? '-' : '+';
668                         else
669                                 sign = date->utc ? '+' : '-';
670                         return g_strdup_printf (
671                                 "%s, %d %s %04d %02d:%02d:%02d %c%02d%02d",
672                                 soup_date_weekday (date), date->day,
673                                 months[date->month - 1], date->year,
674                                 date->hour, date->minute, date->second,
675                                 sign, hour_offset, minute_offset);
676
677                 default:
678                         return NULL;
679                 }
680         }
681 }
682
683 /**
684  * soup_date_to_time_t:
685  * @date: a #SoupDate
686  *
687  * Converts @date to a <type>time_t</type>.
688  *
689  * If @date is not representable as a <type>time_t</type>, it will be
690  * clamped into range. (In particular, some HTTP cookies have
691  * expiration dates after "Y2.038k" (2038-01-19T03:14:07Z).)
692  *
693  * Return value: @date as a <type>time_t</type>
694  **/
695 time_t
696 soup_date_to_time_t (SoupDate *date)
697 {
698         time_t tt;
699         GTimeVal val;
700
701         g_return_val_if_fail (date != NULL, 0);
702
703         /* FIXME: offset, etc */
704
705         if (date->year < 1970)
706                 return 0;
707
708         /* If the year is later than 2038, we're guaranteed to
709          * overflow a 32-bit time_t. (If it's exactly 2038, we'll
710          * *probably* overflow, but only by a little, and it's easiest
711          * to test that at the end by seeing if the result has turned
712          * negative.)
713          */
714         if (sizeof (time_t) == 4 && date->year > 2038)
715                 return (time_t)0x7fffffff;
716
717         soup_date_to_timeval (date, &val);
718         tt = val.tv_sec;
719
720         if (sizeof (time_t) == 4 && tt < 0)
721                 return (time_t)0x7fffffff;
722         return tt;
723 }
724
725 /**
726  * soup_date_to_timeval:
727  * @date: a #SoupDate
728  * @time: (out): a #GTimeVal structure in which to store the converted time.
729  *
730  * Converts @date to a #GTimeVal.
731  *
732  * Since: 2.24
733  */
734 void
735 soup_date_to_timeval (SoupDate *date, GTimeVal *time)
736 {
737         g_return_if_fail (date != NULL);
738         g_return_if_fail (time != NULL);
739
740         /* FIXME: offset, etc */
741
742         time->tv_sec = rata_die_day (date) - TIME_T_EPOCH_RATA_DIE_DAY;
743         time->tv_sec = ((((time->tv_sec * 24) + date->hour) * 60) + date->minute) * 60 + date->second;
744         time->tv_usec = 0;
745 }
746
747 #if ENABLE(TIZEN_TV_ADJUST_TIME)
748 /**
749  * soup_date_set_timeOffset:
750  * @date: a #SoupDate
751  *
752  * set time offset
753  *
754  * Return value: None
755  *
756  * Since: 2013.Aug, (porting from Orsay2014)
757  **/
758 double soupTimeOffset = 0;
759 void
760 soup_date_set_timeOffset (double timeOffset)
761 {
762     time_t timer;
763
764     timer = time (NULL);
765     TIZEN_LOGI("soup date set time offset is [%f], TV board time is [%ld]", timeOffset, timer);
766     TIZEN_LOGI("TV borad time is: %s",ctime(&timer));
767     timer = timer + timeOffset/1000;
768     TIZEN_LOGI("after off set time is: %s",ctime(&timer));
769
770     soupTimeOffset = timeOffset;
771 }
772 #endif
773
774 /**
775  * soup_date_is_past:
776  * @date: a #SoupDate
777  *
778  * Determines if @date is in the past.
779  *
780  * Return value: %TRUE if @date is in the past
781  *
782  * Since: 2.24
783  **/
784 gboolean
785 soup_date_is_past (SoupDate *date)
786 {
787         g_return_val_if_fail (date != NULL, TRUE);
788
789         /* optimization */
790         if (date->year < 2010)
791                 return TRUE;
792 #if ENABLE(TIZEN_TV_ADJUST_TIME)
793         return soup_date_to_time_t (date) < time (NULL) + (int)(soupTimeOffset / 1000);
794 #else
795         return soup_date_to_time_t (date) < time (NULL);
796 #endif
797 }
798
799 /**
800  * soup_date_get_year:
801  * @date: a #SoupDate
802  *
803  * Gets @date's year.
804  *
805  * Return value: @date's year
806  *
807  * Since: 2.32
808  **/
809 int
810 soup_date_get_year (SoupDate *date)
811 {
812         return date->year;
813 }
814
815 /**
816  * soup_date_get_month:
817  * @date: a #SoupDate
818  *
819  * Gets @date's month.
820  *
821  * Return value: @date's month
822  *
823  * Since: 2.32
824  **/
825 int
826 soup_date_get_month (SoupDate *date)
827 {
828         return date->month;
829 }
830
831 /**
832  * soup_date_get_day:
833  * @date: a #SoupDate
834  *
835  * Gets @date's day.
836  *
837  * Return value: @date's day
838  *
839  * Since: 2.32
840  **/
841 int
842 soup_date_get_day (SoupDate *date)
843 {
844         return date->day;
845 }
846
847 /**
848  * soup_date_get_hour:
849  * @date: a #SoupDate
850  *
851  * Gets @date's hour.
852  *
853  * Return value: @date's hour
854  *
855  * Since: 2.32
856  **/
857 int
858 soup_date_get_hour (SoupDate *date)
859 {
860         return date->hour;
861 }
862
863 /**
864  * soup_date_get_minute:
865  * @date: a #SoupDate
866  *
867  * Gets @date's minute.
868  *
869  * Return value: @date's minute
870  *
871  * Since: 2.32
872  **/
873 int
874 soup_date_get_minute (SoupDate *date)
875 {
876         return date->minute;
877 }
878
879 /**
880  * soup_date_get_second:
881  * @date: a #SoupDate
882  *
883  * Gets @date's second.
884  *
885  * Return value: @date's second
886  *
887  * Since: 2.32
888  **/
889 int
890 soup_date_get_second (SoupDate *date)
891 {
892         return date->second;
893 }
894
895 /**
896  * soup_date_get_utc:
897  * @date: a #SoupDate
898  *
899  * Gets @date's UTC flag
900  *
901  * Return value: %TRUE if @date is UTC.
902  *
903  * Since: 2.32
904  **/
905 gboolean
906 soup_date_get_utc (SoupDate *date)
907 {
908         return date->utc;
909 }
910
911 /**
912  * soup_date_get_offset:
913  * @date: a #SoupDate
914  *
915  * Gets @date's offset from UTC.
916  *
917  * Return value: @date's offset from UTC. If soup_date_get_utc()
918  * returns %FALSE but soup_date_get_offset() returns 0, that means the
919  * date is a "floating" time with no associated offset information.
920  *
921  * Since: 2.32
922  **/
923 int
924 soup_date_get_offset (SoupDate *date)
925 {
926         return date->offset;
927 }
928
929 /**
930  * soup_date_copy:
931  * @date: a #SoupDate
932  *
933  * Copies @date.
934  *
935  * Since: 2.24
936  **/
937 SoupDate *
938 soup_date_copy (SoupDate *date)
939 {
940         SoupDate *copy;
941
942         g_return_val_if_fail (date != NULL, NULL);
943
944         copy = g_slice_new (SoupDate);
945         memcpy (copy, date, sizeof (SoupDate));
946         return copy;
947 }
948
949 /**
950  * soup_date_free:
951  * @date: a #SoupDate
952  *
953  * Frees @date.
954  *
955  * Since: 2.24
956  **/
957 void
958 soup_date_free (SoupDate *date)
959 {
960         g_return_if_fail (date != NULL);
961
962         g_slice_free (SoupDate, date);
963 }