From 79af97156eb2dba76545314a92e760d40fc9aa93 Mon Sep 17 00:00:00 2001 From: Damien Bradley Date: Fri, 15 Mar 2024 19:32:51 +0000 Subject: [PATCH 1/3] Issue390: Re-worked nbt file, added negative time format and tests --- examples/datetime_human_tests.nbt | 4 +++ numbat/modules/datetime/human.nbt | 45 +++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/examples/datetime_human_tests.nbt b/examples/datetime_human_tests.nbt index 9857f400..35ed40cf 100644 --- a/examples/datetime_human_tests.nbt +++ b/examples/datetime_human_tests.nbt @@ -36,3 +36,7 @@ assert((1 µs -> human) == "0.000001 seconds") assert((1 ns -> human) == "0.000000001 seconds") assert((1234 ns -> human) == "0.000001234 seconds") assert((1s + 1234 ns -> human) == "1.000001234 seconds") + +assert((-2.5 minute -> human) == "2 minutes + 30 seconds ago") +assert((-2 weeks -> human) == "14 days ago") +assert((-1234 ns -> human) == "0.000001234 seconds ago") \ No newline at end of file diff --git a/numbat/modules/datetime/human.nbt b/numbat/modules/datetime/human.nbt index 9a334b14..017e1977 100644 --- a/numbat/modules/datetime/human.nbt +++ b/numbat/modules/datetime/human.nbt @@ -3,7 +3,19 @@ use core::strings use units::si use datetime::functions -fn _human_num_days(time: Time) -> Scalar = floor(time / day) +fn _human_num_days(time: Time) -> Time = floor(time / day)*day + +fn _human_num_hours(time: Time) -> Time = floor(time / hours)*hour + +fn _human_num_minutes(time: Time) -> Time = floor(time / minutes)*minute + +fn _human_num_seconds(time: Time) -> Time = (time / seconds)second + +fn _seconds_on_stopwatch(time: Time) -> Time = _human_num_seconds(time)-_human_num_seconds(_human_num_minutes(time)) + +fn _minutes_on_clock(time: Time) -> Time = _human_num_minutes(time)-_human_num_minutes(_human_num_hours(time)) + +fn _hours_of_a_day(time: Time) -> Time = _human_num_hours(time)-_human_num_hours(_human_num_days(time)) fn _human_join(a: String, b: String) -> String = if str_slice(a, 0, 2) == "0 " then b else if str_slice(b, 0, 2) == "0 " then a else "{a} + {b}" @@ -11,26 +23,31 @@ fn _human_join(a: String, b: String) -> String = fn _remove_plural_suffix(str: String) -> String = if str_slice(str, 0, 2) == "1 " then str_slice(str, 0, str_length(str) - 1) else str -fn _human_seconds(dt: DateTime) -> String = - _remove_plural_suffix(format_datetime("%-S%.f seconds", dt)) +fn _human_formatted_seconds(time: Time) -> String = + _remove_plural_suffix(format_datetime("%-S%.f seconds", datetime("0001-01-01T00:00:00Z") + _seconds_on_stopwatch(time))) -fn _human_minutes(dt: DateTime) -> String = - _remove_plural_suffix(format_datetime("%-M minutes", dt)) +fn _human_formatted_minutes(time: Time) -> String = + _remove_plural_suffix("{_minutes_on_clock(time)/minute} minutes") -fn _human_hours(dt: DateTime) -> String = - _remove_plural_suffix(format_datetime("%-H hours", dt)) +fn _human_formatted_hours(time: Time) -> String = + _remove_plural_suffix("{_hours_of_a_day(time)/hour} hours") -fn _human_days(num_days: Scalar) -> String = - _remove_plural_suffix("{num_days} days") +fn _human_formatted_days(num_days: Time) -> String = + _remove_plural_suffix("{_human_num_days(num_days)/day} days") -fn _human_readable_duration(time: Time, dt: DateTime, num_days: Scalar) -> String = - _human_join(_human_join(_human_join(_human_days(_human_num_days(time)), _human_hours(dt)), _human_minutes(dt)), _human_seconds(dt)) +fn _human_readable_duration(time: Time) -> String = + _human_join(_human_join(_human_join(_human_formatted_days(time), _human_formatted_hours(time)), _human_formatted_minutes(time)), _human_formatted_seconds(time)) # Implementation details: # we skip hours/minutes/seconds for durations larger than 1000 days because: # (a) we run into floating point precision problems at the nanosecond level at this point # (b) for much larger numbers, we can't convert to DateTimes anymore +fn human_time_check_overflow(time: Time) = + if _human_num_days(time) > 1000 days + then _human_formatted_days(time) + else _human_readable_duration(time) + fn human(time: Time) = - if _human_num_days(time) > 1000 - then "{_human_num_days(time)} days" - else _human_readable_duration(time, datetime("0001-01-01T00:00:00Z") + time, _human_num_days(time)) + if _human_num_seconds(time) < 0 seconds + then "{human_time_check_overflow(time*-1)} ago" + else human_time_check_overflow(time) From 4ecec674094dc89439d35696791a3ce1769d1116 Mon Sep 17 00:00:00 2001 From: Damien Bradley Date: Mon, 18 Mar 2024 21:49:15 +0000 Subject: [PATCH 2/3] Issue390: Added new unit tests --- examples/datetime_human_tests.nbt | 56 ++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/examples/datetime_human_tests.nbt b/examples/datetime_human_tests.nbt index 35ed40cf..d56ce692 100644 --- a/examples/datetime_human_tests.nbt +++ b/examples/datetime_human_tests.nbt @@ -1,7 +1,13 @@ assert((0 second -> human) == "0 seconds") +assert((0.1 second -> human) == "0.100 seconds") +assert((0.01 second -> human) == "0.010 seconds") +assert((0.001 second -> human) == "0.001 seconds") + assert((1 second -> human) == "1 second") assert((5 second -> human) == "5 seconds") assert((1.5 second -> human) == "1.500 seconds") +assert((2.55 second -> human) == "2.550 seconds") +assert((5.99999 second -> human) == "5.999990 seconds") assert((60 seconds -> human) == "1 minute") assert((73 seconds -> human) == "1 minute + 13 seconds") @@ -22,7 +28,20 @@ assert((1.37 day -> human) == "1 day + 8 hours + 52 minutes + 48 seconds assert((1 week -> human) == "7 days") assert((1.5 weeks -> human) == "10 days + 12 hours") assert((2 weeks -> human) == "14 days") +assert((4.566 weeks -> human) == "31 days + 23 hours + 5 minutes + 16.800 seconds") + +assert((1 year -> human) == "365 days + 5 hours + 48 minutes + 45.051840004 seconds") +assert((3.45 years -> human) == "1260 days") +assert((1 month -> human) == "30 days + 10 hours + 29 minutes + 3.754320 seconds") +assert((3.78 months -> human) == "115 days + 1 hour + 13 minutes + 51.391329601 seconds") +assert((1 gregorian_year -> human) == "365 days + 5 hours + 49 minutes + 12 seconds") +assert((2.34 gregorian_year -> human) == "854 days + 16 hours + 1 minute + 7.679999992 seconds") +assert((1 julian_year -> human) == "365 days + 6 hours") +assert((1.06 julian_year -> human) == "387 days + 3 hours + 57 minutes + 36 seconds") +assert((1 decade -> human) == "3652 days") +assert((1 century -> human) == "36524 days") +assert((1 millennium -> human) == "365_242 days") assert((1 sidereal_day -> human) == "23 hours + 56 minutes + 4.090500 seconds") assert((10000 days -> human) == "10000 days") @@ -32,11 +51,46 @@ assert((1e12 days -> human) == "1_000_000_000_000 days") assert((1e15 days -> human) == "1.0e+15 days") assert((1 ms -> human) == "0.001 seconds") +assert((12 ms -> human) == "0.012 seconds") +assert((342 ms -> human) == "0.342 seconds") + assert((1 µs -> human) == "0.000001 seconds") +assert((1245 µs -> human) == "0.001245 seconds") +assert((1236876 µs -> human) == "1.236876 seconds") + assert((1 ns -> human) == "0.000000001 seconds") assert((1234 ns -> human) == "0.000001234 seconds") assert((1s + 1234 ns -> human) == "1.000001234 seconds") +assert((-1 second -> human) == "1 second ago") +assert((-25 seconds -> human) == "25 seconds ago") +assert((-49.010 seconds -> human) == "49.010 seconds ago") + assert((-2.5 minute -> human) == "2 minutes + 30 seconds ago") +assert((-1 hour -> human) == "1 hour ago") +assert((-3 hour -> human) == "3 hours ago") +assert((-5.34 hour -> human) == "5 hours + 20 minutes + 24 seconds ago") +assert((-7.89 hour -> human) == "7 hours + 53 minutes + 24 seconds ago") +assert((-7.89 hour - 4 minutes -> human) == "7 hours + 57 minutes + 24 seconds ago") + +assert((-1 day -> human) == "1 day ago") +assert((-4.6 days -> human) == "4 days + 14 hours + 23 minutes ago") +assert((-9.2345 days -> human) == "9 days + 5 hours + 37 minutes + 40.800 seconds ago") +assert((-9.2345 days + 52 hours -> human) == "7 days + 1 hour + 37 minutes + 40.800 seconds ago") + assert((-2 weeks -> human) == "14 days ago") -assert((-1234 ns -> human) == "0.000001234 seconds ago") \ No newline at end of file +assert((-4.5 weeks -> human) == "31 days + 12 hours ago") +assert((-20.5 weeks -> human) == "143 days + 12 hours ago") + +assert((-2.5 months -> human) == "76 days + 2 hours + 12 minutes + 39.385800 seconds ago") +assert((-2.5 years -> human) == "913 days + 2 hours + 31 minutes + 52.629600003 seconds ago") +assert((-10.5 decades -> human) == "38350 days ago") + +assert((-25 ms -> human) == "0.025 seconds ago") +assert((-6400 ms -> human) == "6.400 seconds ago") + +assert((-2500 µs -> human) == "0.002500 seconds ago") +assert((-40525 µs -> human) == "0.040525 seconds ago") + +assert((-5147 ns -> human) == "0.000005147 seconds ago") +assert((-23s + 1234 ns -> human) == "22.999998766 seconds ago") \ No newline at end of file From 581fae1d595e92f62b676c2858372aae3819711a Mon Sep 17 00:00:00 2001 From: Damien Bradley Date: Fri, 5 Apr 2024 15:19:54 +0100 Subject: [PATCH 3/3] Issue390: Removed redundant negative time tests --- examples/datetime_human_tests.nbt | 32 +------------------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/examples/datetime_human_tests.nbt b/examples/datetime_human_tests.nbt index d56ce692..92cefc8b 100644 --- a/examples/datetime_human_tests.nbt +++ b/examples/datetime_human_tests.nbt @@ -63,34 +63,4 @@ assert((1234 ns -> human) == "0.000001234 seconds") assert((1s + 1234 ns -> human) == "1.000001234 seconds") assert((-1 second -> human) == "1 second ago") -assert((-25 seconds -> human) == "25 seconds ago") -assert((-49.010 seconds -> human) == "49.010 seconds ago") - -assert((-2.5 minute -> human) == "2 minutes + 30 seconds ago") -assert((-1 hour -> human) == "1 hour ago") -assert((-3 hour -> human) == "3 hours ago") -assert((-5.34 hour -> human) == "5 hours + 20 minutes + 24 seconds ago") -assert((-7.89 hour -> human) == "7 hours + 53 minutes + 24 seconds ago") -assert((-7.89 hour - 4 minutes -> human) == "7 hours + 57 minutes + 24 seconds ago") - -assert((-1 day -> human) == "1 day ago") -assert((-4.6 days -> human) == "4 days + 14 hours + 23 minutes ago") -assert((-9.2345 days -> human) == "9 days + 5 hours + 37 minutes + 40.800 seconds ago") -assert((-9.2345 days + 52 hours -> human) == "7 days + 1 hour + 37 minutes + 40.800 seconds ago") - -assert((-2 weeks -> human) == "14 days ago") -assert((-4.5 weeks -> human) == "31 days + 12 hours ago") -assert((-20.5 weeks -> human) == "143 days + 12 hours ago") - -assert((-2.5 months -> human) == "76 days + 2 hours + 12 minutes + 39.385800 seconds ago") -assert((-2.5 years -> human) == "913 days + 2 hours + 31 minutes + 52.629600003 seconds ago") -assert((-10.5 decades -> human) == "38350 days ago") - -assert((-25 ms -> human) == "0.025 seconds ago") -assert((-6400 ms -> human) == "6.400 seconds ago") - -assert((-2500 µs -> human) == "0.002500 seconds ago") -assert((-40525 µs -> human) == "0.040525 seconds ago") - -assert((-5147 ns -> human) == "0.000005147 seconds ago") -assert((-23s + 1234 ns -> human) == "22.999998766 seconds ago") \ No newline at end of file +assert((-7.89 hour -> human) == "7 hours + 53 minutes + 24 seconds ago") \ No newline at end of file