1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2009 The Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <stdlib.h>
24 #include "glib-utils.h"
25 #include "gth-time.h"
26 
27 
28 #define INVALID_HOUR (24)
29 #define INVALID_MIN (60)
30 #define INVALID_SEC (60)
31 #define INVALID_USEC (1000000)
32 
33 
34 static GthDateTime *
gth_datetime_copy_for_boxed(GthDateTime * source)35 gth_datetime_copy_for_boxed (GthDateTime *source)
36 {
37 	GthDateTime *dest;
38 
39 	dest = gth_datetime_new ();
40 	gth_datetime_copy (source, dest);
41 
42 	return dest;
43 }
44 
45 
G_DEFINE_BOXED_TYPE(GthDateTime,gth_datetime,gth_datetime_copy_for_boxed,gth_datetime_free)46 G_DEFINE_BOXED_TYPE (GthDateTime, gth_datetime, gth_datetime_copy_for_boxed, gth_datetime_free)
47 
48 
49 GthTime *
50 gth_time_new (void)
51 {
52 	GthTime *time;
53 
54 	time = g_new (GthTime, 1);
55 	gth_time_clear (time);
56 
57 	return time;
58 }
59 
60 
61 void
gth_time_free(GthTime * time)62 gth_time_free (GthTime *time)
63 {
64 	g_free (time);
65 }
66 
67 
68 void
gth_time_clear(GthTime * time)69 gth_time_clear (GthTime *time)
70 {
71 	time->hour = INVALID_HOUR;
72 	time->min = INVALID_MIN;
73 	time->sec = INVALID_SEC;
74 	time->usec = INVALID_USEC;
75 }
76 
77 
78 gboolean
gth_time_valid(GthTime * time)79 gth_time_valid (GthTime *time)
80 {
81 	return (time->hour < INVALID_HOUR) && (time->min < INVALID_MIN) && (time->sec < INVALID_SEC) && (time->usec < INVALID_USEC);
82 }
83 
84 
85 void
gth_time_set_hms(GthTime * time,guint8 hour,guint8 min,guint8 sec,guint usec)86 gth_time_set_hms (GthTime *time,
87 	 	  guint8   hour,
88 		  guint8   min,
89 		  guint8   sec,
90 		  guint    usec)
91 {
92 	time->hour = hour;
93 	time->min = min;
94 	time->sec = sec;
95 	time->usec = usec;
96 }
97 
98 
99 GthDateTime *
gth_datetime_new(void)100 gth_datetime_new (void)
101 {
102 	GthDateTime *dt;
103 
104 	dt = g_new0 (GthDateTime, 1);
105 	dt->date = g_date_new ();
106 	dt->time = gth_time_new ();
107 
108 	return dt;
109 }
110 
111 
112 void
gth_datetime_free(GthDateTime * dt)113 gth_datetime_free (GthDateTime *dt)
114 {
115 	if (dt == NULL)
116 		return;
117 	g_date_free (dt->date);
118 	gth_time_free (dt->time);
119 	g_free (dt);
120 }
121 
122 
123 void
gth_datetime_copy(GthDateTime * src,GthDateTime * dest)124 gth_datetime_copy (GthDateTime *src,
125 		   GthDateTime *dest)
126 {
127 	if (g_date_valid (src->date)) {
128 		*dest->date = *src->date;
129 		if (gth_time_valid (src->time))
130 			*dest->time = *src->time;
131 		else
132 			gth_time_clear (dest->time);
133 	}
134 	else
135 		gth_datetime_clear (dest);
136 }
137 
138 
139 void
gth_datetime_clear(GthDateTime * dt)140 gth_datetime_clear (GthDateTime *dt)
141 {
142 	gth_time_clear (dt->time);
143 	g_date_clear (dt->date, 1);
144 }
145 
146 
147 gboolean
gth_datetime_valid(GthDateTime * dt)148 gth_datetime_valid (GthDateTime *dt)
149 {
150 	return gth_time_valid (dt->time) && g_date_valid (dt->date);
151 }
152 
153 
154 gboolean
gth_datetime_valid_date(GthDateTime * dt)155 gth_datetime_valid_date (GthDateTime *dt)
156 {
157 	return g_date_valid (dt->date);
158 }
159 
160 
161 void
gth_datetime_from_timeval(GthDateTime * dt,GTimeVal * tv)162 gth_datetime_from_timeval (GthDateTime *dt,
163 			   GTimeVal    *tv)
164 {
165 	char *exif_date;
166 
167 	exif_date = _g_time_val_to_exif_date (tv);
168 	gth_datetime_from_exif_date (dt, exif_date);
169 
170 	g_free (exif_date);
171 }
172 
173 
174 gboolean
gth_datetime_from_exif_date(GthDateTime * dt,const char * exif_date)175 gth_datetime_from_exif_date (GthDateTime *dt,
176 			     const char  *exif_date)
177 {
178 	GDateYear   year;
179 	GDateMonth  month;
180 	GDateDay    day;
181 	long        val;
182 
183 	if (exif_date == NULL)
184 		return FALSE;
185 
186 	g_return_val_if_fail (dt != NULL, FALSE);
187 
188 	while (g_ascii_isspace (*exif_date))
189 		exif_date++;
190 
191 	if (*exif_date == '\0')
192 		return FALSE;
193 
194 	if (! g_ascii_isdigit (*exif_date))
195 		return FALSE;
196 
197 	/* YYYY */
198 
199 	val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
200 	year = val;
201 
202 	if (*exif_date != ':')
203 		return FALSE;
204 
205 	/* MM */
206 
207 	exif_date++;
208 	month = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
209 
210 	if (*exif_date != ':')
211 		return FALSE;
212 
213 	/* DD */
214 
215 	exif_date++;
216 	day = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
217 
218   	if (*exif_date != ' ')
219 		return FALSE;
220 
221 	g_date_set_dmy (dt->date, day, month, year);
222 
223   	/* hh */
224 
225   	val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
226   	dt->time->hour = val;
227 
228   	if (*exif_date != ':')
229 		return FALSE;
230 
231   	/* mm */
232 
233 	exif_date++;
234 	dt->time->min = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
235 
236 	if (*exif_date != ':')
237 		return FALSE;
238 
239       	/* ss */
240 
241 	exif_date++;
242 	dt->time->sec = strtoul (exif_date, (char **)&exif_date, 10);
243 
244 	/* usec */
245 
246 	dt->time->usec = 0;
247 	if ((*exif_date == ',') || (*exif_date == '.')) {
248 		glong mul = 100000;
249 
250 		while (g_ascii_isdigit (*++exif_date)) {
251 			dt->time->usec += (*exif_date - '0') * mul;
252 			mul /= 10;
253 		}
254 	}
255 
256 	while (g_ascii_isspace (*exif_date))
257 		exif_date++;
258 
259 	return *exif_date == '\0';
260 }
261 
262 
263 void
gth_datetime_from_struct_tm(GthDateTime * dt,struct tm * tm)264 gth_datetime_from_struct_tm (GthDateTime *dt,
265 			     struct tm   *tm)
266 {
267 	if (tm->tm_hour < 0)
268 		gth_time_clear (dt->time);
269 	else
270 		gth_time_set_hms (dt->time, tm->tm_hour, tm->tm_min, tm->tm_sec, 0);
271 
272 	if ((tm->tm_year < 0) || (tm->tm_mday < 1) || (tm->tm_mday > 31) || (tm->tm_mon < 0) || (tm->tm_mon > 11))
273 		g_date_clear (dt->date, 1);
274 	else
275 		g_date_set_dmy (dt->date, tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
276 }
277 
278 
279 void
gth_datetime_from_gdate(GthDateTime * dt,GDate * date)280 gth_datetime_from_gdate (GthDateTime *dt,
281 			 GDate       *date)
282 {
283 	if (date != NULL)
284 		*dt->date = *date;
285 	else
286 		g_date_clear (dt->date, 1);
287 	gth_time_clear (dt->time);
288 }
289 
290 
291 char *
gth_datetime_to_exif_date(GthDateTime * dt)292 gth_datetime_to_exif_date (GthDateTime *dt)
293 {
294 	if (gth_datetime_valid (dt))
295 		return g_strdup_printf ("%4d:%02d:%02d %02d:%02d:%02d",
296 					g_date_get_year (dt->date),
297 					g_date_get_month (dt->date),
298 					g_date_get_day (dt->date),
299 					dt->time->hour,
300 					dt->time->min,
301 					dt->time->sec);
302 	else if (g_date_valid (dt->date))
303 		return g_strdup_printf ("%4d:%02d:%02d 00:00:00",
304 					g_date_get_year (dt->date),
305 					g_date_get_month (dt->date),
306 					g_date_get_day (dt->date));
307 	else
308 		return g_strdup ("");
309 }
310 
311 
312 gboolean
gth_datetime_to_struct_tm(GthDateTime * dt,struct tm * tm)313 gth_datetime_to_struct_tm (GthDateTime *dt,
314 		           struct tm   *tm)
315 {
316 	if (! gth_datetime_valid (dt))
317 		return FALSE;
318 
319 	g_date_to_struct_tm (dt->date, tm);
320 	tm->tm_hour = dt->time->hour;
321 	tm->tm_min = dt->time->min;
322 	tm->tm_sec = dt->time->sec;
323 
324 	return TRUE;
325 }
326 
327 
328 gboolean
gth_datetime_to_timeval(GthDateTime * dt,GTimeVal * tv)329 gth_datetime_to_timeval (GthDateTime *dt,
330 			 GTimeVal    *tv)
331 {
332 	char     *exif_date;
333 	gboolean  result;
334 
335 	exif_date = gth_datetime_to_exif_date (dt);
336 	result = _g_time_val_from_exif_date (exif_date, tv);
337 
338 	g_free (exif_date);
339 
340 	return result;
341 }
342 
343 
344 char *
gth_datetime_strftime(GthDateTime * dt,const char * format)345 gth_datetime_strftime (GthDateTime *dt,
346 		       const char  *format)
347 {
348 	struct  tm tm;
349 
350 	if (gth_datetime_to_struct_tm (dt, &tm))
351 		return _g_struct_tm_strftime (&tm, format);
352 	else
353 		return g_strdup ("");
354 }
355