e05d22298d332be05f72c6315ed6934930526adb
[platform/upstream/gstreamer.git] / gst / gstdatetime.c
1 /* GStreamer
2  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "glib-compat-private.h"
25 #include "gst_private.h"
26 #include "gstdatetime.h"
27 #include <glib.h>
28 #include <math.h>
29
30 /**
31  * SECTION:gstdatetime
32  * @title: GstDateTime
33  * @short_description: A date, time and timezone structure
34  *
35  * Struct to store date, time and timezone information altogether.
36  * #GstDateTime is refcounted and immutable.
37  *
38  * Date information is handled using the proleptic Gregorian calendar.
39  *
40  * Provides basic creation functions and accessor functions to its fields.
41  *
42  * Since: 0.10.31
43  */
44
45 /**
46  * gst_date_time_get_year:
47  * @datetime: a #GstDateTime
48  *
49  * Returns the year of this #GstDateTime
50  *
51  * Return value: The year of this #GstDateTime
52  * Since: 0.10.31
53  */
54
55 /**
56  * gst_date_time_get_month:
57  * @datetime: a #GstDateTime
58  *
59  * Returns the month of this #GstDateTime. January is 1, February is 2, etc..
60  *
61  * Return value: The month of this #GstDateTime
62  * Since: 0.10.31
63  */
64
65 /**
66  * gst_date_time_get_day:
67  * @datetime: a #GstDateTime
68  *
69  * Returns the day of this #GstDateTime.
70  *
71  * Return value: The day of this #GstDateTime
72  * Since: 0.10.31
73  */
74
75 /**
76  * gst_date_time_get_hour:
77  * @datetime: a #GstDateTime
78  *
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.
81  *
82  * Return value: the hour of the day
83  *
84  * Since: 0.10.31
85  */
86
87 /**
88  * gst_date_time_get_microsecond:
89  * @datetime: a #GstDateTime
90  *
91  * Retrieves the fractional part of the seconds in microseconds represented by
92  * @datetime in the gregorian calendar.
93  *
94  * Return value: the microsecond of the second
95  *
96  * Since: 0.10.31
97  */
98
99 /**
100  * gst_date_time_get_minute:
101  * @datetime: a #GstDateTime
102  *
103  * Retrieves the minute of the hour represented by @datetime in the gregorian
104  * calendar.
105  *
106  * Return value: the minute of the hour
107  *
108  * Since: 0.10.31
109  */
110
111 /**
112  * gst_date_time_get_second:
113  * @datetime: a #GstDateTime
114  *
115  * Retrieves the second of the minute represented by @datetime in the gregorian
116  * calendar.
117  *
118  * Return value: the second represented by @datetime
119  *
120  * Since: 0.10.31
121  */
122
123 /**
124  * gst_date_time_get_second:
125  * @datetime: a #GstDateTime
126  *
127  * Retrieves the second of the minute represented by @datetime in the gregorian
128  * calendar.
129  *
130  * Return value: the second represented by @datetime
131  *
132  * Since: 0.10.31
133  */
134
135 /**
136  * gst_date_time_get_time_zone_offset:
137  * @datetime: a #GstDateTime
138  *
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.
143  *
144  * Return value: the offset from UTC in hours
145  * Since: 0.10.31
146  */
147
148 /**
149  * gst_date_time_new_from_unix_epoch_local_time:
150  * @secs: seconds from the Unix epoch
151  *
152  * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
153  * @secs. The #GstDateTime is in the local timezone.
154  *
155  * Return value: the newly created #GstDateTime
156  *
157  * Since: 0.10.31
158  */
159
160 /**
161  * gst_date_time_new_from_unix_epoch_utc:
162  * @secs: seconds from the Unix epoch
163  *
164  * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
165  * @secs. The #GstDateTime is in the UTC timezone.
166  *
167  * Return value: the newly created #GstDateTime
168  *
169  * Since: 0.10.31
170  */
171
172 /**
173  * gst_date_time_new_local_time:
174  * @year: the gregorian year
175  * @month: the gregorian month
176  * @day: the day of the gregorian month
177  * @hour: the hour of the day
178  * @minute: the minute of the hour
179  * @second: the second of the minute
180  * @microsecond: the microsecond of the second
181  *
182  * Creates a new #GstDateTime using the date and times in the gregorian calendar
183  * in the local timezone.
184  *
185  * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
186  * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59 and
187  * @microsecond from 0 to 999999.
188  *
189  * Return value: the newly created #GstDateTime
190  *
191  * Since: 0.10.31
192  */
193
194 /**
195  * gst_date_time_new:
196  * @tzoffset: Offset from UTC in hours.
197  * @year: the gregorian year
198  * @month: the gregorian month
199  * @day: the day of the gregorian month
200  * @hour: the hour of the day
201  * @minute: the minute of the hour
202  * @second: the second of the minute
203  * @microsecond: the microsecond of the second
204  *
205  * Creates a new #GstDateTime using the date and times in the gregorian calendar
206  * in the supplied timezone.
207  *
208  * @year should be from 1 to 9999, @month should be from 1 to 12, @day from
209  * 1 to 31, @hour from 0 to 23, @minutes and @seconds from 0 to 59 and
210  * @microsecond from 0 to 999999.
211  *
212  * Note that @tzoffset is a float and was chosen so for being able to handle
213  * some fractional timezones, while it still keeps the readability of
214  * represeting it in hours for most timezones.
215  *
216  * Return value: the newly created #GstDateTime
217  *
218  * Since: 0.10.31
219  */
220
221 /**
222  * gst_date_time_new_now_local_time:
223  *
224  * Creates a new #GstDateTime representing the current date and time.
225  *
226  * Return value: the newly created #GstDateTime which should be freed with
227  *   gst_date_time_unref().
228  *
229  * Since: 0.10.31
230  */
231
232 /**
233  * gst_date_time_new_now_utc:
234  *
235  * Creates a new #GstDateTime that represents the current instant at Universal
236  * coordinated time.
237  *
238  * Return value: the newly created #GstDateTime which should be freed with
239  *   gst_date_time_unref().
240  *
241  * Since: 0.10.31
242  */
243
244
245 #define GST_DATE_TIME_SEC_PER_DAY          (G_GINT64_CONSTANT (86400))
246 #define GST_DATE_TIME_USEC_PER_DAY         (G_GINT64_CONSTANT (86400000000))
247 #define GST_DATE_TIME_USEC_PER_HOUR        (G_GINT64_CONSTANT (3600000000))
248 #define GST_DATE_TIME_USEC_PER_MINUTE      (G_GINT64_CONSTANT (60000000))
249 #define GST_DATE_TIME_USEC_PER_SECOND      (G_GINT64_CONSTANT (1000000))
250 #define GST_DATE_TIME_USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
251
252 #ifndef GLIB_HAS_GDATETIME
253
254 #define MAX_SUPPORTED_YEAR 9999
255 #define GREGORIAN_LEAP(y)  (((y%4)==0)&&(!(((y%100)==0)&&((y%400)!=0))))
256
257 static const guint16 days_in_months[2][13] = {
258   {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
259   {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
260 };
261
262 struct _GstDateTime
263 {
264   /*
265    * As we don't have a datetime math API, we can have fields split here.
266    * (There is still some math done internally, but nothing really relevant).
267    *
268    * If we ever add one, we should go for a days since some epoch counter.
269    * (Proleptic Gregorian with 0001-01-01 as day 1)
270    */
271   gint16 year;
272   gint8 month;
273   gint8 day;
274   guint64 usec;                 /* Microsecond timekeeping within Day */
275
276   gint tzoffset;
277
278   volatile gint ref_count;
279 };
280
281 /*
282  * Returns the utc offset in seconds for this time structure
283  */
284 static gint
285 gmt_offset (struct tm *tm, time_t t)
286 {
287 #if defined (HAVE_TM_GMTOFF)
288   return tm->tm_gmtoff;
289 #else
290   struct tm g;
291   time_t t2;
292 #ifdef HAVE_GMTIME_R
293   gmtime_r (&t, &g);
294 #else
295   g = *gmtime (&t);
296 #endif
297   t2 = mktime (&g);
298   return (int) difftime (t, t2);
299 #endif
300 }
301
302 static void
303 gst_date_time_set_local_timezone (GstDateTime * dt)
304 {
305   struct tm tt;
306   time_t t;
307
308   g_return_if_fail (dt != NULL);
309
310   memset (&tt, 0, sizeof (tt));
311
312   tt.tm_mday = gst_date_time_get_day (dt);
313   tt.tm_mon = gst_date_time_get_month (dt) - 1;
314   tt.tm_year = gst_date_time_get_year (dt) - 1900;
315   tt.tm_hour = gst_date_time_get_hour (dt);
316   tt.tm_min = gst_date_time_get_minute (dt);
317   tt.tm_sec = gst_date_time_get_second (dt);
318
319   t = mktime (&tt);
320
321   dt->tzoffset = gmt_offset (&tt, t) / 60;
322 }
323
324 static GstDateTime *
325 gst_date_time_alloc (void)
326 {
327   GstDateTime *datetime;
328
329   datetime = g_slice_new0 (GstDateTime);
330   datetime->ref_count = 1;
331
332   return datetime;
333 }
334
335 static void
336 gst_date_time_free (GstDateTime * datetime)
337 {
338   g_slice_free (GstDateTime, datetime);
339 }
340
341 static GstDateTime *
342 gst_date_time_new_from_date (gint year, gint month, gint day)
343 {
344   GstDateTime *dt;
345
346   g_return_val_if_fail (year > 0 && year <= 9999, NULL);
347   g_return_val_if_fail ((month > 0 && month <= 12), NULL);
348   g_return_val_if_fail ((day > 0 && day <= 31), NULL);
349
350   dt = gst_date_time_alloc ();
351
352   dt->year = year;
353   dt->month = month;
354   dt->day = day;
355   gst_date_time_set_local_timezone (dt);
356
357   return dt;
358 }
359
360 gint
361 gst_date_time_get_year (const GstDateTime * datetime)
362 {
363   g_return_val_if_fail (datetime != NULL, 0);
364
365   return datetime->year;
366 }
367
368 gint
369 gst_date_time_get_month (const GstDateTime * datetime)
370 {
371   g_return_val_if_fail (datetime != NULL, 0);
372
373   return datetime->month;
374 }
375
376 gint
377 gst_date_time_get_day (const GstDateTime * datetime)
378 {
379   g_return_val_if_fail (datetime != NULL, 0);
380
381   return datetime->day;
382 }
383
384 gint
385 gst_date_time_get_hour (const GstDateTime * datetime)
386 {
387   g_return_val_if_fail (datetime != NULL, 0);
388   return (datetime->usec / GST_DATE_TIME_USEC_PER_HOUR);
389 }
390
391 gint
392 gst_date_time_get_microsecond (const GstDateTime * datetime)
393 {
394   g_return_val_if_fail (datetime != NULL, 0);
395   return (datetime->usec % GST_DATE_TIME_USEC_PER_SECOND);
396 }
397
398 gint
399 gst_date_time_get_minute (const GstDateTime * datetime)
400 {
401   g_return_val_if_fail (datetime != NULL, 0);
402   return (datetime->usec % GST_DATE_TIME_USEC_PER_HOUR) /
403       GST_DATE_TIME_USEC_PER_MINUTE;
404 }
405
406 gint
407 gst_date_time_get_second (const GstDateTime * datetime)
408 {
409   g_return_val_if_fail (datetime != NULL, 0);
410   return (datetime->usec % GST_DATE_TIME_USEC_PER_MINUTE) /
411       GST_DATE_TIME_USEC_PER_SECOND;
412 }
413
414 gfloat
415 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
416 {
417   g_return_val_if_fail (datetime != NULL, 0);
418
419   return datetime->tzoffset / 60.0f;
420 }
421
422 GstDateTime *
423 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
424 {
425   GstDateTime *dt;
426   struct tm tm;
427   time_t tt;
428
429   memset (&tm, 0, sizeof (tm));
430   tt = (time_t) secs;
431
432 #ifdef HAVE_LOCALTIME_R
433   localtime_r (&tt, &tm);
434 #else
435   memcpy (&tm, localtime (&tt), sizeof (struct tm));
436 #endif
437
438   dt = gst_date_time_new (0, tm.tm_year + 1900,
439       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
440   gst_date_time_set_local_timezone (dt);
441   return dt;
442 }
443
444 GstDateTime *
445 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
446 {
447   GstDateTime *dt;
448   struct tm tm;
449   time_t tt;
450
451   memset (&tm, 0, sizeof (tm));
452   tt = (time_t) secs;
453
454 #ifdef HAVE_GMTIME_R
455   gmtime_r (&tt, &tm);
456 #else
457   memcpy (&tm, gmtime (&tt), sizeof (struct tm));
458 #endif
459
460   dt = gst_date_time_new (0, tm.tm_year + 1900,
461       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
462   return dt;
463 }
464
465 GstDateTime *
466 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
467     gint minute, gdouble seconds)
468 {
469   GstDateTime *dt;
470
471   dt = gst_date_time_new (0, year, month, day, hour, minute, seconds);
472
473   gst_date_time_set_local_timezone (dt);
474
475   return dt;
476 }
477
478 GstDateTime *
479 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
480     gint minute, gdouble seconds)
481 {
482   GstDateTime *dt;
483
484   g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
485   g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
486   g_return_val_if_fail (seconds >= 0 && seconds < 60, NULL);
487   g_return_val_if_fail (tzoffset >= -12.0 && tzoffset <= 12.0, NULL);
488
489   if (!(dt = gst_date_time_new_from_date (year, month, day)))
490     return NULL;
491
492   dt->usec = (hour * GST_DATE_TIME_USEC_PER_HOUR)
493       + (minute * GST_DATE_TIME_USEC_PER_MINUTE)
494       + (guint64) (floor (seconds * GST_DATE_TIME_USEC_PER_SECOND + 0.5));
495
496   /* we store in minutes */
497   dt->tzoffset = (gint) tzoffset *60.0;
498
499   return dt;
500 }
501
502 GstDateTime *
503 gst_date_time_new_now_local_time (void)
504 {
505   GstDateTime *datetime;
506   GTimeVal tv;
507   g_get_current_time (&tv);
508
509   datetime = gst_date_time_new_from_unix_epoch_local_time (tv.tv_sec);
510   datetime->usec += tv.tv_usec;
511   gst_date_time_set_local_timezone (datetime);
512   return datetime;
513 }
514
515 static GstDateTime *
516 gst_date_time_copy (const GstDateTime * dt)
517 {
518   GstDateTime *copy = gst_date_time_alloc ();
519
520   memcpy (copy, dt, sizeof (GstDateTime));
521   copy->ref_count = 1;
522
523   return copy;
524 }
525
526 static GstDateTime *
527 gst_date_time_to_utc (const GstDateTime * dt)
528 {
529   GstDateTime *utc;
530   gint64 usec;
531   gint days;
532   gint leap;
533
534   g_return_val_if_fail (dt != NULL, NULL);
535
536   utc = gst_date_time_copy (dt);
537
538   usec = dt->usec - dt->tzoffset * GST_DATE_TIME_USEC_PER_MINUTE;
539   days = usec / GST_DATE_TIME_USEC_PER_DAY;
540   if (usec < 0)
541     days--;
542   utc->day += days;
543
544   leap = GREGORIAN_LEAP (utc->year) ? 1 : 0;
545
546   /* check if we should update month/year */
547   if (utc->day < 1) {
548     if (utc->month == 1) {
549       utc->year--;
550       utc->month = 12;
551     } else {
552       utc->month--;
553     }
554     if (GREGORIAN_LEAP (utc->year))
555       utc->day = days_in_months[1][utc->month];
556     else
557       utc->day = days_in_months[0][utc->month];
558   } else if (utc->day > days_in_months[leap][utc->month]) {
559     if (utc->month == 12) {
560       utc->year++;
561       utc->month = 1;
562     } else {
563       utc->month++;
564     }
565     utc->day = 1;
566   }
567
568   if (usec < 0)
569     utc->usec =
570         GST_DATE_TIME_USEC_PER_DAY + (usec % GST_DATE_TIME_USEC_PER_DAY);
571   else
572     utc->usec = usec % GST_DATE_TIME_USEC_PER_DAY;
573
574   return utc;
575 }
576
577 GstDateTime *
578 gst_date_time_new_now_utc (void)
579 {
580   GstDateTime *now, *utc;
581
582   now = gst_date_time_new_now_local_time ();
583   utc = gst_date_time_to_utc (now);
584   gst_date_time_unref (now);
585   return utc;
586 }
587
588 gint
589 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
590 {
591   GstDateTime *a, *b;
592   gint res = 0;
593
594   a = gst_date_time_to_utc (dt1);
595   b = gst_date_time_to_utc (dt2);
596
597 #define GST_DATE_TIME_COMPARE_VALUE(a,b,v)   \
598   if ((a)->v > (b)->v) {                     \
599     res = 1;                                 \
600     goto done;                               \
601   } else if ((a)->v < (b)->v) {              \
602     res = -1;                                \
603     goto done;                               \
604   }
605
606   GST_DATE_TIME_COMPARE_VALUE (a, b, year);
607   GST_DATE_TIME_COMPARE_VALUE (a, b, month);
608   GST_DATE_TIME_COMPARE_VALUE (a, b, day);
609   GST_DATE_TIME_COMPARE_VALUE (a, b, usec);
610
611 #undef GST_DATE_TIME_COMPARE_VALUE
612
613 done:
614   gst_date_time_unref (a);
615   gst_date_time_unref (b);
616   return res;
617 }
618
619 #else
620
621 struct _GstDateTime
622 {
623   GDateTime *datetime;
624
625   volatile gint ref_count;
626 };
627
628 static GstDateTime *
629 gst_date_time_new_from_gdatetime (GDateTime * dt)
630 {
631   GstDateTime *gst_dt;
632
633   if (!dt)
634     return NULL;
635
636   gst_dt = g_slice_new (GstDateTime);
637   gst_dt->datetime = dt;
638   gst_dt->ref_count = 1;
639   return gst_dt;
640 }
641
642 gint
643 gst_date_time_get_year (const GstDateTime * datetime)
644 {
645   return g_date_time_get_year (datetime->datetime);
646 }
647
648 gint
649 gst_date_time_get_month (const GstDateTime * datetime)
650 {
651   return g_date_time_get_month (datetime->datetime);
652 }
653
654 gint
655 gst_date_time_get_day (const GstDateTime * datetime)
656 {
657   return g_date_time_get_day_of_month (datetime->datetime);
658 }
659
660 gint
661 gst_date_time_get_hour (const GstDateTime * datetime)
662 {
663   return g_date_time_get_hour (datetime->datetime);
664 }
665
666 gint
667 gst_date_time_get_minute (const GstDateTime * datetime)
668 {
669   return g_date_time_get_minute (datetime->datetime);
670 }
671
672 gint
673 gst_date_time_get_second (const GstDateTime * datetime)
674 {
675   return g_date_time_get_second (datetime->datetime);
676 }
677
678 gint
679 gst_date_time_get_microsecond (const GstDateTime * datetime)
680 {
681   return g_date_time_get_microsecond (datetime->datetime);
682 }
683
684 gfloat
685 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
686 {
687   return g_date_time_get_utc_offset (datetime->datetime) /
688       (G_USEC_PER_SEC * G_GINT64_CONSTANT (3600));
689 }
690
691 GstDateTime *
692 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
693 {
694   return
695       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_local (secs));
696 }
697
698 GstDateTime *
699 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
700 {
701   return
702       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_utc (secs));
703 }
704
705 GstDateTime *
706 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
707     gint minute, gdouble seconds)
708 {
709   return gst_date_time_new_from_gdatetime (g_date_time_new_local (year, month,
710           day, hour, minute, seconds));
711 }
712
713 GstDateTime *
714 gst_date_time_new_now_local_time (void)
715 {
716   return gst_date_time_new_from_gdatetime (g_date_time_new_now_local ());
717 }
718
719 GstDateTime *
720 gst_date_time_new_now_utc (void)
721 {
722   return gst_date_time_new_from_gdatetime (g_date_time_new_now_utc ());
723 }
724
725 gint
726 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
727 {
728   const GstDateTime *datetime1 = dt1;
729   const GstDateTime *datetime2 = dt2;
730   return g_date_time_compare (datetime1->datetime, datetime2->datetime);
731 }
732
733 GstDateTime *
734 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
735     gint minute, gdouble seconds)
736 {
737   gchar buf[6];
738   GTimeZone *tz;
739   GDateTime *dt;
740   gint tzhour, tzminute;
741
742   tzhour = (gint) ABS (tzoffset);
743   tzminute = (gint) ((ABS (tzoffset) - tzhour) * 60);
744
745   g_snprintf (buf, 6, "%c%02d%02d", tzoffset >= 0 ? '+' : '-', tzhour,
746       tzminute);
747
748   tz = g_time_zone_new (buf);
749   dt = g_date_time_new (tz, year, month, day, hour, minute, seconds);
750   g_time_zone_unref (tz);
751   return gst_date_time_new_from_gdatetime (dt);
752 }
753
754 static void
755 gst_date_time_free (GstDateTime * datetime)
756 {
757   g_date_time_unref (datetime->datetime);
758   g_slice_free (GstDateTime, datetime);
759 }
760
761 #endif
762
763 /**
764  * gst_date_time_ref:
765  * @datetime: a #GstDateTime
766  *
767  * Atomically increments the reference count of @datetime by one.
768  *
769  * Return value: the reference @datetime
770  *
771  * Since: 0.10.31
772  */
773 GstDateTime *
774 gst_date_time_ref (GstDateTime * datetime)
775 {
776   g_return_val_if_fail (datetime != NULL, NULL);
777   g_return_val_if_fail (datetime->ref_count > 0, NULL);
778   g_atomic_int_inc (&datetime->ref_count);
779   return datetime;
780 }
781
782 /**
783  * gst_date_time_unref:
784  * @datetime: a #GstDateTime
785  *
786  * Atomically decrements the reference count of @datetime by one.  When the
787  * reference count reaches zero, the structure is freed.
788  *
789  * Since: 0.10.31
790  */
791 void
792 gst_date_time_unref (GstDateTime * datetime)
793 {
794   g_return_if_fail (datetime != NULL);
795   g_return_if_fail (datetime->ref_count > 0);
796
797   if (g_atomic_int_dec_and_test (&datetime->ref_count))
798     gst_date_time_free (datetime);
799 }