From fa2e74eacab046f27fb26353f3c11114fe97c997 Mon Sep 17 00:00:00 2001 From: Deon George Date: Thu, 7 Dec 2023 12:07:11 +1100 Subject: [PATCH] Changes to timew() and wtime() to leverage last 2 bits for 4 year timestamp, making msgid checking valid according to FTSC. Added a test suite for timew()/wtime(). --- app/helpers.php | 37 ++++++++++++++++++++----- tests/Unit/TimeWTest.php | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/Unit/TimeWTest.php diff --git a/app/helpers.php b/app/helpers.php index 00dc03a..55e92e3 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -103,17 +103,18 @@ if (! function_exists('timew')) { * are unique using 1/10th second precision. * * Time is: - * + 02 bits unused + * + 02 bits least significant bits of year - giving us a 4 year timestamp * + 04 bits Month * + 05 bits Day * + 05 bits Hour * + 06 bits Min * + 06 bits Sec * + 04 bits 10th Sec - * = 32 (2 bits free) + * = 32 bits * * @param Carbon|null $time * @return int + * @todo Since this is used as part of our msgid, we need to use the first 2 bits to get our 3 year unique msgid, ie: year&0x03 */ function timew(Carbon $time=NULL): int { @@ -130,19 +131,30 @@ if (! function_exists('timew')) { $delay = $time->getPreciseTimestamp(1); - $t = ($time->month & 0xf) << 5; + $t = 0; + $t = ($t | $time->year & 0x3) << 4; + $t = ($t | ($time->month & 0xf)) << 5; $t = ($t | ($time->day & 0x1f)) << 5; $t = ($t | ($time->hour & 0x1f)) << 6; $t = ($t | ($time->minute & 0x3f)) << 6; - $t = ($t | ($time->second & 0x3f)); + $t = ($t | ($time->second & 0x3f)) << 4; + $t = ($t | ((int)($time->milli/100)) & 0xf); - return hexdec(sprintf('%07x%1x',$t,(round($time->milli/100) & 0x7f))); + return $t; } } if (! function_exists('wtime')) { /** * Convert a 40 bit integer into a time. + * We need to filter out loose bits, ie: + * + year all bits valid + * + month 11xx and 0000 are invalid + * + day all bits valid except 0000 + * + hour 11xxx are invalid + * + min 1111xx are invalid + * + sec 1111xx are invalid + * + 1/2 11xx, 101x are invalid * @see timew() * * @param int $time @@ -158,25 +170,36 @@ if (! function_exists('wtime')) { if ($time > pow(2,26)-1) { $milli = ($time & 0xf); $time = $time >> 4; + if ($milli > 9) + $milli = 9; } else { $milli = 0; } $sec = ($time & 0x3f); + if ($sec > 59) + $sec = 59; $time = $time >> 6; $min = ($time & 0x3f); + if ($min > 59) + $min = 59; $time = $time >> 6; $hr = ($time & 0x1f); + if ($hr > 23) + $hr = 23; $time = $time >> 5; $day = ($time & 0x1f); $time = $time >> 5; - $month = ($time & 0x1f); + $month = ($time & 0xf); + if ($month > 12) + $month = 12; + $time = $time >> 4; - return Carbon::create($year,$month,$day,$hr,$min,$sec+$milli/10); + return Carbon::create(($year & 0xffc)+$time,$month,$day,$hr,$min,$sec+$milli/10); } } \ No newline at end of file diff --git a/tests/Unit/TimeWTest.php b/tests/Unit/TimeWTest.php new file mode 100644 index 0000000..0ee9b48 --- /dev/null +++ b/tests/Unit/TimeWTest.php @@ -0,0 +1,59 @@ +assertEquals(4042011877,timew($date)); + + $date = Carbon::createFromFormat('Y-m-d H:i:s.v','2019-12-07 12:13:14.567'); + + $this->assertEquals(4042011877,timew($date)); + + $date = Carbon::createFromFormat('Y-m-d H:i:s.v','2022-12-07 01:28:50.400'); + + $this->assertEquals(2967565092,timew($date)); + } + + /** + * A basic unit test example. + */ + public function test_wtime(): void + { + $date = Carbon::createFromFormat('Y-m-d H:i:s.v','2023-12-07 12:13:14.5'); + + $this->assertEquals($date,wtime(4042011877,2022)); + + $date = Carbon::createFromFormat('Y-m-d H:i:s.v','2019-12-07 12:13:14.5'); + + $this->assertEquals($date,wtime(4042011877,2018)); + + $date = Carbon::createFromFormat('Y-m-d H:i:s.v','2022-12-07 01:28:50.400'); + + $this->assertEquals($date,wtime(2967565092,2022)); + } + + public function test_random_time(): void + { + $times = []; + $now = Carbon::now()->milli(rand(0,9)*100); + + for ($i=0;$i<1000;$i++) { + $ran = $now->clone()->addYears(rand(-50,50))->addDays(rand(-365,365))->addHours(rand(-24,24))->addMinutes(rand(-60,60))->addSeconds(rand(-60,60)); + $times[timew($ran)] = $ran; + } + + foreach ($times as $wtime => $time) + $this->assertEquals($time,wtime($wtime,$time->year)); + } +}