strip added smb:// shares of their user/pass when adding, and instead store that...
[vuplus_xbmc] / lib / cmyth / libcmyth / timestamp.c
1 /*
2  *  Copyright (C) 2004-2006, Eric Lund
3  *  http://www.mvpmc.org/
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 /*
21  * timestamp.c - functions to manage MythTV timestamps.  Primarily,
22  *               these allocate timestamps and convert between string
23  *               and cmyth_timestamp_t and between time_t and
24  *               cmyth_timestamp_t.
25  */
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #ifndef _MSC_VER
29 #include <unistd.h>
30 #endif
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <cmyth_local.h>
36 #include <time.h>
37
38
39 /*
40  * cmyth_timestamp_create(void)
41  * 
42  * Scope: PUBLIC
43  *
44  * Description
45  *
46  * Create a timestamp structure and return a pointer to the structure.
47  *
48  * Return Value:
49  *
50  * Success: A non-NULL cmyth_timestamp_t (this type is a pointer)
51  *
52  * Failure: A NULL cmyth_timestamp_t
53  */
54 cmyth_timestamp_t
55 cmyth_timestamp_create(void)
56 {
57         cmyth_timestamp_t ret = ref_alloc(sizeof(*ret));
58
59         cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
60         if (!ret) {
61                 return(NULL);
62         }
63         ret->timestamp_year = 0;
64         ret->timestamp_month = 0;
65         ret->timestamp_day = 0;
66         ret->timestamp_hour = 0;
67         ret->timestamp_minute = 0;
68         ret->timestamp_second = 0;
69         ret->timestamp_isdst = 0;
70         return ret;
71 }
72
73 /*
74  * cmyth_timestamp_from_string(char *str)
75  * 
76  * Scope: PUBLIC
77  *
78  * Description
79  *
80  * Create and fill out a timestamp structure using the string 'str'.
81  * The string must be a timestamp of the forn:
82  *
83  *    yyyy-mm-ddThh:mm:ss
84  *
85  * Return Value:
86  *
87  * Success: A timestamp structure (this is a pointer type)
88  *
89  * Failure: NULL
90  */
91 cmyth_timestamp_t
92 cmyth_timestamp_from_string(char *str)
93 {
94         cmyth_timestamp_t ret;
95         unsigned int i;
96         int datetime = 1;
97         char *yyyy = &str[0];
98         char *MM = &str[5];
99         char *dd = &str[8];
100         char *hh = &str[11];
101         char *mm = &str[14];
102         char *ss = &str[17];
103         
104         if (!str) {
105                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL string\n", __FUNCTION__);
106                 return NULL;
107         }
108
109         ret = cmyth_timestamp_create();
110         if (!ret) {
111                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp\n",
112                           __FUNCTION__);
113                 return NULL;
114         }
115         if (strlen(str) != CMYTH_TIMESTAMP_LEN) {
116                 datetime = 0;
117                 if (strlen(str) != CMYTH_DATESTAMP_LEN) {
118                         cmyth_dbg(CMYTH_DBG_ERROR,
119                                   "%s: string is not a timestamp '%s'\n",
120                                   __FUNCTION__, str);
121                         goto err;
122                 }
123         }
124
125         if ((datetime == 1) &&
126             ((str[4] != '-') || (str[7] != '-') || (str[10] != 'T') ||
127              (str[13] != ':') || (str[16] != ':'))) {
128                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: string is badly formed '%s'\n",
129                           __FUNCTION__, str);
130                 goto err;
131         }
132         if ((datetime == 0) &&
133             ((str[4] != '-') || (str[7] != '-'))) {
134                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: string is badly formed '%s'\n",
135                           __FUNCTION__, str);
136                 goto err;
137         }
138
139         str[4] = '\0';
140         str[7] = '\0';
141         if (datetime) {
142                 str[10] = '\0';
143                 str[13] = '\0';
144                 str[16] = '\0';
145         }
146         for (i = 0;
147              i < (datetime ? CMYTH_TIMESTAMP_LEN : CMYTH_DATESTAMP_LEN);
148              ++i) {
149                 if (str[i] && !isdigit(str[i])) {
150                         cmyth_dbg(CMYTH_DBG_ERROR,
151                                   "%s: expected numeral at '%s'[%d]\n",
152                                   __FUNCTION__, str, i);
153                         goto err;
154                 }
155         }
156         ret->timestamp_year = atoi(yyyy);
157         ret->timestamp_month = atoi(MM);
158         if (ret->timestamp_month > 12) {
159                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: month value too big'%s'\n",
160                           __FUNCTION__, str);
161                 goto err;
162         }
163         ret->timestamp_day = atoi(dd);
164         if (ret->timestamp_day > 31) {
165                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: day value too big'%s'\n",
166                           __FUNCTION__, str);
167                 goto err;
168         }
169
170         if (datetime == 0)
171                 return ret;
172
173         ret->timestamp_hour = atoi(hh);
174         if (ret->timestamp_hour > 23) {
175                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: hour value too big'%s'\n",
176                           __FUNCTION__, str);
177                 goto err;
178         }
179         ret->timestamp_minute = atoi(mm);
180         if (ret->timestamp_minute > 59) {
181                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: minute value too big'%s'\n",
182                           __FUNCTION__, str);
183                 goto err;
184         }
185         ret->timestamp_second = atoi(ss);
186         if (ret->timestamp_second > 59) {
187                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: second value too big'%s'\n",
188                           __FUNCTION__, str);
189                 goto err;
190         }
191         return ret;
192
193     err:
194         ref_release(ret);
195         return NULL;
196 }
197
198 cmyth_timestamp_t
199 cmyth_timestamp_from_tm(struct tm * tm_datetime)
200 {
201         cmyth_timestamp_t ret;
202         ret = cmyth_timestamp_create();
203         if (!ret) {
204                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp\n",
205                           __FUNCTION__);
206                 return NULL;
207         }
208
209         ret->timestamp_year = tm_datetime->tm_year + 1900;
210         ret->timestamp_month = tm_datetime->tm_mon + 1;
211         ret->timestamp_day = tm_datetime->tm_mday;
212         ret->timestamp_hour = tm_datetime->tm_hour;
213         ret->timestamp_minute = tm_datetime->tm_min;
214         ret->timestamp_second = tm_datetime->tm_sec;
215         ret->timestamp_isdst = tm_datetime->tm_isdst;
216         return ret;
217 }
218
219 /*
220  * cmyth_timestamp_from_unixtime(time_t l)
221  * 
222  * Scope: PUBLIC
223  *
224  * Description
225  *
226  * Create and fill out a timestamp structure using the time_t 'l'.
227  *
228  * Return Value:
229  *
230  * Success: cmyth_timestamp_t object
231  *
232  * Failure: -(ERRNO)
233  */
234 cmyth_timestamp_t
235 cmyth_timestamp_from_unixtime(time_t l)
236 {
237         struct tm tm_datetime;
238         localtime_r(&l,&tm_datetime);
239         return cmyth_timestamp_from_tm(&tm_datetime);
240 }
241
242
243 /*
244  * cmyth_timestamp_to_longlong( cmyth_timestamp_t ts)
245  * 
246  * Scope: PUBLIC
247  *
248  * Description
249  *
250  * Create a time_t value from the timestamp structure 'ts' and
251  * return the result.
252  * 
253  *
254  * Return Value:
255  *
256  * Success: time_t value > 0 (seconds from January 1, 1970)
257  *
258  * Failure: (time_t) -1
259  */
260 time_t
261 cmyth_timestamp_to_unixtime(cmyth_timestamp_t ts)
262 {
263     struct tm tm;
264     tm.tm_sec = ts->timestamp_second;
265     tm.tm_min = ts->timestamp_minute;
266     tm.tm_hour = ts->timestamp_hour;
267     tm.tm_mday = ts->timestamp_day;
268     tm.tm_mon = ts->timestamp_month-1;
269     tm.tm_year = ts->timestamp_year-1900;
270     tm.tm_isdst = ts->timestamp_isdst;
271     return mktime(&tm);
272 }
273
274 /*
275  * cmyth_timestamp_to_string(char *str, cmyth_timestamp_t ts)
276  * 
277  * Scope: PUBLIC
278  *
279  * Description
280  *
281  * Create a string from the timestamp structure 'ts' and put it in the
282  * user supplied buffer 'str'.  The size of 'str' must be
283  * CMYTH_TIMESTAMP_LEN + 1 or this will overwrite beyond 'str'.
284  * 
285  *
286  * Return Value:
287  *
288  * Success: 0
289  *
290  * Failure: -(ERRNO)
291  */
292 int
293 cmyth_timestamp_to_string(char *str, cmyth_timestamp_t ts)
294 {
295         if (!str) {
296                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL output string provided\n",
297                           __FUNCTION__);
298                 return -EINVAL;
299         }
300         if (!ts) {
301                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp provided\n",
302                           __FUNCTION__);
303                 return -EINVAL;
304         }
305         sprintf(str,
306                 "%4.4ld-%2.2ld-%2.2ldT%2.2ld:%2.2ld:%2.2ld",
307                 ts->timestamp_year,
308                 ts->timestamp_month,
309                 ts->timestamp_day,
310                 ts->timestamp_hour,
311                 ts->timestamp_minute,
312                 ts->timestamp_second);
313         return 0;
314 }
315
316 /*
317  * cmyth_timestamp_to_isostring(char *str, cmyth_timestamp_t ts)
318  * 
319  * Scope: PUBLIC
320  *
321  * Description
322  *
323  * Create a string from the timestamp structure 'ts' and put it in the
324  * user supplied buffer 'str'.  The size of 'str' must be
325  * CMYTH_TIMESTAMP_LEN + 1 or this will overwrite beyond 'str'.
326  * 
327  *
328  * Return Value:
329  *
330  * Success: 0
331  *
332  * Failure: -(ERRNO)
333  */
334 int
335 cmyth_timestamp_to_isostring(char *str, cmyth_timestamp_t ts)
336 {
337         if (!str) {
338                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL output string provided\n",
339                           __FUNCTION__);
340                 return -EINVAL;
341         }
342         if (!ts) {
343                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp provided\n",
344                           __FUNCTION__);
345                 return -EINVAL;
346         }
347         sprintf(str,
348                 "%4.4ld-%2.2ld-%2.2ld",
349                 ts->timestamp_year,
350                 ts->timestamp_month,
351                 ts->timestamp_day);
352         return 0;
353 }
354
355 int
356 cmyth_timestamp_to_display_string(char *str, cmyth_timestamp_t ts,
357                                                                                                                                         int time_format_12)
358 {
359         if (!str) {
360                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL output string provided\n",
361                           __FUNCTION__);
362                 return -EINVAL;
363         }
364         if (!ts) {
365                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp provided\n",
366                           __FUNCTION__);
367                 return -EINVAL;
368         }
369         if (time_format_12)
370         {
371                 unsigned long hour = ts->timestamp_hour;
372                 int pm = 0;
373                 if (hour > 11)
374                 {
375                         pm = 1;
376                         hour -= 12;
377                 }
378                 if (hour == 0)
379                         hour = 12;
380
381                 sprintf(str,
382                         "%4.4ld-%2.2ld-%2.2ldT%2.2ld:%2.2ld:%2.2ld %s",
383                         ts->timestamp_year,
384                         ts->timestamp_month,
385                         ts->timestamp_day,
386                         hour,
387                         ts->timestamp_minute,
388                         ts->timestamp_second,
389                         pm ? "PM" : "AM");
390         }
391         else
392         {
393                 sprintf(str,
394                         "%4.4ld-%2.2ld-%2.2ldT%2.2ld:%2.2ld:%2.2ld",
395                         ts->timestamp_year,
396                         ts->timestamp_month,
397                         ts->timestamp_day,
398                         ts->timestamp_hour,
399                         ts->timestamp_minute,
400                         ts->timestamp_second);
401         }
402         return 0;
403 }
404
405 /*
406  * cmyth_datetime_to_string(char *str, cmyth_timestamp_t ts)
407  * 
408  * Scope: PUBLIC
409  *
410  * Description
411  *
412  * Create a string from the timestamp structure 'ts' and put it in the
413  * user supplied buffer 'str'.  The size of 'str' must be
414  * CMYTH_DATETIME_LEN + 1 or this will overwrite beyond 'str'.
415  * 
416  *
417  * Return Value:
418  *
419  * Success: 0
420  *
421  * Failure: -(ERRNO)
422  */
423 int
424 cmyth_datetime_to_string(char *str, cmyth_timestamp_t ts)
425 {
426         struct tm tm_datetime;
427         time_t t_datetime;
428
429         if (!str) {
430                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL output string provided\n",
431                           __FUNCTION__);
432                 return -EINVAL;
433         }
434         if (!ts) {
435                 cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL timestamp provided\n",
436                           __FUNCTION__);
437                 return -EINVAL;
438         }
439
440         memset(&tm_datetime, 0, sizeof(tm_datetime));
441         tm_datetime.tm_year = ts->timestamp_year - 1900;
442         tm_datetime.tm_mon = ts->timestamp_month - 1;
443         tm_datetime.tm_mday = ts->timestamp_day;
444         tm_datetime.tm_hour = ts->timestamp_hour;
445         tm_datetime.tm_min = ts->timestamp_minute;
446         tm_datetime.tm_sec = ts->timestamp_second;
447         tm_datetime.tm_isdst = ts->timestamp_isdst;
448         t_datetime = mktime(&tm_datetime);
449         sprintf(str,
450                 "%4.4ld-%2.2ld-%2.2ldT%2.2ld:%2.2ld:%2.2ld",
451                 ts->timestamp_year,
452                 ts->timestamp_month,
453                 ts->timestamp_day,
454                 ts->timestamp_hour,
455                 ts->timestamp_minute,
456                 ts->timestamp_second);
457         cmyth_dbg(CMYTH_DBG_ERROR, "original timestamp string: %s \n",str);
458         sprintf(str,"%lu",(unsigned long) t_datetime);
459         cmyth_dbg(CMYTH_DBG_ERROR, "time in seconds: %s \n",str);
460         
461         return 0;
462 }
463
464
465
466 /*
467  * cmyth_timestamp_compare(cmyth_timestamp_t ts1, cmyth_timestamp_t ts2)
468  * 
469  * Scope: PUBLIC
470  *
471  * Description
472  *
473  * Compare ts1 to ts2 and indicate whether ts1 is less than, equal to
474  * or greater than ts1.
475  * 
476  *
477  * Return Value:
478  *
479  * -1: ts1 is less than (erlier than) ts2
480  *  0: ts1 is the same as ts2
481  *  1: ts1 is greater than (later than) ts2
482  */
483 int
484 cmyth_timestamp_compare(cmyth_timestamp_t ts1, cmyth_timestamp_t ts2)
485 {
486         /*
487          * If either timestamp is NULL it is 'less than' the non-NULL one
488          * (this is a stretch, but it shouldn't happen).  If they are both
489          * NULL, they are equal.
490          */
491         if (!ts1) {
492                 if (!ts2) {
493                         return 0;
494                 }
495                 return -1;
496         }
497         if (!ts2) {
498                 return 1;
499         }
500         if (ts1->timestamp_year != ts2->timestamp_year) {
501                 return (ts1->timestamp_year > ts2->timestamp_year) ? 1 : -1;
502         }
503         if (ts1->timestamp_month != ts2->timestamp_month) {
504                 return (ts1->timestamp_month > ts2->timestamp_month) ? 1 : -1;
505         }
506         if (ts1->timestamp_day != ts2->timestamp_day) {
507                 return (ts1->timestamp_day > ts2->timestamp_day) ? 1 : -1;
508         }
509         if (ts1->timestamp_hour != ts2->timestamp_hour) {
510                 return (ts1->timestamp_hour > ts2->timestamp_hour) ? 1 : -1;
511         }
512         if (ts1->timestamp_minute != ts2->timestamp_minute) {
513                 return (ts1->timestamp_minute > ts2->timestamp_minute) 
514                         ? 1
515                         : -1;
516         }
517         if (ts1->timestamp_second != ts2->timestamp_second) {
518                 return (ts1->timestamp_second > ts2->timestamp_second)
519                         ? 1
520                         : -1;
521         }
522         return 0;
523 }
524
525 int
526 cmyth_timestamp_diff(cmyth_timestamp_t ts1, cmyth_timestamp_t ts2)
527 {
528         struct tm tm_datetime;
529         time_t start, end;
530
531         memset(&tm_datetime, 0, sizeof(tm_datetime));
532         tm_datetime.tm_year = ts1->timestamp_year - 1900;
533         tm_datetime.tm_mon = ts1->timestamp_month - 1;
534         tm_datetime.tm_mday = ts1->timestamp_day;
535         tm_datetime.tm_hour = ts1->timestamp_hour;
536         tm_datetime.tm_min = ts1->timestamp_minute;
537         tm_datetime.tm_sec = ts1->timestamp_second;
538         tm_datetime.tm_isdst = ts1->timestamp_isdst;
539         start = mktime(&tm_datetime);
540
541         memset(&tm_datetime, 0, sizeof(tm_datetime));
542         tm_datetime.tm_year = ts2->timestamp_year - 1900;
543         tm_datetime.tm_mon = ts2->timestamp_month - 1;
544         tm_datetime.tm_mday = ts2->timestamp_day;
545         tm_datetime.tm_hour = ts2->timestamp_hour;
546         tm_datetime.tm_min = ts2->timestamp_minute;
547         tm_datetime.tm_sec = ts2->timestamp_second;
548         tm_datetime.tm_isdst = ts2->timestamp_isdst;
549         end = mktime(&tm_datetime);
550
551         return (int)(end - start);
552 }