# HG changeset patch
# Node ID 578de5ccc292
# Parent  452ba49e16d4
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -54,6 +54,7 @@
 	'purpleconversationuiops.c',
 	'purplecredentialmanager.c',
 	'purplecredentialprovider.c',
+	'purpledatetime.c',
 	'purpledebugui.c',
 	'purplefiletransfer.c',
 	'purplefiletransfermanager.c',
@@ -178,6 +179,7 @@
 	'purpleconversationuiops.h',
 	'purplecredentialmanager.h',
 	'purplecredentialprovider.h',
+	'purpledatetime.h',
 	'purpledebugui.h',
 	'purplefiletransfer.h',
 	'purplefiletransfermanager.h',
diff --git a/libpurple/purpledatetime.h b/libpurple/purpledatetime.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purpledatetime.h
@@ -0,0 +1,74 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_DATE_TIME_H
+#define PURPLE_DATE_TIME_H
+
+#include <glib.h>
+
+#include "purpleversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * purple_date_time_set:
+ * @datetime_ptr: (inout) (not optional) (nullable): A pointer to a [type@GLib.DateTime] reference.
+ * @new_datetime: (nullable) (transfer none): The new date time to set.
+ *
+ * Updates @datetime_ptr to point to @new_datetime.
+ *
+ * If @datetime_ptr had a previous reference, it will be un-referenced.
+ *
+ * If @new_datetime is not %NULL, a new reference will be added when it is
+ * assigned to @datetime_ptr.
+ *
+ * @datetime_ptr can not be %NULL but may point to a %NULL value.
+ *
+ * Returns: %TRUE if the value of @datetime_ptr changed, otherwise %FALSE.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+gboolean purple_date_time_set(GDateTime **datetime_ptr, GDateTime *new_datetime);
+
+/**
+ * purple_date_time_clear:
+ * @datetime_ptr: A pointer to a [type@GLib.DateTime] reference.
+ *
+ * Clears a reference to a [type@GLib.DateTime].
+ *
+ * If the reference is %NULL, this function does nothing. Otherwise, the
+ * reference count of the [type@GLib.DateTime] is decreased and the pointer is
+ * set to %NULL.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_date_time_clear(GDateTime **datetime_ptr);
+
+G_END_DECLS
+
+#endif /* PURPLE_DATE_TIME_H */
diff --git a/libpurple/purpledatetime.c b/libpurple/purpledatetime.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purpledatetime.c
@@ -0,0 +1,61 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purpledatetime.h"
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+gboolean
+purple_date_time_set(GDateTime **datetime_ptr, GDateTime *new_datetime) {
+	GDateTime *old = NULL;
+
+	g_return_val_if_fail(datetime_ptr != NULL, FALSE);
+
+	old = *datetime_ptr;
+
+	if(old == new_datetime) {
+		return FALSE;
+	}
+
+	if(old != NULL) {
+		g_date_time_unref(old);
+	}
+
+	if(new_datetime != NULL) {
+		*datetime_ptr = g_date_time_ref(new_datetime);
+	} else {
+		*datetime_ptr = NULL;
+	}
+
+	return TRUE;
+}
+
+void
+purple_date_time_clear(GDateTime **datetime_ptr) {
+	if(datetime_ptr == NULL || *datetime_ptr == NULL) {
+		return;
+	}
+
+	g_date_time_unref(*datetime_ptr);
+	*datetime_ptr = NULL;
+}
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -12,6 +12,7 @@
     'conversation_member',
     'credential_manager',
     'credential_provider',
+    'date_time',
     'file_transfer',
     'file_transfer_manager',
     'history_adapter',
diff --git a/libpurple/tests/test_date_time.c b/libpurple/tests/test_date_time.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_date_time.c
@@ -0,0 +1,126 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <purple.h>
+
+/******************************************************************************
+ * set tests
+ *****************************************************************************/
+static void
+test_purple_date_time_set_null_null(void) {
+	GDateTime *dt = NULL;
+	g_assert_false(purple_date_time_set(&dt, NULL));
+}
+
+static void
+test_purple_date_time_set_null_nonnull(void) {
+	GDateTime *dt = NULL;
+	GDateTime *dt1 = NULL;
+	gboolean ret = FALSE;
+
+	dt1 = g_date_time_new_now_utc();
+	ret = purple_date_time_set(&dt, dt1);
+	g_assert_true(ret);
+
+	g_assert_true(dt == dt1);
+
+	g_clear_pointer(&dt, g_date_time_unref);
+	g_clear_pointer(&dt1, g_date_time_unref);
+}
+
+static void
+test_purple_date_time_set_nonnull_null(void) {
+	GDateTime *dt = NULL;
+	gboolean ret = FALSE;
+
+	dt = g_date_time_new_now_utc();
+	ret = purple_date_time_set(&dt, NULL);
+	g_assert_true(ret);
+
+	g_assert_null(dt);
+}
+
+static void
+test_purple_date_time_set_nonnull_nonnull(void) {
+	GDateTime *tmp = NULL;
+	GDateTime *dt = NULL;
+	GDateTime *dt1 = NULL;
+	gboolean ret = FALSE;
+
+	/* We push our existing time back 2 hours to avoid issues with day light
+	 * savings time and other weird clock skew issues.
+	 */
+	tmp = g_date_time_new_now_utc();
+	dt = g_date_time_add_hours(tmp, -2);
+	g_clear_pointer(&tmp, g_date_time_unref);
+
+	dt1 = g_date_time_new_now_utc();
+
+	ret = purple_date_time_set(&dt, dt1);
+	g_assert_true(ret);
+
+	g_assert_true(dt == dt1);
+
+	g_clear_pointer(&dt, g_date_time_unref);
+	g_clear_pointer(&dt1, g_date_time_unref);
+}
+
+/******************************************************************************
+ * clear tests
+ *****************************************************************************/
+static void
+test_purple_date_time_clear_null(void) {
+	GDateTime *dt = NULL;
+
+	purple_date_time_clear(NULL);
+	purple_date_time_clear(&dt);
+
+	g_assert_null(dt);
+}
+
+static void
+test_purple_date_time_clear_nonnull(void) {
+	GDateTime *dt = g_date_time_new_now_utc();
+
+	purple_date_time_clear(&dt);
+
+	g_assert_null(dt);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/date-time/set/null-null",
+	                test_purple_date_time_set_null_null);
+	g_test_add_func("/date-time/set/null-nonnull",
+	                test_purple_date_time_set_null_nonnull);
+	g_test_add_func("/date-time/set/nonnull-null",
+	                test_purple_date_time_set_nonnull_null);
+	g_test_add_func("/date-time/set/nonnull-nonnull",
+	                test_purple_date_time_set_nonnull_nonnull);
+
+	g_test_add_func("/date-time/clear/null", test_purple_date_time_clear_null);
+	g_test_add_func("/date-time/clear/nonnull",
+	                test_purple_date_time_clear_nonnull);
+
+	return g_test_run();
+}
