gdatetime: fix floating-point conversion

Conversion from floating point to integer requires special care.

https://bugzilla.gnome.org/show_bug.cgi?id=697715
This commit is contained in:
David Schleef 2013-04-13 11:26:34 -07:00 committed by Philip Withnall
parent b5733ecc76
commit 3cfac71d09
2 changed files with 28 additions and 1 deletions

View File

@ -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;
}

View File

@ -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 ();
}