[glib] gdatetime: fix floating-point conversion
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] gdatetime: fix floating-point conversion
- Date: Thu, 16 Nov 2017 11:07:44 +0000 (UTC)
commit 3cfac71d09dded67485f153fa76d6f063dbb6a76
Author: David Schleef <ds schleef org>
Date: Sat Apr 13 11:26:34 2013 -0700
gdatetime: fix floating-point conversion
Conversion from floating point to integer requires special care.
https://bugzilla.gnome.org/show_bug.cgi?id=697715
glib/gdatetime.c | 13 ++++++++++++-
glib/tests/gdatetime.c | 16 ++++++++++++++++
2 files changed, 28 insertions(+), 1 deletions(-)
---
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index e1c7260..045c578 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -1295,6 +1295,7 @@ g_date_time_new (GTimeZone *tz,
{
GDateTime *datetime;
gint64 full_time;
+ gint64 usec;
g_return_val_if_fail (tz != NULL, NULL);
@@ -1322,10 +1323,20 @@ g_date_time_new (GTimeZone *tz,
G_TIME_TYPE_STANDARD,
&full_time);
+ /* This is the correct way to convert a scaled FP value to integer.
+ * If this surprises you, please observe that (int)(1.000001 * 1e6)
+ * is 1000000. This is not a problem with precision, it's just how
+ * FP numbers work.
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=697715. */
+ usec = seconds * USEC_PER_SECOND;
+ if ((usec + 1) * 1e-6 <= seconds) {
+ usec++;
+ }
+
full_time += UNIX_EPOCH_START * SEC_PER_DAY;
datetime->days = full_time / SEC_PER_DAY;
datetime->usec = (full_time % SEC_PER_DAY) * USEC_PER_SECOND;
- datetime->usec += ((int) (seconds * USEC_PER_SECOND)) % USEC_PER_SECOND;
+ datetime->usec += usec % USEC_PER_SECOND;
return datetime;
}
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index f13b9de..03a7935 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -2083,6 +2083,21 @@ test_posix_parse (void)
g_time_zone_unref (tz);
}
+static void
+test_GDateTime_floating_point (void)
+{
+ GDateTime *dt;
+ GTimeZone *tz;
+
+ g_test_bug ("697715");
+
+ tz = g_time_zone_new ("-03:00");
+ dt = g_date_time_new (tz, 2010, 5, 24, 8, 0, 1.000001);
+ g_time_zone_unref (tz);
+ g_assert_cmpint (g_date_time_get_microsecond (dt), ==, 1);
+ g_date_time_unref (dt);
+}
+
gint
main (gint argc,
gchar *argv[])
@@ -2140,6 +2155,7 @@ main (gint argc,
g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time);
g_test_add_func ("/GTimeZone/no-header", test_no_header);
g_test_add_func ("/GTimeZone/posix-parse", test_posix_parse);
+ g_test_add_func ("/GTimeZone/floating-point", test_GDateTime_floating_point);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]