diff --git a/python_datetime/datetime_timestamp_floating_point_behavior.py b/python_datetime/datetime_timestamp_floating_point_behavior.py new file mode 100644 index 0000000..9e136b3 --- /dev/null +++ b/python_datetime/datetime_timestamp_floating_point_behavior.py @@ -0,0 +1,86 @@ +"""Show datetime.datetime.timestamp() floating-point behavior. + +Please review the output of this code first, then look back here. + +* https://docs.python.org/3/library/datetime.html +* https://en.wikipedia.org/wiki/IEEE_754 +""" + +import datetime +import sys + + +def annotate_behavior(t_int, t_flt): + if int(t_flt) == t_int: + return "truncating" + if int(t_flt) == t_int + 1: + return "ROUNDING UP" + return "LOSSY" + + +def dt_strftime(dt): + return ("000" + dt.strftime("%Y-%m-%d %H:%M:%S.%f"))[-26:] + + +def run(args): + """Please review the output of this code first, then look back here.""" + + assert len(args) == 1, "sample_max_exponent (e.g. 53 for IEEE 754)" + + sample_max_exponent = int(args[0]) + + resolution_exponent = 6 + resolution_num = 10**resolution_exponent # 1000000 + resolution_nines = resolution_num - 1 # 999999 + resolution_nines_over_num = resolution_nines / resolution_num # 0.999999 + + tz_utc = datetime.timezone.utc + dt_min = datetime.datetime.min.replace(tzinfo=tz_utc) + dt_max = datetime.datetime.max.replace(tzinfo=tz_utc) + dt_min_t = dt_min.timestamp() + dt_max_t = dt_max.timestamp() + + print("datetime.min.timestamp()", dt_min_t, "", dt_strftime(dt_min)) + print("datetime.max.timestamp()", dt_max_t, "", dt_strftime(dt_max)) + print() + + print(" offset t_int t_int+0.999999") + + def print_mm(name, t, offset): + t_int = int(t) + offset + t_flt = t_int + resolution_nines_over_num + print( + f"{name} {offset:6} {t_int:13} {t_flt:15}" + f" {annotate_behavior(t_int, t_flt)}" + ) + + for offset in (0, 1): + print_mm("datetime.min", dt_min_t, offset) + for offset in (-1, 0): + print_mm("datetime.max", dt_max_t, offset) + print() + + print("2**e offset t_int t_int+0.999999") + t_int_done = set() + for exponent in range(sample_max_exponent + 1): + ip2 = 2**exponent + for offset in (-1, 0, 1): + t_int = ip2 + offset + if t_int in t_int_done: + continue + t_int_done.add(t_int) + t_flt = t_int + resolution_nines_over_num + if t_flt < dt_max_t: + dt_utc = datetime.datetime.fromtimestamp(t_int, tz=tz_utc) + dt_fmt = dt_strftime(dt_utc) + else: + dt_fmt = "out of datetime range" + print( + f"{exponent:4} {offset:6} {t_int:16} {t_flt:20}" + f" {annotate_behavior(t_int, t_flt):11} {dt_fmt}" + ) + print() + + +if __name__ == "__main__": + run(args=sys.argv[1:]) diff --git a/python_datetime/datetime_timestamp_floating_point_behavior_output.txt b/python_datetime/datetime_timestamp_floating_point_behavior_output.txt new file mode 100644 index 0000000..f07e94b --- /dev/null +++ b/python_datetime/datetime_timestamp_floating_point_behavior_output.txt @@ -0,0 +1,170 @@ +datetime.min.timestamp() -62135596800.0 0001-01-01 00:00:00.000000 +datetime.max.timestamp() 253402300800.0 9999-12-31 23:59:59.999999 + + offset t_int t_int+0.999999 +datetime.min 0 -62135596800 -62135596799.0 ROUNDING UP +datetime.min 1 -62135596799 -62135596798.0 ROUNDING UP +datetime.max -1 253402300799 253402300800.0 ROUNDING UP +datetime.max 0 253402300800 253402300801.0 ROUNDING UP + +2**e offset t_int t_int+0.999999 + 0 -1 0 0.999999 truncating 1970-01-01 00:00:00.000000 + 0 0 1 1.9999989999999999 truncating 1970-01-01 00:00:01.000000 + 0 1 2 2.999999 truncating 1970-01-01 00:00:02.000000 + 1 1 3 3.999999 truncating 1970-01-01 00:00:03.000000 + 2 0 4 4.999999 truncating 1970-01-01 00:00:04.000000 + 2 1 5 5.999999 truncating 1970-01-01 00:00:05.000000 + 3 -1 7 7.999999 truncating 1970-01-01 00:00:07.000000 + 3 0 8 8.999999 truncating 1970-01-01 00:00:08.000000 + 3 1 9 9.999999 truncating 1970-01-01 00:00:09.000000 + 4 -1 15 15.999999 truncating 1970-01-01 00:00:15.000000 + 4 0 16 16.999999 truncating 1970-01-01 00:00:16.000000 + 4 1 17 17.999999 truncating 1970-01-01 00:00:17.000000 + 5 -1 31 31.999999 truncating 1970-01-01 00:00:31.000000 + 5 0 32 32.999999 truncating 1970-01-01 00:00:32.000000 + 5 1 33 33.999999 truncating 1970-01-01 00:00:33.000000 + 6 -1 63 63.999999 truncating 1970-01-01 00:01:03.000000 + 6 0 64 64.999999 truncating 1970-01-01 00:01:04.000000 + 6 1 65 65.999999 truncating 1970-01-01 00:01:05.000000 + 7 -1 127 127.999999 truncating 1970-01-01 00:02:07.000000 + 7 0 128 128.999999 truncating 1970-01-01 00:02:08.000000 + 7 1 129 129.999999 truncating 1970-01-01 00:02:09.000000 + 8 -1 255 255.999999 truncating 1970-01-01 00:04:15.000000 + 8 0 256 256.999999 truncating 1970-01-01 00:04:16.000000 + 8 1 257 257.999999 truncating 1970-01-01 00:04:17.000000 + 9 -1 511 511.999999 truncating 1970-01-01 00:08:31.000000 + 9 0 512 512.999999 truncating 1970-01-01 00:08:32.000000 + 9 1 513 513.999999 truncating 1970-01-01 00:08:33.000000 + 10 -1 1023 1023.999999 truncating 1970-01-01 00:17:03.000000 + 10 0 1024 1024.999999 truncating 1970-01-01 00:17:04.000000 + 10 1 1025 1025.999999 truncating 1970-01-01 00:17:05.000000 + 11 -1 2047 2047.999999 truncating 1970-01-01 00:34:07.000000 + 11 0 2048 2048.999999 truncating 1970-01-01 00:34:08.000000 + 11 1 2049 2049.999999 truncating 1970-01-01 00:34:09.000000 + 12 -1 4095 4095.999999 truncating 1970-01-01 01:08:15.000000 + 12 0 4096 4096.999999 truncating 1970-01-01 01:08:16.000000 + 12 1 4097 4097.999999 truncating 1970-01-01 01:08:17.000000 + 13 -1 8191 8191.999999 truncating 1970-01-01 02:16:31.000000 + 13 0 8192 8192.999999 truncating 1970-01-01 02:16:32.000000 + 13 1 8193 8193.999999 truncating 1970-01-01 02:16:33.000000 + 14 -1 16383 16383.999999 truncating 1970-01-01 04:33:03.000000 + 14 0 16384 16384.999999 truncating 1970-01-01 04:33:04.000000 + 14 1 16385 16385.999999 truncating 1970-01-01 04:33:05.000000 + 15 -1 32767 32767.999999 truncating 1970-01-01 09:06:07.000000 + 15 0 32768 32768.999999 truncating 1970-01-01 09:06:08.000000 + 15 1 32769 32769.999999 truncating 1970-01-01 09:06:09.000000 + 16 -1 65535 65535.999999 truncating 1970-01-01 18:12:15.000000 + 16 0 65536 65536.999999 truncating 1970-01-01 18:12:16.000000 + 16 1 65537 65537.999999 truncating 1970-01-01 18:12:17.000000 + 17 -1 131071 131071.999999 truncating 1970-01-02 12:24:31.000000 + 17 0 131072 131072.999999 truncating 1970-01-02 12:24:32.000000 + 17 1 131073 131073.999999 truncating 1970-01-02 12:24:33.000000 + 18 -1 262143 262143.999999 truncating 1970-01-04 00:49:03.000000 + 18 0 262144 262144.999999 truncating 1970-01-04 00:49:04.000000 + 18 1 262145 262145.999999 truncating 1970-01-04 00:49:05.000000 + 19 -1 524287 524287.999999 truncating 1970-01-07 01:38:07.000000 + 19 0 524288 524288.999999 truncating 1970-01-07 01:38:08.000000 + 19 1 524289 524289.999999 truncating 1970-01-07 01:38:09.000000 + 20 -1 1048575 1048575.999999 truncating 1970-01-13 03:16:15.000000 + 20 0 1048576 1048576.999999 truncating 1970-01-13 03:16:16.000000 + 20 1 1048577 1048577.999999 truncating 1970-01-13 03:16:17.000000 + 21 -1 2097151 2097151.999999 truncating 1970-01-25 06:32:31.000000 + 21 0 2097152 2097152.999999 truncating 1970-01-25 06:32:32.000000 + 21 1 2097153 2097153.999999 truncating 1970-01-25 06:32:33.000000 + 22 -1 4194303 4194303.999999 truncating 1970-02-18 13:05:03.000000 + 22 0 4194304 4194304.999999 truncating 1970-02-18 13:05:04.000000 + 22 1 4194305 4194305.999999 truncating 1970-02-18 13:05:05.000000 + 23 -1 8388607 8388607.999999 truncating 1970-04-08 02:10:07.000000 + 23 0 8388608 8388608.999999 truncating 1970-04-08 02:10:08.000000 + 23 1 8388609 8388609.999999 truncating 1970-04-08 02:10:09.000000 + 24 -1 16777215 16777215.999999 truncating 1970-07-14 04:20:15.000000 + 24 0 16777216 16777216.999999 truncating 1970-07-14 04:20:16.000000 + 24 1 16777217 16777217.999999 truncating 1970-07-14 04:20:17.000000 + 25 -1 33554431 33554431.999999 truncating 1971-01-24 08:40:31.000000 + 25 0 33554432 33554432.999999 truncating 1971-01-24 08:40:32.000000 + 25 1 33554433 33554433.999999 truncating 1971-01-24 08:40:33.000000 + 26 -1 67108863 67108863.999999 truncating 1972-02-16 17:21:03.000000 + 26 0 67108864 67108864.999999 truncating 1972-02-16 17:21:04.000000 + 26 1 67108865 67108865.999999 truncating 1972-02-16 17:21:05.000000 + 27 -1 134217727 134217727.999999 truncating 1974-04-03 10:42:07.000000 + 27 0 134217728 134217728.999999 truncating 1974-04-03 10:42:08.000000 + 27 1 134217729 134217729.999999 truncating 1974-04-03 10:42:09.000000 + 28 -1 268435455 268435455.999999 truncating 1978-07-04 21:24:15.000000 + 28 0 268435456 268435456.999999 truncating 1978-07-04 21:24:16.000000 + 28 1 268435457 268435457.999999 truncating 1978-07-04 21:24:17.000000 + 29 -1 536870911 536870911.999999 truncating 1987-01-05 18:48:31.000000 + 29 0 536870912 536870912.999999 truncating 1987-01-05 18:48:32.000000 + 29 1 536870913 536870913.999999 truncating 1987-01-05 18:48:33.000000 + 30 -1 1073741823 1073741823.999999 truncating 2004-01-10 13:37:03.000000 + 30 0 1073741824 1073741824.999999 truncating 2004-01-10 13:37:04.000000 + 30 1 1073741825 1073741825.999999 truncating 2004-01-10 13:37:05.000000 + 31 -1 2147483647 2147483647.999999 truncating 2038-01-19 03:14:07.000000 + 31 0 2147483648 2147483648.999999 truncating 2038-01-19 03:14:08.000000 + 31 1 2147483649 2147483649.999999 truncating 2038-01-19 03:14:09.000000 + 32 -1 4294967295 4294967295.999999 truncating 2106-02-07 06:28:15.000000 + 32 0 4294967296 4294967296.999999 truncating 2106-02-07 06:28:16.000000 + 32 1 4294967297 4294967297.999999 truncating 2106-02-07 06:28:17.000000 + 33 -1 8589934591 8589934591.999999 truncating 2242-03-16 12:56:31.000000 + 33 0 8589934592 8589934592.999998 truncating 2242-03-16 12:56:32.000000 + 33 1 8589934593 8589934593.999998 truncating 2242-03-16 12:56:33.000000 + 34 -1 17179869183 17179869183.999998 truncating 2514-05-30 01:53:03.000000 + 34 0 17179869184 17179869185.0 ROUNDING UP 2514-05-30 01:53:04.000000 + 34 1 17179869185 17179869186.0 ROUNDING UP 2514-05-30 01:53:05.000000 + 35 -1 34359738367 34359738368.0 ROUNDING UP 3058-10-26 03:46:07.000000 + 35 0 34359738368 34359738369.0 ROUNDING UP 3058-10-26 03:46:08.000000 + 35 1 34359738369 34359738370.0 ROUNDING UP 3058-10-26 03:46:09.000000 + 36 -1 68719476735 68719476736.0 ROUNDING UP 4147-08-20 07:32:15.000000 + 36 0 68719476736 68719476737.0 ROUNDING UP 4147-08-20 07:32:16.000000 + 36 1 68719476737 68719476738.0 ROUNDING UP 4147-08-20 07:32:17.000000 + 37 -1 137438953471 137438953472.0 ROUNDING UP 6325-04-08 15:04:31.000000 + 37 0 137438953472 137438953473.0 ROUNDING UP 6325-04-08 15:04:32.000000 + 37 1 137438953473 137438953474.0 ROUNDING UP 6325-04-08 15:04:33.000000 + 38 -1 274877906943 274877906944.0 ROUNDING UP out of datetime range + 38 0 274877906944 274877906945.0 ROUNDING UP out of datetime range + 38 1 274877906945 274877906946.0 ROUNDING UP out of datetime range + 39 -1 549755813887 549755813888.0 ROUNDING UP out of datetime range + 39 0 549755813888 549755813889.0 ROUNDING UP out of datetime range + 39 1 549755813889 549755813890.0 ROUNDING UP out of datetime range + 40 -1 1099511627775 1099511627776.0 ROUNDING UP out of datetime range + 40 0 1099511627776 1099511627777.0 ROUNDING UP out of datetime range + 40 1 1099511627777 1099511627778.0 ROUNDING UP out of datetime range + 41 -1 2199023255551 2199023255552.0 ROUNDING UP out of datetime range + 41 0 2199023255552 2199023255553.0 ROUNDING UP out of datetime range + 41 1 2199023255553 2199023255554.0 ROUNDING UP out of datetime range + 42 -1 4398046511103 4398046511104.0 ROUNDING UP out of datetime range + 42 0 4398046511104 4398046511105.0 ROUNDING UP out of datetime range + 42 1 4398046511105 4398046511106.0 ROUNDING UP out of datetime range + 43 -1 8796093022207 8796093022208.0 ROUNDING UP out of datetime range + 43 0 8796093022208 8796093022209.0 ROUNDING UP out of datetime range + 43 1 8796093022209 8796093022210.0 ROUNDING UP out of datetime range + 44 -1 17592186044415 17592186044416.0 ROUNDING UP out of datetime range + 44 0 17592186044416 17592186044417.0 ROUNDING UP out of datetime range + 44 1 17592186044417 17592186044418.0 ROUNDING UP out of datetime range + 45 -1 35184372088831 35184372088832.0 ROUNDING UP out of datetime range + 45 0 35184372088832 35184372088833.0 ROUNDING UP out of datetime range + 45 1 35184372088833 35184372088834.0 ROUNDING UP out of datetime range + 46 -1 70368744177663 70368744177664.0 ROUNDING UP out of datetime range + 46 0 70368744177664 70368744177665.0 ROUNDING UP out of datetime range + 46 1 70368744177665 70368744177666.0 ROUNDING UP out of datetime range + 47 -1 140737488355327 140737488355328.0 ROUNDING UP out of datetime range + 47 0 140737488355328 140737488355329.0 ROUNDING UP out of datetime range + 47 1 140737488355329 140737488355330.0 ROUNDING UP out of datetime range + 48 -1 281474976710655 281474976710656.0 ROUNDING UP out of datetime range + 48 0 281474976710656 281474976710657.0 ROUNDING UP out of datetime range + 48 1 281474976710657 281474976710658.0 ROUNDING UP out of datetime range + 49 -1 562949953421311 562949953421312.0 ROUNDING UP out of datetime range + 49 0 562949953421312 562949953421313.0 ROUNDING UP out of datetime range + 49 1 562949953421313 562949953421314.0 ROUNDING UP out of datetime range + 50 -1 1125899906842623 1125899906842624.0 ROUNDING UP out of datetime range + 50 0 1125899906842624 1125899906842625.0 ROUNDING UP out of datetime range + 50 1 1125899906842625 1125899906842626.0 ROUNDING UP out of datetime range + 51 -1 2251799813685247 2251799813685248.0 ROUNDING UP out of datetime range + 51 0 2251799813685248 2251799813685249.0 ROUNDING UP out of datetime range + 51 1 2251799813685249 2251799813685250.0 ROUNDING UP out of datetime range + 52 -1 4503599627370495 4503599627370496.0 ROUNDING UP out of datetime range + 52 0 4503599627370496 4503599627370497.0 ROUNDING UP out of datetime range + 52 1 4503599627370497 4503599627370498.0 ROUNDING UP out of datetime range + 53 -1 9007199254740991 9007199254740992.0 ROUNDING UP out of datetime range + 53 0 9007199254740992 9007199254740992.0 truncating out of datetime range + 53 1 9007199254740993 9007199254740992.0 LOSSY out of datetime range +