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 <gsf/gsf.h>
25
26 #include <string.h>
27 #include <time.h>
28 #ifdef G_OS_WIN32
29 #include <windows.h>
30 #endif
31
32 static void
timestamp_to_string(GValue const * src_value,GValue * dest_value)33 timestamp_to_string (GValue const *src_value, GValue *dest_value)
34 {
35 char *str = gsf_timestamp_as_string (g_value_get_boxed (src_value));
36 g_value_set_string (dest_value, str);
37 g_free (str);
38 }
39
40 GType
gsf_timestamp_get_type(void)41 gsf_timestamp_get_type (void)
42 {
43 static GType our_type = 0;
44
45 if (our_type == 0) {
46 our_type = g_boxed_type_register_static ("GsfTimestamp",
47 (GBoxedCopyFunc)gsf_timestamp_copy,
48 (GBoxedFreeFunc)gsf_timestamp_free);
49 g_value_register_transform_func (our_type, G_TYPE_STRING,
50 ×tamp_to_string);
51 }
52 return our_type;
53 }
54
55 GsfTimestamp *
gsf_timestamp_new(void)56 gsf_timestamp_new (void)
57 {
58 GsfTimestamp *res = g_new0 (GsfTimestamp, 1);
59 res->timet = -1;
60 return res;
61 }
62
63 /**
64 * gsf_timestamp_copy:
65 * @stamp: timestamp to be copied
66 *
67 * Copies a timestamp.
68 *
69 * Returns: a separate copy of @stamp.
70 */
71 GsfTimestamp *
gsf_timestamp_copy(GsfTimestamp const * stamp)72 gsf_timestamp_copy (GsfTimestamp const *stamp)
73 {
74 GsfTimestamp *res = gsf_timestamp_new ();
75 res->timet = stamp->timet;
76 return res;
77 }
78
79 /**
80 * gsf_timestamp_free:
81 * @stamp: timestamp to be freed
82 *
83 * Releases the memory in use for @stamp (if any).
84 **/
85 void
gsf_timestamp_free(GsfTimestamp * stamp)86 gsf_timestamp_free (GsfTimestamp *stamp)
87 {
88 g_free (stamp);
89 }
90
91 /**
92 * gsf_timestamp_load_from_string:
93 * @stamp: #GsfTimestamp
94 * @spec: The string to parse
95 *
96 * Very simple parser for time stamps. Currently requires a format of
97 * 'YYYY-MM-DDThh:mm:ss'
98 * and does only rudimentary range checking
99 *
100 * Since: 1.14.24
101 *
102 * Returns: %TRUE on success
103 **/
104 int
gsf_timestamp_load_from_string(GsfTimestamp * stamp,char const * spec)105 gsf_timestamp_load_from_string (GsfTimestamp *stamp, char const *spec)
106 {
107 guint year, month, day, hour, minute;
108 float second;
109 GDateTime *dt;
110
111 /* 'YYYY-MM-DDThh:mm:ss' */
112 if (6 != sscanf (spec, "%u-%u-%uT%u:%u:%f",
113 &year, &month, &day, &hour, &minute, &second))
114 return FALSE;
115
116 /* g_date_time_new_utc documentation says: */
117 /* It not considered a programmer error for the values to this function to be out of range,*/
118 /* but in the case that they are, the function will return NULL. */
119 /* Nevertheless it seems to fail on values that are extremely out of range, see bug #702671 */
120 if (second < 0.0 || second >= 60.0)
121 return FALSE;
122 if (minute > 59 || hour > 23)
123 return FALSE;
124 if (day > 32 || month > 12 || year > 9999)
125 return FALSE;
126
127 dt = g_date_time_new_utc ((int)year, (int)month, (int)day, (int)hour, (int)minute, second);
128 if (!dt)
129 return FALSE;
130
131 stamp->timet = g_date_time_to_unix (dt);
132
133 g_date_time_unref (dt);
134 return TRUE;
135 }
136
137 /**
138 * gsf_timestamp_from_string: (skip)
139 * @spec: The string to parse
140 * @stamp: #GsfTimestamp
141 *
142 * Very simple parser for time stamps. Currently requires a format of
143 * 'YYYY-MM-DDThh:mm:ss'
144 * and does no bounds checking.
145 *
146 * Deprecated: 1.14.24, use gsf_timestamp_load_from_string
147 *
148 * Returns: %TRUE on success
149 **/
150 int
gsf_timestamp_from_string(char const * spec,GsfTimestamp * stamp)151 gsf_timestamp_from_string (char const *spec, GsfTimestamp *stamp)
152 {
153 return gsf_timestamp_load_from_string (stamp, spec);
154 }
155
156 /**
157 * gsf_timestamp_parse: (skip)
158 * @spec: The string to parse
159 * @stamp: #GsfTimestamp
160 *
161 * Very simple parser for time stamps. Currently requires a format of
162 * 'YYYY-MM-DDThh:mm:ss'
163 * and does no bounds checking.
164 *
165 * Deprecated: Use gsf_timestamp_load_from_string
166 *
167 * Returns: %TRUE on success
168 **/
169 int
gsf_timestamp_parse(char const * spec,GsfTimestamp * stamp)170 gsf_timestamp_parse (char const *spec, GsfTimestamp *stamp)
171 {
172 return gsf_timestamp_load_from_string (stamp, spec);
173 }
174
175 /**
176 * gsf_timestamp_as_string:
177 * @stamp: timestamp to be converted.
178 *
179 * Produce a string representation (ISO 8601 format) of @stamp.
180 *
181 * Returns: a string representation of @stamp. When @stamp is %NULL, the
182 * representation is "<invalid>".
183 */
184 char *
gsf_timestamp_as_string(GsfTimestamp const * stamp)185 gsf_timestamp_as_string (GsfTimestamp const *stamp)
186 {
187 time_t t;
188 struct tm tm;
189
190 g_return_val_if_fail (stamp != NULL, g_strdup ("<invalid>"));
191
192 t = stamp->timet; /* Use an honest time_t for gmtime_r. */
193 #ifdef HAVE_GMTIME_R
194 gmtime_r (&t, &tm);
195 #else
196 /* -NOT- thread-safe */
197 tm = *gmtime (&t);
198 #endif
199
200
201 /* using 'YYYY-MM-DDThh:mm:ss' */
202 return g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02dZ",
203 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
204 tm.tm_hour, tm.tm_min, tm.tm_sec);
205 }
206
207 guint
gsf_timestamp_hash(GsfTimestamp const * stamp)208 gsf_timestamp_hash (GsfTimestamp const *stamp)
209 {
210 return stamp->timet;
211 }
212
213 /**
214 * gsf_timestamp_equal:
215 * @a: a timestamp
216 * @b: another timestamp
217 *
218 * Compare timestamps @a and @b.
219 *
220 * Returns: true if @a and @b represent the same point in time; false otherwise.
221 *
222 **/
223 gboolean
gsf_timestamp_equal(GsfTimestamp const * a,GsfTimestamp const * b)224 gsf_timestamp_equal (GsfTimestamp const *a, GsfTimestamp const *b)
225 {
226 return a->timet == b->timet;
227 }
228
229 /**
230 * gsf_timestamp_to_value:
231 * @stamp: #GsfTimestamp
232 * @value: #GValue
233 *
234 * Calls g_value_set_box (value, stamp);
235 *
236 * Since: 1.14.24
237 **/
238 void
gsf_timestamp_to_value(GsfTimestamp const * stamp,GValue * value)239 gsf_timestamp_to_value (GsfTimestamp const *stamp, GValue *value)
240 {
241 g_value_set_boxed (value, stamp);
242 }
243
244 /**
245 * gsf_value_set_timestamp: (skip)
246 * @value: #GValue
247 * @stamp: #GsfTimestamp
248 *
249 * Deprecated: 1.14.24, use gsf_timestamp_to_value.
250 **/
251 void
gsf_value_set_timestamp(GValue * value,GsfTimestamp const * stamp)252 gsf_value_set_timestamp (GValue *value, GsfTimestamp const *stamp)
253 {
254 g_value_set_boxed (value, stamp);
255 }
256
257 void
gsf_timestamp_set_time(GsfTimestamp * stamp,guint64 t)258 gsf_timestamp_set_time (GsfTimestamp *stamp, guint64 t)
259 {
260 stamp->timet = t;
261 }
262