"Initial commit to Gerrit"
[profile/ivi/libgsf.git] / gsf / gsf-timestamp.c
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * gsf-timestamp.c: 
4  *
5  * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2.1 of the GNU Lesser General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
19  * USA
20  */
21
22 #include <gsf-config.h>
23 #include <gsf/gsf-timestamp.h>
24 #include <string.h>
25 #include <time.h>
26 #include <stdio.h>
27 #ifdef G_OS_WIN32
28 #include <windows.h>
29 #endif
30
31 static void
32 timestamp_to_string (GValue const *src_value, GValue *dest_value)
33 {
34         char *str = gsf_timestamp_as_string (g_value_get_boxed (src_value));
35         g_value_set_string (dest_value, str);
36         g_free (str);
37 }
38
39 GType
40 gsf_timestamp_get_type (void)
41 {
42         static GType our_type = 0;
43
44         if (our_type == 0) {
45                 our_type = g_boxed_type_register_static ("GsfTimestamp",
46                                         (GBoxedCopyFunc)gsf_timestamp_copy,
47                                         (GBoxedFreeFunc)gsf_timestamp_free);
48                 g_value_register_transform_func (our_type, G_TYPE_STRING,
49                         &timestamp_to_string);
50         }
51         return our_type;
52 }
53
54 GsfTimestamp *
55 gsf_timestamp_new (void)
56 {
57         GsfTimestamp *res = g_new0 (GsfTimestamp, 1);
58         res->timet = -1;
59         return res;
60 }
61
62 /**
63  * gsf_timestamp_copy:
64  * @stamp: timestamp to be copied
65  *
66  * Copies a timestamp.
67  *
68  * Returns: a separate copy of @stamp.
69  */
70 GsfTimestamp *
71 gsf_timestamp_copy (GsfTimestamp const *stamp)
72 {
73         GsfTimestamp *res = gsf_timestamp_new ();
74         res->timet = stamp->timet;
75         return res;
76 }
77
78 /**
79  * gsf_timestamp_free :
80  * @stamp : timestamp to be freed
81  *
82  * Releases the memory in use for @stamp (if any).
83  **/
84 void
85 gsf_timestamp_free (GsfTimestamp *stamp)
86 {
87         g_free (stamp);
88 }
89
90 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
91 #define GMTOFF(t) ((t).tm_gmtoff)
92 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
93 #define GMTOFF(t) ((t).__tm_gmtoff)
94 #elif defined(G_OS_WIN32)
95 #define GMTOFF(t) (gmt_to_local_win32())
96 #else
97 /* FIXME: work out the offset anyway. */
98 #define GMTOFF(t) (0)
99 #endif
100
101 #ifdef G_OS_WIN32
102 static time_t gmt_to_local_win32(void)
103 {
104     TIME_ZONE_INFORMATION tzinfo;
105     DWORD dwStandardDaylight;
106     long bias;
107
108     dwStandardDaylight = GetTimeZoneInformation(&tzinfo);
109     bias = tzinfo.Bias;
110
111     if (dwStandardDaylight == TIME_ZONE_ID_STANDARD)
112         bias += tzinfo.StandardBias;
113     
114     if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT)
115         bias += tzinfo.DaylightBias;
116     
117     return (- bias * 60);
118 }
119 #endif
120
121 /**
122  * gsf_timestamp_from_string :
123  * @spec : The string to parse
124  * @stamp : #GsfTimestamp
125  *
126  * Very simple parser for time stamps.  Currently requires a format of
127  *      'YYYY-MM-DDThh:mm:ss'
128  * and does no bounds checking.
129  *
130  * Since: 1.14.12
131  *
132  * Returns: %TRUE on success
133  **/
134 int
135 gsf_timestamp_from_string (char const *spec, GsfTimestamp *stamp)
136 {
137         struct tm       tm;
138
139         memset (&tm, 0, sizeof (struct tm));
140
141         /* 'YYYY-MM-DDThh:mm:ss' */
142         if (6 == sscanf (spec, "%d-%d-%dT%d:%d:%d",
143                          &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
144                          &tm.tm_hour, &tm.tm_min, &tm.tm_sec)) {
145                 time_t t;
146
147                 tm.tm_mon--; /* 0..11 */
148
149                 /* err on the side of avoiding negatives */
150                 if (tm.tm_year >= 1900)
151                         tm.tm_year -= 1900;
152
153                 t = mktime (&tm);
154                 if (t == -1)
155                         return FALSE;
156
157                 stamp->timet = t + GMTOFF(tm);
158                 return TRUE;
159         }
160         return FALSE;
161 }
162
163 /**
164  * gsf_timestamp_parse :
165  * @spec : The string to parse
166  * @stamp : #GsfTimestamp
167  *
168  * Very simple parser for time stamps.  Currently requires a format of
169  *      'YYYY-MM-DDThh:mm:ss'
170  * and does no bounds checking.
171  *
172  * Deprecated : Use gsf_timestamp_from_string
173  *
174  * Returns: %TRUE on success
175  **/
176 int
177 gsf_timestamp_parse (char const *spec, GsfTimestamp *stamp)
178 {
179         return gsf_timestamp_from_string (spec, stamp);
180 }
181
182 /**
183  * gsf_timestamp_as_string :
184  * @stamp: timestamp to be converted.
185  *
186  * Produce a string representation (ISO 8601 format) of @stamp.
187  *
188  * Returns: a string representation of @stamp. When @stamp is %NULL, the
189  * representation is "&lt;invalid&gt;".
190  */
191 char *
192 gsf_timestamp_as_string (GsfTimestamp const *stamp)
193 {
194         time_t    t;
195         struct tm tm;
196
197         g_return_val_if_fail (stamp != NULL, g_strdup ("<invalid>"));
198
199         t = stamp->timet;       /* Use an honest time_t for gmtime_r.  */
200 #ifdef HAVE_GMTIME_R
201         gmtime_r (&t, &tm);
202 #else
203         /* -NOT- thread-safe */
204         tm = *gmtime (&t);
205 #endif
206
207
208         /* using 'YYYY-MM-DDThh:mm:ss' */
209         return g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02dZ",
210                 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
211                 tm.tm_hour, tm.tm_min, tm.tm_sec);
212 }
213
214 guint
215 gsf_timestamp_hash (GsfTimestamp const *stamp)
216 {
217         return stamp->timet;
218 }
219
220 /**
221  * gsf_timestamp_equal :
222  * @a: a timestamp
223  * @b: another timestamp
224  *
225  * Compare timestamps @a and @b.
226  *
227  * Returns: true if @a and @b represent the same point in time; false otherwise.
228  *
229  **/
230 gboolean
231 gsf_timestamp_equal (GsfTimestamp const *a, GsfTimestamp const *b)
232 {
233         return a->timet == b->timet;
234 }
235
236 void
237 gsf_value_set_timestamp (GValue *value, GsfTimestamp const *stamp)
238 {
239         g_value_set_boxed (value, stamp);
240 }
241
242 void
243 gsf_timestamp_set_time (GsfTimestamp *stamp, guint64 t)
244 {
245         stamp->timet = t;
246 }