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  * Free-function: gst_date_time_unref
 156  *
 157  * Return value: (transfer full): the newly created #GstDateTime
 158  *
 159  * Since: 0.10.31
 160  */
 161 
 162 /**
 163  * gst_date_time_new_from_unix_epoch_utc:
 164  * @secs: seconds from the Unix epoch
 165  *
 166  * Creates a new #GstDateTime using the time since Jan 1, 1970 specified by
 167  * @secs. The #GstDateTime is in the UTC timezone.
 168  *
 169  * Free-function: gst_date_time_unref
 170  *
 171  * Return value: (transfer full): the newly created #GstDateTime
 172  *
 173  * Since: 0.10.31
 174  */
 175 
 176 /**
 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
 184  *
 185  * Creates a new #GstDateTime using the date and times in the gregorian calendar
 186  * in the local timezone.
 187  *
 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.
 190  *
 191  * Free-function: gst_date_time_unref
 192  *
 193  * Return value: (transfer full): the newly created #GstDateTime
 194  *
 195  * Since: 0.10.31
 196  */
 197 
 198 /**
 199  * gst_date_time_new:
 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
 207  *
 208  * Creates a new #GstDateTime using the date and times in the gregorian calendar
 209  * in the supplied timezone.
 210  *
 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.
 213  *
 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.
 217  *
 218  * Free-function: gst_date_time_unref
 219  *
 220  * Return value: (transfer full): the newly created #GstDateTime
 221  *
 222  * Since: 0.10.31
 223  */
 224 
 225 /**
 226  * gst_date_time_new_now_local_time:
 227  *
 228  * Creates a new #GstDateTime representing the current date and time.
 229  *
 230  * Free-function: gst_date_time_unref
 231  *
 232  * Return value: (transfer full): the newly created #GstDateTime which should
 233  *     be freed with gst_date_time_unref().
 234  *
 235  * Since: 0.10.31
 236  */
 237 
 238 /**
 239  * gst_date_time_new_now_utc:
 240  *
 241  * Creates a new #GstDateTime that represents the current instant at Universal
 242  * coordinated time.
 243  *
 244  * Free-function: gst_date_time_unref
 245  *
 246  * Return value: (transfer full): the newly created #GstDateTime which should
 247  *   be freed with gst_date_time_unref().
 248  *
 249  * Since: 0.10.31
 250  */
 251 
 252 
 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))
 259 
 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 */
 263 #ifdef HAVE_OSX
 264 #undef GLIB_HAS_GDATETIME
 265 #endif
 266 
 267 
 268 #ifndef GLIB_HAS_GDATETIME
 269 
 270 #define MAX_SUPPORTED_YEAR 9999
 271 #define GREGORIAN_LEAP(y)  (((y%4)==0)&&(!(((y%100)==0)&&((y%400)!=0))))
 272 
 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}
 276 };
 277 
 278 struct _GstDateTime
 279 {
 280   /*
 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).
 283    *
 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)
 286    */
 287   gint16 year;
 288   gint8 month;
 289   gint8 day;
 290   guint64 usec;                 /* Microsecond timekeeping within Day */
 291 
 292   gint tzoffset;
 293 
 294   volatile gint ref_count;
 295 };
 296 
 297 /*
 298  * Returns the utc offset in seconds for this time structure
 299  */
 300 static gint
 301 gmt_offset (struct tm *tm, time_t t)
 302 {
 303 #if defined (HAVE_TM_GMTOFF)
 304   return tm->tm_gmtoff;
 305 #else
 306   struct tm g;
 307   time_t t2;
 308 #ifdef HAVE_GMTIME_R
 309   gmtime_r (&t, &g);
 310 #else
 311   g = *gmtime (&t);
 312 #endif
 313   t2 = mktime (&g);
 314   return (int) difftime (t, t2);
 315 #endif
 316 }
 317 
 318 static void
 319 gst_date_time_set_local_timezone (GstDateTime * dt)
 320 {
 321   struct tm tt;
 322   time_t t;
 323 
 324   g_return_if_fail (dt != NULL);
 325 
 326   memset (&tt, 0, sizeof (tt));
 327 
 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);
 334 
 335   t = mktime (&tt);
 336 
 337   dt->tzoffset = gmt_offset (&tt, t) / 60;
 338 }
 339 
 340 static GstDateTime *
 341 gst_date_time_alloc (void)
 342 {
 343   GstDateTime *datetime;
 344 
 345   datetime = g_slice_new0 (GstDateTime);
 346   datetime->ref_count = 1;
 347 
 348   return datetime;
 349 }
 350 
 351 static void
 352 gst_date_time_free (GstDateTime * datetime)
 353 {
 354   g_slice_free (GstDateTime, datetime);
 355 }
 356 
 357 static GstDateTime *
 358 gst_date_time_new_from_date (gint year, gint month, gint day)
 359 {
 360   GstDateTime *dt;
 361 
 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);
 365 
 366   dt = gst_date_time_alloc ();
 367 
 368   dt->year = year;
 369   dt->month = month;
 370   dt->day = day;
 371   gst_date_time_set_local_timezone (dt);
 372 
 373   return dt;
 374 }
 375 
 376 gint
 377 gst_date_time_get_year (const GstDateTime * datetime)
 378 {
 379   g_return_val_if_fail (datetime != NULL, 0);
 380 
 381   return datetime->year;
 382 }
 383 
 384 gint
 385 gst_date_time_get_month (const GstDateTime * datetime)
 386 {
 387   g_return_val_if_fail (datetime != NULL, 0);
 388 
 389   return datetime->month;
 390 }
 391 
 392 gint
 393 gst_date_time_get_day (const GstDateTime * datetime)
 394 {
 395   g_return_val_if_fail (datetime != NULL, 0);
 396 
 397   return datetime->day;
 398 }
 399 
 400 gint
 401 gst_date_time_get_hour (const GstDateTime * datetime)
 402 {
 403   g_return_val_if_fail (datetime != NULL, 0);
 404   return (datetime->usec / GST_DATE_TIME_USEC_PER_HOUR);
 405 }
 406 
 407 gint
 408 gst_date_time_get_microsecond (const GstDateTime * datetime)
 409 {
 410   g_return_val_if_fail (datetime != NULL, 0);
 411   return (datetime->usec % GST_DATE_TIME_USEC_PER_SECOND);
 412 }
 413 
 414 gint
 415 gst_date_time_get_minute (const GstDateTime * datetime)
 416 {
 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;
 420 }
 421 
 422 gint
 423 gst_date_time_get_second (const GstDateTime * datetime)
 424 {
 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;
 428 }
 429 
 430 gfloat
 431 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
 432 {
 433   g_return_val_if_fail (datetime != NULL, 0);
 434 
 435   return datetime->tzoffset / 60.0f;
 436 }
 437 
 438 GstDateTime *
 439 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
 440 {
 441   GstDateTime *dt;
 442   struct tm tm;
 443   time_t tt;
 444 
 445   memset (&tm, 0, sizeof (tm));
 446   tt = (time_t) secs;
 447 
 448 #ifdef HAVE_LOCALTIME_R
 449   localtime_r (&tt, &tm);
 450 #else
 451   memcpy (&tm, localtime (&tt), sizeof (struct tm));
 452 #endif
 453 
 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);
 457   return dt;
 458 }
 459 
 460 GstDateTime *
 461 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
 462 {
 463   GstDateTime *dt;
 464   struct tm tm;
 465   time_t tt;
 466 
 467   memset (&tm, 0, sizeof (tm));
 468   tt = (time_t) secs;
 469 
 470 #ifdef HAVE_GMTIME_R
 471   gmtime_r (&tt, &tm);
 472 #else
 473   memcpy (&tm, gmtime (&tt), sizeof (struct tm));
 474 #endif
 475 
 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);
 478   return dt;
 479 }
 480 
 481 GstDateTime *
 482 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
 483     gint minute, gdouble seconds)
 484 {
 485   GstDateTime *dt;
 486 
 487   dt = gst_date_time_new (0, year, month, day, hour, minute, seconds);
 488 
 489   gst_date_time_set_local_timezone (dt);
 490 
 491   return dt;
 492 }
 493 
 494 GstDateTime *
 495 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
 496     gint minute, gdouble seconds)
 497 {
 498   GstDateTime *dt;
 499 
 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);
 504 
 505   if (!(dt = gst_date_time_new_from_date (year, month, day)))
 506     return NULL;
 507 
 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));
 511 
 512   /* we store in minutes */
 513   dt->tzoffset = (gint) (tzoffset * 60.0);
 514 
 515   return dt;
 516 }
 517 
 518 GstDateTime *
 519 gst_date_time_new_now_local_time (void)
 520 {
 521   GstDateTime *datetime;
 522   GTimeVal tv;
 523   g_get_current_time (&tv);
 524 
 525   datetime = gst_date_time_new_from_unix_epoch_local_time (tv.tv_sec);
 526 #ifdef GSTREAMER_LITE
 527   if (datetime == NULL) {
 528     return NULL;
 529   }
 530 #endif // GSTREAMER_LITE
 531   datetime->usec += tv.tv_usec;
 532   gst_date_time_set_local_timezone (datetime);
 533   return datetime;
 534 }
 535 
 536 static GstDateTime *
 537 gst_date_time_copy (const GstDateTime * dt)
 538 {
 539   GstDateTime *copy = gst_date_time_alloc ();
 540 
 541   memcpy (copy, dt, sizeof (GstDateTime));
 542   copy->ref_count = 1;
 543 
 544   return copy;
 545 }
 546 
 547 static GstDateTime *
 548 gst_date_time_to_utc (const GstDateTime * dt)
 549 {
 550   GstDateTime *utc;
 551   gint64 usec;
 552   gint days;
 553   gint leap;
 554 
 555   g_return_val_if_fail (dt != NULL, NULL);
 556 
 557   utc = gst_date_time_copy (dt);
 558 
 559   usec = dt->usec - dt->tzoffset * GST_DATE_TIME_USEC_PER_MINUTE;
 560   days = usec / GST_DATE_TIME_USEC_PER_DAY;
 561   if (usec < 0)
 562     days--;
 563   utc->day += days;
 564 
 565   leap = GREGORIAN_LEAP (utc->year) ? 1 : 0;
 566 
 567   /* check if we should update month/year */
 568   if (utc->day < 1) {
 569     if (utc->month == 1) {
 570       utc->year--;
 571       utc->month = 12;
 572     } else {
 573       utc->month--;
 574     }
 575     if (GREGORIAN_LEAP (utc->year))
 576       utc->day = days_in_months[1][utc->month];
 577     else
 578       utc->day = days_in_months[0][utc->month];
 579   } else if (utc->day > days_in_months[leap][utc->month]) {
 580     if (utc->month == 12) {
 581       utc->year++;
 582       utc->month = 1;
 583     } else {
 584       utc->month++;
 585     }
 586     utc->day = 1;
 587   }
 588 
 589   if (usec < 0)
 590     utc->usec =
 591         GST_DATE_TIME_USEC_PER_DAY + (usec % GST_DATE_TIME_USEC_PER_DAY);
 592   else
 593     utc->usec = usec % GST_DATE_TIME_USEC_PER_DAY;
 594 
 595   return utc;
 596 }
 597 
 598 GstDateTime *
 599 gst_date_time_new_now_utc (void)
 600 {
 601   GstDateTime *now, *utc;
 602 
 603   now = gst_date_time_new_now_local_time ();
 604   utc = gst_date_time_to_utc (now);
 605   gst_date_time_unref (now);
 606   return utc;
 607 }
 608 
 609 gint
 610 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
 611 {
 612   GstDateTime *a, *b;
 613   gint res = 0;
 614 
 615   a = gst_date_time_to_utc (dt1);
 616   b = gst_date_time_to_utc (dt2);
 617 
 618 #define GST_DATE_TIME_COMPARE_VALUE(a,b,v)   \
 619   if ((a)->v > (b)->v) {                     \
 620     res = 1;                                 \
 621     goto done;                               \
 622   } else if ((a)->v < (b)->v) {              \
 623     res = -1;                                \
 624     goto done;                               \
 625   }
 626 
 627   GST_DATE_TIME_COMPARE_VALUE (a, b, year);
 628   GST_DATE_TIME_COMPARE_VALUE (a, b, month);
 629   GST_DATE_TIME_COMPARE_VALUE (a, b, day);
 630   GST_DATE_TIME_COMPARE_VALUE (a, b, usec);
 631 
 632 #undef GST_DATE_TIME_COMPARE_VALUE
 633 
 634 done:
 635   gst_date_time_unref (a);
 636   gst_date_time_unref (b);
 637   return res;
 638 }
 639 
 640 #else
 641 
 642 struct _GstDateTime
 643 {
 644   GDateTime *datetime;
 645 
 646   volatile gint ref_count;
 647 };
 648 
 649 static GstDateTime *
 650 gst_date_time_new_from_gdatetime (GDateTime * dt)
 651 {
 652   GstDateTime *gst_dt;
 653 
 654   if (!dt)
 655     return NULL;
 656 
 657   gst_dt = g_slice_new (GstDateTime);
 658   gst_dt->datetime = dt;
 659   gst_dt->ref_count = 1;
 660   return gst_dt;
 661 }
 662 
 663 gint
 664 gst_date_time_get_year (const GstDateTime * datetime)
 665 {
 666   return g_date_time_get_year (datetime->datetime);
 667 }
 668 
 669 gint
 670 gst_date_time_get_month (const GstDateTime * datetime)
 671 {
 672   return g_date_time_get_month (datetime->datetime);
 673 }
 674 
 675 gint
 676 gst_date_time_get_day (const GstDateTime * datetime)
 677 {
 678   return g_date_time_get_day_of_month (datetime->datetime);
 679 }
 680 
 681 gint
 682 gst_date_time_get_hour (const GstDateTime * datetime)
 683 {
 684   return g_date_time_get_hour (datetime->datetime);
 685 }
 686 
 687 gint
 688 gst_date_time_get_minute (const GstDateTime * datetime)
 689 {
 690   return g_date_time_get_minute (datetime->datetime);
 691 }
 692 
 693 gint
 694 gst_date_time_get_second (const GstDateTime * datetime)
 695 {
 696   return g_date_time_get_second (datetime->datetime);
 697 }
 698 
 699 gint
 700 gst_date_time_get_microsecond (const GstDateTime * datetime)
 701 {
 702   return g_date_time_get_microsecond (datetime->datetime);
 703 }
 704 
 705 gfloat
 706 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
 707 {
 708   return (g_date_time_get_utc_offset (datetime->datetime) /
 709       G_USEC_PER_SEC) / 3600.0;
 710 }
 711 
 712 GstDateTime *
 713 gst_date_time_new_from_unix_epoch_local_time (gint64 secs)
 714 {
 715   return
 716       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_local (secs));
 717 }
 718 
 719 GstDateTime *
 720 gst_date_time_new_from_unix_epoch_utc (gint64 secs)
 721 {
 722   return
 723       gst_date_time_new_from_gdatetime (g_date_time_new_from_unix_utc (secs));
 724 }
 725 
 726 GstDateTime *
 727 gst_date_time_new_local_time (gint year, gint month, gint day, gint hour,
 728     gint minute, gdouble seconds)
 729 {
 730   return gst_date_time_new_from_gdatetime (g_date_time_new_local (year, month,
 731           day, hour, minute, seconds));
 732 }
 733 
 734 GstDateTime *
 735 gst_date_time_new_now_local_time (void)
 736 {
 737   return gst_date_time_new_from_gdatetime (g_date_time_new_now_local ());
 738 }
 739 
 740 GstDateTime *
 741 gst_date_time_new_now_utc (void)
 742 {
 743   return gst_date_time_new_from_gdatetime (g_date_time_new_now_utc ());
 744 }
 745 
 746 gint
 747 priv_gst_date_time_compare (gconstpointer dt1, gconstpointer dt2)
 748 {
 749   const GstDateTime *datetime1 = dt1;
 750   const GstDateTime *datetime2 = dt2;
 751   return g_date_time_compare (datetime1->datetime, datetime2->datetime);
 752 }
 753 
 754 GstDateTime *
 755 gst_date_time_new (gfloat tzoffset, gint year, gint month, gint day, gint hour,
 756     gint minute, gdouble seconds)
 757 {
 758   gchar buf[6];
 759   GTimeZone *tz;
 760   GDateTime *dt;
 761   gint tzhour, tzminute;
 762 
 763   tzhour = (gint) ABS (tzoffset);
 764   tzminute = (gint) ((ABS (tzoffset) - tzhour) * 60);
 765 
 766   g_snprintf (buf, 6, "%c%02d%02d", tzoffset >= 0 ? '+' : '-', tzhour,
 767       tzminute);
 768 
 769   tz = g_time_zone_new (buf);
 770 
 771   dt = g_date_time_new (tz, year, month, day, hour, minute, seconds);
 772   g_time_zone_unref (tz);
 773   return gst_date_time_new_from_gdatetime (dt);
 774 }
 775 
 776 static void
 777 gst_date_time_free (GstDateTime * datetime)
 778 {
 779   g_date_time_unref (datetime->datetime);
 780   g_slice_free (GstDateTime, datetime);
 781 }
 782 
 783 #endif
 784 
 785 /**
 786  * gst_date_time_ref:
 787  * @datetime: a #GstDateTime
 788  *
 789  * Atomically increments the reference count of @datetime by one.
 790  *
 791  * Return value: (transfer full): the reference @datetime
 792  *
 793  * Since: 0.10.31
 794  */
 795 GstDateTime *
 796 gst_date_time_ref (GstDateTime * datetime)
 797 {
 798   g_return_val_if_fail (datetime != NULL, NULL);
 799   g_return_val_if_fail (datetime->ref_count > 0, NULL);
 800   g_atomic_int_inc (&datetime->ref_count);
 801   return datetime;
 802 }
 803 
 804 /**
 805  * gst_date_time_unref:
 806  * @datetime: (transfer full): a #GstDateTime
 807  *
 808  * Atomically decrements the reference count of @datetime by one.  When the
 809  * reference count reaches zero, the structure is freed.
 810  *
 811  * Since: 0.10.31
 812  */
 813 void
 814 gst_date_time_unref (GstDateTime * datetime)
 815 {
 816   g_return_if_fail (datetime != NULL);
 817   g_return_if_fail (datetime->ref_count > 0);
 818 
 819   if (g_atomic_int_dec_and_test (&datetime->ref_count))
 820     gst_date_time_free (datetime);
 821 }