Add purple_str_to_date_time.

Tue, 11 Jul 2017 05:27:50 -0400

author
Elliott Sales de Andrade <qulogic@pidgin.im>
date
Tue, 11 Jul 2017 05:27:50 -0400
changeset 38619
2121337626ee
parent 38582
878de3ba891b
child 38620
b02941b9fa9a

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", &microseconds, &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/

mercurial