datetime: accept just a time as ISO 8601 string and use today's date then

If no date and only a time is given in gst_date_time_new_from_iso8601_string(),
assume that it is "today" and try to parse the time-only string. "Today" is
assumed to be in the timezone provided by the user (if any), otherwise Z -
just like the behavior of the existing code.

https://bugzilla.gnome.org/show_bug.cgi?id=753455
This commit is contained in:
Vivia Nikolaidou 2015-08-10 15:31:37 +03:00 committed by Tim-Philipp Müller
parent 28100e0b6a
commit 88f6334af6
2 changed files with 140 additions and 33 deletions

View file

@ -748,7 +748,13 @@ gst_date_time_to_iso8601_string (GstDateTime * datetime)
* @string: ISO 8601-formatted datetime string.
*
* Tries to parse common variants of ISO-8601 datetime strings into a
* #GstDateTime.
* #GstDateTime. Possible input formats are (for example):
* 2012-06-30T22:46:43Z, 2012, 2012-06, 2012-06-30, 2012-06-30T22:46:43-0430,
* 2012-06-30T22:46Z, 2012-06-30T22:46-0430, 2012-06-30 22:46,
* 2012-06-30 22:46:43, 2012-06-00, 2012-00-00, 2012-00-30, 22:46:43Z, 22:46Z,
* 22:46:43-0430, 22:46-0430, 22:46:30, 22:46
* If no date is provided, it is assumed to be "today" in the timezone
* provided (if any), otherwise UTC.
*
* Free-function: gst_date_time_unref
*
@ -759,6 +765,7 @@ GstDateTime *
gst_date_time_new_from_iso8601_string (const gchar * string)
{
gint year = -1, month = -1, day = -1, hour = -1, minute = -1;
gint gmt_offset_hour = -99, gmt_offset_min = -99;
gdouble second = -1.0;
gfloat tzoffset = 0.0;
guint64 usecs;
@ -770,40 +777,45 @@ gst_date_time_new_from_iso8601_string (const gchar * string)
len = strlen (string);
if (len < 4 || !g_ascii_isdigit (string[0]) || !g_ascii_isdigit (string[1])
|| !g_ascii_isdigit (string[2]) || !g_ascii_isdigit (string[3]))
/* The input string is expected to start either with a year (4 digits) or
* with an hour (2 digits). Hour must be followed by minute. In any case,
* the string must be at least 4 characters long and start with 2 digits */
if (len < 4 || !g_ascii_isdigit (string[0]) || !g_ascii_isdigit (string[1]))
return NULL;
ret = sscanf (string, "%04d-%02d-%02d", &year, &month, &day);
if (g_ascii_isdigit (string[2]) && g_ascii_isdigit (string[3])) {
ret = sscanf (string, "%04d-%02d-%02d", &year, &month, &day);
if (ret == 0)
return NULL;
if (ret == 0)
return NULL;
if (ret == 3 && day <= 0) {
ret = 2;
day = -1;
if (ret == 3 && day <= 0) {
ret = 2;
day = -1;
}
if (ret >= 2 && month <= 0) {
ret = 1;
month = day = -1;
}
if (ret >= 1 && year <= 0)
return NULL;
else if (ret >= 1 && len < 16)
/* YMD is 10 chars. XMD + HM will be 16 chars. if it is less,
* it make no sense to continue. We will stay with YMD. */
goto ymd;
string += 10;
/* Exit if there is no expeceted value on this stage */
if (!(*string == 'T' || *string == '-' || *string == ' '))
goto ymd;
string += 1;
}
if (ret >= 2 && month <= 0) {
ret = 1;
month = day = -1;
}
if (ret >= 1 && year <= 0)
return NULL;
else if (ret >= 1 && len < 16)
/* YMD is 10 chars. XMD + HM will be 16 chars. if it is less,
* it make no sense to continue. We will stay with YMD. */
goto ymd;
string += 10;
/* Exit if there is no expeceted value on this stage */
if (!(*string == 'T' || *string == '-' || *string == ' '))
goto ymd;
/* if hour or minute fails, then we will use onlly ymd. */
hour = g_ascii_strtoull (string + 1, (gchar **) & string, 10);
/* if hour or minute fails, then we will use only ymd. */
hour = g_ascii_strtoull (string, (gchar **) & string, 10);
if (hour > 24 || *string != ':')
goto ymd;
@ -838,7 +850,7 @@ gst_date_time_new_from_iso8601_string (const gchar * string)
goto ymd_hms;
else {
/* reuse some code from gst-plugins-base/gst-libs/gst/tag/gstxmptag.c */
gint gmt_offset_hour = -1, gmt_offset_min = -1, gmt_offset = -1;
gint gmt_offset = -1;
gchar *plus_pos = NULL;
gchar *neg_pos = NULL;
gchar *pos = NULL;
@ -863,9 +875,11 @@ gst_date_time_new_from_iso8601_string (const gchar * string)
GST_DEBUG ("Parsing timezone: %s", pos);
if (ret_tz == 2) {
if (neg_pos != NULL && neg_pos + 1 == pos) {
gmt_offset_hour *= -1;
gmt_offset_min *= -1;
}
gmt_offset = gmt_offset_hour * 60 + gmt_offset_min;
if (neg_pos != NULL && neg_pos + 1 == pos)
gmt_offset *= -1;
tzoffset = gmt_offset / 60.0;
@ -876,8 +890,31 @@ gst_date_time_new_from_iso8601_string (const gchar * string)
}
ymd_hms:
if (year == -1 || month == -1 || day == -1) {
GDateTime *now_utc, *now_in_given_tz;
/* No date was supplied: make it today */
now_utc = g_date_time_new_now_utc ();
if (tzoffset != 0.0) {
/* If a timezone offset was supplied, get the date of that timezone */
g_assert (gmt_offset_min != -99);
g_assert (gmt_offset_hour != -99);
now_in_given_tz =
g_date_time_add_minutes (now_utc,
(60 * gmt_offset_hour) + gmt_offset_min);
g_date_time_unref (now_utc);
} else {
now_in_given_tz = now_utc;
}
g_date_time_get_ymd (now_in_given_tz, &year, &month, &day);
g_date_time_unref (now_in_given_tz);
}
return gst_date_time_new (tzoffset, year, month, day, hour, minute, second);
ymd:
if (year == -1) {
/* No date was supplied and time failed to parse */
return NULL;
}
return gst_date_time_new_ymd (year, month, day);
}

View file

@ -385,6 +385,7 @@ GST_START_TEST (test_GstDateTime_iso8601)
{
GstDateTime *dt, *dt2;
gchar *str, *str2;
GDateTime *gdt, *gdt2;
dt = gst_date_time_new_now_utc ();
fail_unless (gst_date_time_has_year (dt));
@ -632,6 +633,75 @@ GST_START_TEST (test_GstDateTime_iso8601)
fail_unless (!gst_date_time_has_day (dt));
fail_unless (!gst_date_time_has_time (dt));
gst_date_time_unref (dt);
/* only time provided - we assume today's date */
gdt = g_date_time_new_now_utc ();
dt = gst_date_time_new_from_iso8601_string ("15:50:33");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (gst_date_time_get_second (dt) == 33);
gst_date_time_unref (dt);
dt = gst_date_time_new_from_iso8601_string ("15:50:33Z");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (gst_date_time_get_second (dt) == 33);
gst_date_time_unref (dt);
dt = gst_date_time_new_from_iso8601_string ("15:50");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (!gst_date_time_has_second (dt));
gst_date_time_unref (dt);
dt = gst_date_time_new_from_iso8601_string ("15:50Z");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (!gst_date_time_has_second (dt));
gst_date_time_unref (dt);
gdt2 = g_date_time_add_minutes (gdt, -270);
g_date_time_unref (gdt);
dt = gst_date_time_new_from_iso8601_string ("15:50:33-0430");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt2));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt2));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt2));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (gst_date_time_get_second (dt) == 33);
gst_date_time_unref (dt);
dt = gst_date_time_new_from_iso8601_string ("15:50-0430");
fail_unless (gst_date_time_get_year (dt) == g_date_time_get_year (gdt2));
fail_unless (gst_date_time_get_month (dt) == g_date_time_get_month (gdt2));
fail_unless (gst_date_time_get_day (dt) ==
g_date_time_get_day_of_month (gdt2));
fail_unless (gst_date_time_get_hour (dt) == 15);
fail_unless (gst_date_time_get_minute (dt) == 50);
fail_unless (!gst_date_time_has_second (dt));
gst_date_time_unref (dt);
g_date_time_unref (gdt2);
}
GST_END_TEST;