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().

This commit is contained in:
Deon George 2023-12-07 12:07:11 +11:00
parent ee15274478
commit fa2e74eaca
2 changed files with 89 additions and 7 deletions

View File

@ -103,17 +103,18 @@ if (! function_exists('timew')) {
* are unique using 1/10th second precision. * are unique using 1/10th second precision.
* *
* Time is: * Time is:
* + 02 bits unused * + 02 bits least significant bits of year - giving us a 4 year timestamp
* + 04 bits Month * + 04 bits Month
* + 05 bits Day * + 05 bits Day
* + 05 bits Hour * + 05 bits Hour
* + 06 bits Min * + 06 bits Min
* + 06 bits Sec * + 06 bits Sec
* + 04 bits 10th Sec * + 04 bits 10th Sec
* = 32 (2 bits free) * = 32 bits
* *
* @param Carbon|null $time * @param Carbon|null $time
* @return int * @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 function timew(Carbon $time=NULL): int
{ {
@ -130,19 +131,30 @@ if (! function_exists('timew')) {
$delay = $time->getPreciseTimestamp(1); $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->day & 0x1f)) << 5;
$t = ($t | ($time->hour & 0x1f)) << 6; $t = ($t | ($time->hour & 0x1f)) << 6;
$t = ($t | ($time->minute & 0x3f)) << 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')) { if (! function_exists('wtime')) {
/** /**
* Convert a 40 bit integer into a time. * 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() * @see timew()
* *
* @param int $time * @param int $time
@ -158,25 +170,36 @@ if (! function_exists('wtime')) {
if ($time > pow(2,26)-1) { if ($time > pow(2,26)-1) {
$milli = ($time & 0xf); $milli = ($time & 0xf);
$time = $time >> 4; $time = $time >> 4;
if ($milli > 9)
$milli = 9;
} else { } else {
$milli = 0; $milli = 0;
} }
$sec = ($time & 0x3f); $sec = ($time & 0x3f);
if ($sec > 59)
$sec = 59;
$time = $time >> 6; $time = $time >> 6;
$min = ($time & 0x3f); $min = ($time & 0x3f);
if ($min > 59)
$min = 59;
$time = $time >> 6; $time = $time >> 6;
$hr = ($time & 0x1f); $hr = ($time & 0x1f);
if ($hr > 23)
$hr = 23;
$time = $time >> 5; $time = $time >> 5;
$day = ($time & 0x1f); $day = ($time & 0x1f);
$time = $time >> 5; $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);
} }
} }

59
tests/Unit/TimeWTest.php Normal file
View File

@ -0,0 +1,59 @@
<?php
namespace Tests\Unit;
use Carbon\Carbon;
use PHPUnit\Framework\TestCase;
class TimeWTest extends TestCase
{
/**
* A basic unit test example.
*/
public function test_timew(): void
{
$date = Carbon::createFromFormat('Y-m-d H:i:s.v','2023-12-07 12:13:14.567');
$this->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));
}
}