Tue, 11 Jul 2017 05:27:50 -0400
Add purple_str_to_date_time.
It is similar to purple_str_to_time, but produces a GDateTime and
doesn't return the extra trailing text (which will not be used.)
| libpurple/tests/test_util.c | file | annotate | diff | comparison | revisions | |
| libpurple/util.c | file | annotate | diff | comparison | revisions | |
| libpurple/util.h | file | annotate | diff | comparison | revisions |
--- a/libpurple/tests/test_util.c Mon Jul 10 07:01:04 2017 +0000 +++ b/libpurple/tests/test_util.c Tue Jul 11 05:27:50 2017 -0400 @@ -199,6 +199,34 @@ } /****************************************************************************** + * str_to_date_time tests + *****************************************************************************/ +static void +test_util_str_to_date_time(void) +{ + GDateTime *dt; + + dt = purple_str_to_date_time("19811214T12:50:00", TRUE); + g_assert_cmpint(377182200, ==, g_date_time_to_unix(dt)); + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt)); + g_date_time_unref(dt); + + dt = purple_str_to_date_time("20070407T04:14:21", TRUE); + g_assert_cmpint(1175919261, ==, g_date_time_to_unix(dt)); + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt)); + g_date_time_unref(dt); + + dt = purple_str_to_date_time("2010-08-27.204202", TRUE); + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt)); + g_assert_cmpint(0, ==, g_date_time_get_utc_offset(dt)); + g_date_time_unref(dt); + + dt = purple_str_to_date_time("2010-08-27.134202-0700PDT", FALSE); + g_assert_cmpint(1282941722, ==, g_date_time_to_unix(dt)); + g_assert_cmpint((-7LL * 60 * 60 * G_USEC_PER_SEC), ==, g_date_time_get_utc_offset(dt)); +} + +/****************************************************************************** * Markup tests *****************************************************************************/ typedef struct { @@ -515,6 +543,9 @@ g_test_add_func("/util/str to time", test_util_str_to_time); + g_test_add_func("/util/str to date time", + test_util_str_to_date_time); + g_test_add_func("/util/markup/html to xhtml", test_util_markup_html_to_xhtml);
--- a/libpurple/util.c Mon Jul 10 07:01:04 2017 +0000 +++ b/libpurple/util.c Tue Jul 11 05:27:50 2017 -0400 @@ -888,6 +888,139 @@ return retval; } +GDateTime * +purple_str_to_date_time(const char *timestamp, gboolean utc) +{ + const gchar *str; + gint year = 0; + gint month = 0; + gint day = 0; + gint hour = 0; + gint minute = 0; + gint seconds = 0; + gint microseconds = 0; + GTimeZone *tz = NULL; + GDateTime *retval; + + g_return_val_if_fail(timestamp != NULL, NULL); + + str = timestamp; + + /* Strip leading whitespace */ + while (g_ascii_isspace(*str)) + str++; + + if (*str == '\0') { + return NULL; + } + + if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') { + return NULL; + } + + /* 4 digit year */ + if (sscanf(str, "%04d", &year) && year > 0) { + str += 4; + + if (*str == '-' || *str == '/') + str++; + } + + /* 2 digit month */ + if (!sscanf(str, "%02d", &month)) { + return NULL; + } + + str += 2; + + if (*str == '-' || *str == '/') + str++; + + /* 2 digit day */ + if (!sscanf(str, "%02d", &day)) { + return NULL; + } + + str += 2; + + /* Grab the year off the end if there's still stuff */ + if (*str == '/' || *str == '-') { + /* But make sure we don't read the year twice */ + if (year > 0) { + return NULL; + } + + str++; + + if (!sscanf(str, "%04d", &year)) { + return NULL; + } + } else if (*str == 'T' || *str == '.') { + str++; + + /* Continue grabbing the hours/minutes/seconds */ + if ((sscanf(str, "%02d:%02d:%02d", &hour, &minute, &seconds) == 3 && + (str += 8)) || + (sscanf(str, "%02d%02d%02d", &hour, &minute, &seconds) == 3 && + (str += 6))) + { + if (*str == '.') { + int chars = 0; + str++; + if (sscanf(str, "%d%n", µseconds, &chars) == 2) { + str += chars; + chars -= 6; + if (chars < 0) { + while (chars++) { + microseconds *= 10; + } + } else { + while (chars--) { + microseconds /= 10; + } + } + } + } + + if (*str) { + const gchar *end = str; + if (*end == '+' || *end == '-') { + end++; + } + + while (isdigit(*end) || *end == ':') { + end++; + } + + if (str != end) { + /* Trim anything trailing a purely numeric time zone. */ + gchar *tzstr = g_strndup(str, end - str); + tz = g_time_zone_new(tzstr); + g_free(tzstr); + } else { + /* Just try whatever is there. */ + tz = g_time_zone_new(str); + } + } + } + } + + if (!tz) { + /* No timezone specified. */ + if (utc) { + tz = g_time_zone_new_utc(); + } else { + tz = g_time_zone_new_local(); + } + } + + retval = g_date_time_new(tz, year, month, day, hour, minute, + seconds + microseconds / 1e6); + g_time_zone_unref(tz); + + return retval; +} + char * purple_uts35_to_str(const char *format, size_t len, struct tm *tm) {
--- a/libpurple/util.h Mon Jul 10 07:01:04 2017 +0000 +++ b/libpurple/util.h Tue Jul 11 05:27:50 2017 -0400 @@ -482,6 +482,18 @@ struct tm *tm, long *tz_off, const char **rest); /** + * purple_str_to_date_time: + * @timestamp: The timestamp + * @utc: Assume UTC if no timezone specified + * + * Parses a timestamp in jabber, ISO8601, or MM/DD/YYYY format and returns + * a GDateTime. + * + * Returns: (transfer full): A GDateTime. + */ +GDateTime *purple_str_to_date_time(const char *timestamp, gboolean utc); + +/** * purple_uts35_to_str: * @format: The formatting string, according to UTS \#35 * See http://unicode.org/reports/tr35/