From aeb039863d2962dcffa60823d9afab2c39c8d8fc Mon Sep 17 00:00:00 2001
From: Alexander Belopolsky <alexander.belopolsky@gmail.com>
Date: Mon, 26 Jul 2010 02:36:41 +0000
Subject: Make python version of fromtimestamp behave more like C.

---
 Lib/datetime.py            | 22 +++++++++++++---------
 Lib/test/datetimetester.py |  8 +++++++-
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/Lib/datetime.py b/Lib/datetime.py
index 19f20e7..23ded3e 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -1356,16 +1356,20 @@ class datetime(date):
         """
 
         _check_tzinfo_arg(tz)
-        if tz is None:
-            converter = _time.localtime
-        else:
-            converter = _time.gmtime
-        if 1 - (t % 1.0) < 0.000001:
-            t = float(int(t)) + 1
-        if t < 0:
-            t -= 1
+
+        converter = _time.localtime if tz is None else _time.gmtime
+
+        t, frac = divmod(t, 1.0)
+        us = round(frac * 1e6)
+
+        # If timestamp is less than one microsecond smaller than a
+        # full second, us can be rounded up to 1000000.  In this case,
+        # roll over to seconds, otherwise, ValueError is raised
+        # by the constructor.
+        if us == 1000000:
+            t += 1
+            us = 0
         y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
-        us = int((t % 1.0) * 1000000)
         ss = min(ss, 59)    # clamp out leap seconds if the platform has them
         result = cls(y, m, d, hh, mm, ss, us, tz)
         if tz is not None:
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 8be72a4..8dd0326 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -1728,9 +1728,15 @@ class TestDateTime(TestDate):
 
     def test_microsecond_rounding(self):
         # Test whether fromtimestamp "rounds up" floats that are less
-        # than one microsecond smaller than an integer.
+        # than 1/2 microsecond smaller than an integer.
         self.assertEqual(self.theclass.fromtimestamp(0.9999999),
                          self.theclass.fromtimestamp(1))
+        self.assertEqual(self.theclass.fromtimestamp(0.99999949).microsecond,
+                         999999)
+        # XXX Arguably incorrect behavior.  Since round(0.6112295, 6)
+        # returns 0.611229, we should see 611229 us below, not 611230
+        self.assertEqual(self.theclass.fromtimestamp(0.6112295).microsecond,
+                         611230)
 
     def test_insane_fromtimestamp(self):
         # It's possible that some platform maps time_t to double,
-- 
cgit v0.12