2 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include "gst_private.h"
25 #include "gstdatetime.h"
28 * SECTION:gst-date-time
30 * @short_description: A date, time and timezone structure
32 * Struct to store date, time and timezone information altogether.
33 * #GstDateTime is refcounted and immutable.
35 * Date information is handled using the proleptic Gregorian calendar.
37 * Provides basic creation functions and accessor functions to its fields.
42 #define GST_DATE_TIME_SEC_PER_DAY (G_GINT64_CONSTANT (86400))
43 #define GST_DATE_TIME_USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
44 #define GST_DATE_TIME_USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
45 #define GST_DATE_TIME_USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
46 #define GST_DATE_TIME_USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
47 #define GST_DATE_TIME_USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
49 #define MAX_SUPPORTED_YEAR 9999
50 #define GREGORIAN_LEAP(y) (((y%4)==0)&&(!(((y%100)==0)&&((y%400)!=0))))
52 static const guint16 days_in_months[2][13] = {
53 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
54 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
60 * As we don't have a math API, we can have fields split here.
61 * (There is still some math done internally, but nothing really relevant).
63 * If we ever add one, we should go for a days since some epoch counter.
64 * (Proleptic Gregorian with 0001-01-01 as day 1)
69 guint64 usec; /* Microsecond timekeeping within Day */
73 volatile gint ref_count;
77 * Returns the utc offset in seconds for this time structure
80 gmt_offset (struct tm *tm, time_t t)
82 #if defined (HAVE_TM_GMTOFF)
93 return (int) difftime (t, t2);
98 gst_date_time_set_local_timezone (GstDateTime * dt)
103 g_return_if_fail (dt != NULL);
105 memset (&tt, 0, sizeof (tt));
107 tt.tm_mday = gst_date_time_get_day (dt);
108 tt.tm_mon = gst_date_time_get_month (dt) - 1;
109 tt.tm_year = gst_date_time_get_year (dt) - 1900;
110 tt.tm_hour = gst_date_time_get_hour (dt);
111 tt.tm_min = gst_date_time_get_minute (dt);
112 tt.tm_sec = gst_date_time_get_second (dt);
116 dt->tzoffset = gmt_offset (&tt, t) / 60;
120 gst_date_time_alloc (void)
122 GstDateTime *datetime;
124 datetime = g_slice_new0 (GstDateTime);
125 datetime->ref_count = 1;
131 gst_date_time_free (GstDateTime * datetime)
133 g_slice_free (GstDateTime, datetime);
137 gst_date_time_new_from_date (gint year, gint month, gint day)
141 g_return_val_if_fail (year > 0 && year <= 9999, NULL);
142 g_return_val_if_fail ((month > 0 && month <= 12), NULL);
143 g_return_val_if_fail ((day > 0 && day <= 31), NULL);
145 dt = gst_date_time_alloc ();
150 gst_date_time_set_local_timezone (dt);
156 * gst_date_time_get_year:
157 * @datetime: a #GstDateTime
159 * Returns the year of this #GstDateTime
161 * Return value: The year of this #GstDateTime
165 gst_date_time_get_year (const GstDateTime * datetime)
167 g_return_val_if_fail (datetime != NULL, 0);
169 return datetime->year;
173 * gst_date_time_get_month:
174 * @datetime: a #GstDateTime
176 * Returns the month of this #GstDateTime. January is 1, February is 2, etc..
178 * Return value: The month of this #GstDateTime
182 gst_date_time_get_month (const GstDateTime * datetime)
184 g_return_val_if_fail (datetime != NULL, 0);
186 return datetime->month;
190 * gst_date_time_get_day:
191 * @datetime: a #GstDateTime
193 * Returns the day of this #GstDateTime.
195 * Return value: The day of this #GstDateTime
199 gst_date_time_get_day (const GstDateTime * datetime)
201 g_return_val_if_fail (datetime != NULL, 0);
203 return datetime->day;
207 * gst_date_time_get_hour:
208 * @datetime: a #GstDateTime
210 * Retrieves the hour of the day represented by @datetime in the gregorian
211 * calendar. The return is in the range of 0 to 23.
213 * Return value: the hour of the day
218 gst_date_time_get_hour (const GstDateTime * datetime)
220 g_return_val_if_fail (datetime != NULL, 0);
221 return (datetime->usec / GST_DATE_TIME_USEC_PER_HOUR);
225 * gst_date_time_get_microsecond:
226 * @datetime: a #GstDateTime
228 * Retrieves the fractional part of the seconds in microseconds represented by
229 * @datetime in the gregorian calendar.
231 * Return value: the microsecond of the second
236 gst_date_time_get_microsecond (const GstDateTime * datetime)
238 g_return_val_if_fail (datetime != NULL, 0);
239 return (datetime->usec % GST_DATE_TIME_USEC_PER_SECOND);
243 * gst_date_time_get_minute:
244 * @datetime: a #GstDateTime
246 * Retrieves the minute of the hour represented by @datetime in the gregorian
249 * Return value: the minute of the hour
254 gst_date_time_get_minute (const GstDateTime * datetime)
256 g_return_val_if_fail (datetime != NULL, 0);
257 return (datetime->usec % GST_DATE_TIME_USEC_PER_HOUR) /
258 GST_DATE_TIME_USEC_PER_MINUTE;
262 * gst_date_time_get_second:
263 * @datetime: a #GstDateTime
265 * Retrieves the second of the minute represented by @datetime in the gregorian
268 * Return value: the second represented by @datetime
273 gst_date_time_get_second (const GstDateTime * datetime)
275 g_return_val_if_fail (datetime != NULL, 0);
276 return (datetime->usec % GST_DATE_TIME_USEC_PER_MINUTE) /
277 GST_DATE_TIME_USEC_PER_SECOND;
281 * gst_date_time_get_time_zone_offset:
282 * @datetime: a #GstDateTime
284 * Retrieves the offset from UTC in hours that the timezone specified
285 * by @datetime represents. Timezones ahead (to the east) of UTC have positive
286 * values, timezones before (to the west) of UTC have negative values.
287 * If @datetime represents UTC time, then the offset is zero.
289 * Return value: the offset from UTC in hours
293 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
295 g_return_val_if_fail (datetime != NULL, 0);
297 return datetime->tzoffset / 60.0f;
301 * gst_date_time_new_from_unix_epoch:
302 * @t: seconds from the Unix epoch
304 * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by @t.
305 * The #GstDateTime is in the local timezone.
307 * Return value: the newly created #GstDateTime
312 gst_date_time_new_from_unix_epoch (gint64 t)
318 memset (&tm, 0, sizeof (tm));
320 #ifdef HAVE_LOCALTIME_R
321 localtime_r (&tt, &tm);
323 localtime (&tt, &tm);
326 dt = gst_date_time_new (tm.tm_year + 1900,
327 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 0, 0);
328 gst_date_time_set_local_timezone (dt);
333 * gst_date_time_new_local_time:
334 * @year: the gregorian year
335 * @month: the gregorian month
336 * @day: the day of the gregorian month
337 * @hour: the hour of the day
338 * @minute: the minute of the hour
339 * @second: the second of the minute
340 * @microsecond: the microsecond of the second
342 * Creates a new #GstDateTime using the date and times in the gregorian calendar
343 * in the local timezone.
345 * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
346 * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59 and
347 * @microsecond from 0 to 999999.
349 * Return value: the newly created #GstDateTime
354 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
355 gint minute, gint second, gint microsecond)
359 dt = gst_date_time_new (year, month, day, hour, minute, second, microsecond,
362 gst_date_time_set_local_timezone (dt);
369 * @year: the gregorian year
370 * @month: the gregorian month
371 * @day: the day of the gregorian month
372 * @hour: the hour of the day
373 * @minute: the minute of the hour
374 * @second: the second of the minute
375 * @microsecond: the microsecond of the second
376 * @tzoffset: Offset from UTC in hours.
378 * Creates a new #GstDateTime using the date and times in the gregorian calendar
379 * in the supplied timezone.
381 * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
382 * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59 and
383 * @microsecond from 0 to 999999.
385 * Note that @tzoffset is a float and was chosen so for being able to handle
386 * some fractional timezones, while it still keeps the readability of
387 * represeting it in hours for most timezones.
389 * Return value: the newly created #GstDateTime
394 gst_date_time_new (gint year, gint month, gint day, gint hour,
395 gint minute, gint second, gint microsecond, gfloat tzoffset)
399 g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
400 g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
401 g_return_val_if_fail (second >= 0 && second < 60, NULL);
402 g_return_val_if_fail (microsecond >= 0 && microsecond < 1000000, NULL);
404 if (!(dt = gst_date_time_new_from_date (year, month, day)))
407 dt->usec = (hour * GST_DATE_TIME_USEC_PER_HOUR)
408 + (minute * GST_DATE_TIME_USEC_PER_MINUTE)
409 + (second * GST_DATE_TIME_USEC_PER_SECOND)
411 dt->tzoffset = (gint) (60 * tzoffset);
417 * gst_date_time_new_now_local_time:
419 * Creates a new #GstDateTime representing the current date and time.
421 * Return value: the newly created #GstDateTime which should be freed with
422 * gst_date_time_unref().
427 gst_date_time_new_now_local_time (void)
429 GstDateTime *datetime;
431 g_get_current_time (&tv);
433 datetime = gst_date_time_new_from_unix_epoch (tv.tv_sec);
434 datetime->usec += tv.tv_usec;
435 gst_date_time_set_local_timezone (datetime);
441 * @datetime: a #GstDateTime
443 * Atomically increments the reference count of @datetime by one.
445 * Return value: the reference @datetime
450 gst_date_time_ref (GstDateTime * datetime)
452 g_return_val_if_fail (datetime != NULL, NULL);
453 g_return_val_if_fail (datetime->ref_count > 0, NULL);
454 g_atomic_int_inc (&datetime->ref_count);
459 * gst_date_time_unref:
460 * @datetime: a #GstDateTime
462 * Atomically decrements the reference count of @datetime by one. When the
463 * reference count reaches zero, the structure is freed.
468 gst_date_time_unref (GstDateTime * datetime)
470 g_return_if_fail (datetime != NULL);
471 g_return_if_fail (datetime->ref_count > 0);
473 if (g_atomic_int_dec_and_test (&datetime->ref_count))
474 gst_date_time_free (datetime);
478 gst_date_time_copy (const GstDateTime * dt)
480 GstDateTime *copy = gst_date_time_alloc ();
482 memcpy (copy, dt, sizeof (GstDateTime));
489 gst_date_time_to_utc (const GstDateTime * dt)
496 g_return_val_if_fail (dt != NULL, NULL);
498 utc = gst_date_time_copy (dt);
500 usec = dt->usec - dt->tzoffset * GST_DATE_TIME_USEC_PER_MINUTE;
501 days = usec / GST_DATE_TIME_USEC_PER_DAY;
506 leap = GREGORIAN_LEAP (utc->year) ? 1 : 0;
508 /* check if we should update month/year */
510 if (utc->month == 1) {
516 if (GREGORIAN_LEAP (utc->year))
517 utc->day = days_in_months[1][utc->month];
519 utc->day = days_in_months[0][utc->month];
520 } else if (utc->day > days_in_months[leap][utc->month]) {
521 if (utc->month == 12) {
532 GST_DATE_TIME_USEC_PER_DAY + (usec % GST_DATE_TIME_USEC_PER_DAY);
534 utc->usec = usec % GST_DATE_TIME_USEC_PER_DAY;
540 * gst_date_time_new_now_utc:
542 * Creates a new #GstDateTime that represents the current instant at Universal
545 * Return value: the newly created #GstDateTime which should be freed with
546 * gst_date_time_unref().
551 gst_date_time_new_now_utc (void)
553 GstDateTime *now, *utc;
555 now = gst_date_time_new_now_local_time ();
556 utc = gst_date_time_to_utc (now);
557 gst_date_time_unref (now);