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 "glib-compat-private.h"
25 #include "gst_private.h"
26 #include "gstdatetime.h"
33 * @short_description: A date, time and timezone structure
35 * Struct to store date, time and timezone information altogether.
36 * #GstDateTime is refcounted and immutable.
38 * Date information is handled using the proleptic Gregorian calendar.
40 * Provides basic creation functions and accessor functions to its fields.
46 * gst_date_time_get_year:
47 * @datetime: a #GstDateTime
49 * Returns the year of this #GstDateTime
51 * Return value: The year of this #GstDateTime
56 * gst_date_time_get_month:
57 * @datetime: a #GstDateTime
59 * Returns the month of this #GstDateTime. January is 1, February is 2, etc..
61 * Return value: The month of this #GstDateTime
66 * gst_date_time_get_day:
67 * @datetime: a #GstDateTime
69 * Returns the day of this #GstDateTime.
71 * Return value: The day of this #GstDateTime
76 * gst_date_time_get_hour:
77 * @datetime: a #GstDateTime
79 * Retrieves the hour of the day represented by @datetime in the gregorian
80 * calendar. The return is in the range of 0 to 23.
82 * Return value: the hour of the day
88 * gst_date_time_get_microsecond:
89 * @datetime: a #GstDateTime
91 * Retrieves the fractional part of the seconds in microseconds represented by
92 * @datetime in the gregorian calendar.
94 * Return value: the microsecond of the second
100 * gst_date_time_get_minute:
101 * @datetime: a #GstDateTime
103 * Retrieves the minute of the hour represented by @datetime in the gregorian
106 * Return value: the minute of the hour
112 * gst_date_time_get_second:
113 * @datetime: a #GstDateTime
115 * Retrieves the second of the minute represented by @datetime in the gregorian
118 * Return value: the second represented by @datetime
124 * gst_date_time_get_second:
125 * @datetime: a #GstDateTime
127 * Retrieves the second of the minute represented by @datetime in the gregorian
130 * Return value: the second represented by @datetime
136 * gst_date_time_get_time_zone_offset:
137 * @datetime: a #GstDateTime
139 * Retrieves the offset from UTC in hours that the timezone specified
140 * by @datetime represents. Timezones ahead (to the east) of UTC have positive
141 * values, timezones before (to the west) of UTC have negative values.
142 * If @datetime represents UTC time, then the offset is zero.
144 * Return value: the offset from UTC in hours
149 * gst_date_time_new_from_unix_epoch_local_time:
150 * @secs: seconds from the Unix epoch
152 * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
153 * @secs. The #GstDateTime is in the local timezone.
155 * Free-function: gst_date_time_unref
157 * Return value: (transfer full): the newly created #GstDateTime
163 * gst_date_time_new_from_unix_epoch_utc:
164 * @secs: seconds from the Unix epoch
166 * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
167 * @secs. The #GstDateTime is in the UTC timezone.
169 * Free-function: gst_date_time_unref
171 * Return value: (transfer full): the newly created #GstDateTime
177 * gst_date_time_new_local_time:
178 * @year: the gregorian year
179 * @month: the gregorian month
180 * @day: the day of the gregorian month
181 * @hour: the hour of the day
182 * @minute: the minute of the hour
183 * @seconds: the second of the minute
185 * Creates a new #GstDateTime using the date and times in the gregorian calendar
186 * in the local timezone.
188 * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
189 * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59.
191 * Free-function: gst_date_time_unref
193 * Return value: (transfer full): the newly created #GstDateTime
200 * @tzoffset: Offset from UTC in hours.
201 * @year: the gregorian year
202 * @month: the gregorian month
203 * @day: the day of the gregorian month
204 * @hour: the hour of the day
205 * @minute: the minute of the hour
206 * @seconds: the second of the minute
208 * Creates a new #GstDateTime using the date and times in the gregorian calendar
209 * in the supplied timezone.
211 * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
212 * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59.
214 * Note that @tzoffset is a float and was chosen so for being able to handle
215 * some fractional timezones, while it still keeps the readability of
216 * represeting it in hours for most timezones.
218 * Free-function: gst_date_time_unref
220 * Return value: (transfer full): the newly created #GstDateTime
226 * gst_date_time_new_now_local_time:
228 * Creates a new #GstDateTime representing the current date and time.
230 * Free-function: gst_date_time_unref
232 * Return value: (transfer full): the newly created #GstDateTime which should
233 * be freed with gst_date_time_unref().
239 * gst_date_time_new_now_utc:
241 * Creates a new #GstDateTime that represents the current instant at Universal
244 * Free-function: gst_date_time_unref
246 * Return value: (transfer full): the newly created #GstDateTime which should
247 * be freed with gst_date_time_unref().
253 #define GST_DATE_TIME_SEC_PER_DAY (G_GINT64_CONSTANT (86400))
254 #define GST_DATE_TIME_USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
255 #define GST_DATE_TIME_USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
256 #define GST_DATE_TIME_USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
257 #define GST_DATE_TIME_USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
258 #define GST_DATE_TIME_USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
260 /* Jan 5th 2011 (Edward) : GLib's GDateTime is broken in regards to gmt offset
261 * on macosx. Re-enable it once the following bug is fixed:
262 * https://bugzilla.gnome.org/show_bug.cgi?id=638666 */
264 #undef GLIB_HAS_GDATETIME
268 #ifndef GLIB_HAS_GDATETIME
270 #define MAX_SUPPORTED_YEAR 9999
271 #define GREGORIAN_LEAP(y) (((y%4)==0)&&(!(((y%100)==0)&&((y%400)!=0))))
273 static const guint16 days_in_months[2][13] = {
274 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
275 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
281 * As we don't have a datetime math API, we can have fields split here.
282 * (There is still some math done internally, but nothing really relevant).
284 * If we ever add one, we should go for a days since some epoch counter.
285 * (Proleptic Gregorian with 0001-01-01 as day 1)
290 guint64 usec; /* Microsecond timekeeping within Day */
294 volatile gint ref_count;
298 * Returns the utc offset in seconds for this time structure
301 gmt_offset (struct tm *tm, time_t t)
303 #if defined (HAVE_TM_GMTOFF)
304 return tm->tm_gmtoff;
314 return (int) difftime (t, t2);
319 gst_date_time_set_local_timezone (GstDateTime * dt)
324 g_return_if_fail (dt != NULL);
326 memset (&tt, 0, sizeof (tt));
328 tt.tm_mday = gst_date_time_get_day (dt);
329 tt.tm_mon = gst_date_time_get_month (dt) - 1;
330 tt.tm_year = gst_date_time_get_year (dt) - 1900;
331 tt.tm_hour = gst_date_time_get_hour (dt);
332 tt.tm_min = gst_date_time_get_minute (dt);
333 tt.tm_sec = gst_date_time_get_second (dt);
337 dt->tzoffset = gmt_offset (&tt, t) / 60;
341 gst_date_time_alloc (void)
343 GstDateTime *datetime;
345 datetime = g_slice_new0 (GstDateTime);
346 datetime->ref_count = 1;
352 gst_date_time_free (GstDateTime * datetime)
354 g_slice_free (GstDateTime, datetime);
358 gst_date_time_new_from_date (gint year, gint month, gint day)
362 g_return_val_if_fail (year > 0 && year <= 9999, NULL);
363 g_return_val_if_fail ((month > 0 && month <= 12), NULL);
364 g_return_val_if_fail ((day > 0 && day <= 31), NULL);
366 dt = gst_date_time_alloc ();
371 gst_date_time_set_local_timezone (dt);
377 gst_date_time_get_year (const GstDateTime * datetime)
379 g_return_val_if_fail (datetime != NULL, 0);
381 return datetime->year;
385 gst_date_time_get_month (const GstDateTime * datetime)
387 g_return_val_if_fail (datetime != NULL, 0);
389 return datetime->month;
393 gst_date_time_get_day (const GstDateTime * datetime)
395 g_return_val_if_fail (datetime != NULL, 0);
397 return datetime->day;
401 gst_date_time_get_hour (const GstDateTime * datetime)
403 g_return_val_if_fail (datetime != NULL, 0);
404 return (datetime->usec / GST_DATE_TIME_USEC_PER_HOUR);
408 gst_date_time_get_microsecond (const GstDateTime * datetime)
410 g_return_val_if_fail (datetime != NULL, 0);
411 return (datetime->usec % GST_DATE_TIME_USEC_PER_SECOND);
415 gst_date_time_get_minute (const GstDateTime * datetime)
417 g_return_val_if_fail (datetime != NULL, 0);
418 return (datetime->usec % GST_DATE_TIME_USEC_PER_HOUR) /
419 GST_DATE_TIME_USEC_PER_MINUTE;
423 gst_date_time_get_second (const GstDateTime * datetime)
425 g_return_val_if_fail (datetime != NULL, 0);
426 return (datetime->usec % GST_DATE_TIME_USEC_PER_MINUTE) /
427 GST_DATE_TIME_USEC_PER_SECOND;
431 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
433 g_return_val_if_fail (datetime != NULL, 0);
435 return datetime->tzoffset / 60.0f;
439 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
445 memset (&tm, 0, sizeof (tm));
448 #ifdef HAVE_LOCALTIME_R
449 localtime_r (&tt, &tm);
451 memcpy (&tm, localtime (&tt), sizeof (struct tm));
454 dt = gst_date_time_new (0, tm.tm_year + 1900,
455 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
456 gst_date_time_set_local_timezone (dt);
461 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
467 memset (&tm, 0, sizeof (tm));
473 memcpy (&tm, gmtime (&tt), sizeof (struct tm));
476 dt = gst_date_time_new (0, tm.tm_year + 1900,
477 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
482 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
483 gint minute, gdouble seconds)
487 dt = gst_date_time_new (0, year, month, day, hour, minute, seconds);
489 gst_date_time_set_local_timezone (dt);
495 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
496 gint minute, gdouble seconds)
500 g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
501 g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
502 g_return_val_if_fail (seconds >= 0 && seconds < 60, NULL);
503 g_return_val_if_fail (tzoffset >= -12.0 && tzoffset <= 12.0, NULL);
505 if (!(dt = gst_date_time_new_from_date (year, month, day)))
508 dt->usec = (hour * GST_DATE_TIME_USEC_PER_HOUR)
509 + (minute * GST_DATE_TIME_USEC_PER_MINUTE)
510 + (guint64) (floor (seconds * GST_DATE_TIME_USEC_PER_SECOND + 0.5));
512 /* we store in minutes */
513 dt->tzoffset = (gint) (tzoffset * 60.0);
519 gst_date_time_new_now_local_time (void)
521 GstDateTime *datetime;
523 g_get_current_time (&tv);
525 datetime = gst_date_time_new_from_unix_epoch_local_time (tv.tv_sec);
526 datetime->usec += tv.tv_usec;
527 gst_date_time_set_local_timezone (datetime);
532 gst_date_time_copy (const GstDateTime * dt)
534 GstDateTime *copy = gst_date_time_alloc ();
536 memcpy (copy, dt, sizeof (GstDateTime));
543 gst_date_time_to_utc (const GstDateTime * dt)
550 g_return_val_if_fail (dt != NULL, NULL);
552 utc = gst_date_time_copy (dt);
554 usec = dt->usec - dt->tzoffset * GST_DATE_TIME_USEC_PER_MINUTE;
555 days = usec / GST_DATE_TIME_USEC_PER_DAY;
560 leap = GREGORIAN_LEAP (utc->year) ? 1 : 0;
562 /* check if we should update month/year */
564 if (utc->month == 1) {
570 if (GREGORIAN_LEAP (utc->year))
571 utc->day = days_in_months[1][utc->month];
573 utc->day = days_in_months[0][utc->month];
574 } else if (utc->day > days_in_months[leap][utc->month]) {
575 if (utc->month == 12) {
586 GST_DATE_TIME_USEC_PER_DAY + (usec % GST_DATE_TIME_USEC_PER_DAY);
588 utc->usec = usec % GST_DATE_TIME_USEC_PER_DAY;
594 gst_date_time_new_now_utc (void)
596 GstDateTime *now, *utc;
598 now = gst_date_time_new_now_local_time ();
599 utc = gst_date_time_to_utc (now);
600 gst_date_time_unref (now);
605 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
610 a = gst_date_time_to_utc (dt1);
611 b = gst_date_time_to_utc (dt2);
613 #define GST_DATE_TIME_COMPARE_VALUE(a,b,v) \
614 if ((a)->v > (b)->v) { \
617 } else if ((a)->v < (b)->v) { \
622 GST_DATE_TIME_COMPARE_VALUE (a, b, year);
623 GST_DATE_TIME_COMPARE_VALUE (a, b, month);
624 GST_DATE_TIME_COMPARE_VALUE (a, b, day);
625 GST_DATE_TIME_COMPARE_VALUE (a, b, usec);
627 #undef GST_DATE_TIME_COMPARE_VALUE
630 gst_date_time_unref (a);
631 gst_date_time_unref (b);
641 volatile gint ref_count;
645 gst_date_time_new_from_gdatetime (GDateTime * dt)
652 gst_dt = g_slice_new (GstDateTime);
653 gst_dt->datetime = dt;
654 gst_dt->ref_count = 1;
659 gst_date_time_get_year (const GstDateTime * datetime)
661 return g_date_time_get_year (datetime->datetime);
665 gst_date_time_get_month (const GstDateTime * datetime)
667 return g_date_time_get_month (datetime->datetime);
671 gst_date_time_get_day (const GstDateTime * datetime)
673 return g_date_time_get_day_of_month (datetime->datetime);
677 gst_date_time_get_hour (const GstDateTime * datetime)
679 return g_date_time_get_hour (datetime->datetime);
683 gst_date_time_get_minute (const GstDateTime * datetime)
685 return g_date_time_get_minute (datetime->datetime);
689 gst_date_time_get_second (const GstDateTime * datetime)
691 return g_date_time_get_second (datetime->datetime);
695 gst_date_time_get_microsecond (const GstDateTime * datetime)
697 return g_date_time_get_microsecond (datetime->datetime);
701 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
703 return (g_date_time_get_utc_offset (datetime->datetime) /
704 G_USEC_PER_SEC) / 3600.0;
708 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
711 gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_local (secs));
715 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
718 gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_utc (secs));
722 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
723 gint minute, gdouble seconds)
725 return gst_date_time_new_from_gdatetime (g_date_time_new_local (year, month,
726 day, hour, minute, seconds));
730 gst_date_time_new_now_local_time (void)
732 return gst_date_time_new_from_gdatetime (g_date_time_new_now_local ());
736 gst_date_time_new_now_utc (void)
738 return gst_date_time_new_from_gdatetime (g_date_time_new_now_utc ());
742 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
744 const GstDateTime *datetime1 = dt1;
745 const GstDateTime *datetime2 = dt2;
746 return g_date_time_compare (datetime1->datetime, datetime2->datetime);
750 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
751 gint minute, gdouble seconds)
756 gint tzhour, tzminute;
758 tzhour = (gint) ABS (tzoffset);
759 tzminute = (gint) ((ABS (tzoffset) - tzhour) * 60);
761 g_snprintf (buf, 6, "%c%02d%02d", tzoffset >= 0 ? '+' : '-', tzhour,
764 tz = g_time_zone_new (buf);
766 dt = g_date_time_new (tz, year, month, day, hour, minute, seconds);
767 g_time_zone_unref (tz);
768 return gst_date_time_new_from_gdatetime (dt);
772 gst_date_time_free (GstDateTime * datetime)
774 g_date_time_unref (datetime->datetime);
775 g_slice_free (GstDateTime, datetime);
782 * @datetime: a #GstDateTime
784 * Atomically increments the reference count of @datetime by one.
786 * Return value: (transfer full): the reference @datetime
791 gst_date_time_ref (GstDateTime * datetime)
793 g_return_val_if_fail (datetime != NULL, NULL);
794 g_return_val_if_fail (datetime->ref_count > 0, NULL);
795 g_atomic_int_inc (&datetime->ref_count);
800 * gst_date_time_unref:
801 * @datetime: (transfer full): a #GstDateTime
803 * Atomically decrements the reference count of @datetime by one. When the
804 * reference count reaches zero, the structure is freed.
809 gst_date_time_unref (GstDateTime * datetime)
811 g_return_if_fail (datetime != NULL);
812 g_return_if_fail (datetime->ref_count > 0);
814 if (g_atomic_int_dec_and_test (&datetime->ref_count))
815 gst_date_time_free (datetime);