mirror of
https://github.com/ramsey/uuid.git
synced 2026-06-15 16:07:55 +03:00
Return Hexadecimal type from TimeConverterInterface::calculateTime()
This commit is contained in:
@@ -95,6 +95,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
string.
|
||||
* `Generator\DefaultTimeGenerator` no longer adds the variant and version bits
|
||||
to the bytes it returns. These must be applied to the bytes afterwards.
|
||||
* `Converter/TimeConverterInterface::calculateTime()` now returns
|
||||
`Type\Hexadecimal` instead of `array`. The value is the full UUID timestamp
|
||||
value (count of 100-nanosecond intervals since the Gregorian calendar epoch)
|
||||
in hexadecimal format.
|
||||
* Change methods in converter interfaces to accept and return string values
|
||||
instead of `mixed`; this simplifies the interface and makes it consistent:
|
||||
* `NumberConverterInterface::fromHex(string $hex): string`
|
||||
|
||||
@@ -41,7 +41,7 @@ class BigNumberTimeConverter implements TimeConverterInterface
|
||||
* @inheritDoc
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function calculateTime(string $seconds, string $microSeconds): array
|
||||
public function calculateTime(string $seconds, string $microSeconds): Hexadecimal
|
||||
{
|
||||
return $this->converter->calculateTime($seconds, $microSeconds);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class GenericTimeConverter implements TimeConverterInterface
|
||||
* @inheritDoc
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function calculateTime(string $seconds, string $microSeconds): array
|
||||
public function calculateTime(string $seconds, string $microSeconds): Hexadecimal
|
||||
{
|
||||
$timestamp = new Time($seconds, $microSeconds);
|
||||
|
||||
@@ -69,11 +69,7 @@ class GenericTimeConverter implements TimeConverterInterface
|
||||
STR_PAD_LEFT
|
||||
);
|
||||
|
||||
return [
|
||||
'low' => substr($uuidTimeHex, 8),
|
||||
'mid' => substr($uuidTimeHex, 4, 4),
|
||||
'hi' => substr($uuidTimeHex, 0, 4),
|
||||
];
|
||||
return new Hexadecimal($uuidTimeHex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ class PhpTimeConverter implements TimeConverterInterface
|
||||
* @inheritDoc
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function calculateTime(string $seconds, string $microSeconds): array
|
||||
public function calculateTime(string $seconds, string $microSeconds): Hexadecimal
|
||||
{
|
||||
$seconds = new IntegerValue($seconds);
|
||||
$microSeconds = new IntegerValue($microSeconds);
|
||||
@@ -88,12 +88,7 @@ class PhpTimeConverter implements TimeConverterInterface
|
||||
);
|
||||
}
|
||||
|
||||
/** @psalm-suppress MixedArgument */
|
||||
return [
|
||||
'low' => sprintf('%08x', $uuidTime & 0xffffffff),
|
||||
'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff),
|
||||
'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff),
|
||||
];
|
||||
return new Hexadecimal(str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,8 +24,9 @@ use Ramsey\Uuid\Type\Time;
|
||||
interface TimeConverterInterface
|
||||
{
|
||||
/**
|
||||
* Uses the provided seconds and micro-seconds to calculate the time_low,
|
||||
* time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
|
||||
* Uses the provided seconds and micro-seconds to calculate the count of
|
||||
* 100-nanosecond intervals since UTC 00:00:00.00, 15 October 1582, for
|
||||
* RFC 4122 variant UUIDs
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc4122#section-4.2.2 RFC 4122, § 4.2.2: Generation Details
|
||||
*
|
||||
@@ -34,11 +35,11 @@ interface TimeConverterInterface
|
||||
* @param string $microSeconds A string representation of the micro-seconds
|
||||
* associated with the time to calculate
|
||||
*
|
||||
* @return string[] An array guaranteed to contain `low`, `mid`, and `hi` keys
|
||||
* @return Hexadecimal The full UUID timestamp as a Hexadecimal value
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function calculateTime(string $seconds, string $microSeconds): array;
|
||||
public function calculateTime(string $seconds, string $microSeconds): Hexadecimal;
|
||||
|
||||
/**
|
||||
* Converts a timestamp extracted from a UUID to a Unix timestamp
|
||||
|
||||
@@ -75,25 +75,18 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
|
||||
}
|
||||
}
|
||||
|
||||
// Create a 60-bit time value as a count of 100-nanosecond intervals
|
||||
// since 00:00:00.00, 15 October 1582.
|
||||
$uuidTime = $this->timeConverter->calculateTime(
|
||||
$this->timeProvider->getTime()->getSeconds()->toString(),
|
||||
$this->timeProvider->getTime()->getMicroSeconds()->toString()
|
||||
);
|
||||
|
||||
$hex = vsprintf(
|
||||
'%08s%04s%04s%04s%012s',
|
||||
[
|
||||
$uuidTime['low'] ?? 0,
|
||||
$uuidTime['mid'] ?? 0,
|
||||
$uuidTime['hi'] ?? 0,
|
||||
sprintf('%04x', $clockSeq),
|
||||
$node,
|
||||
]
|
||||
);
|
||||
$timeBytes = (string) hex2bin(str_pad($uuidTime->toString(), 16, '0', STR_PAD_LEFT));
|
||||
|
||||
return (string) hex2bin($hex);
|
||||
return $timeBytes[4] . $timeBytes[5] . $timeBytes[6] . $timeBytes[7]
|
||||
. $timeBytes[2] . $timeBytes[3]
|
||||
. $timeBytes[0] . $timeBytes[1]
|
||||
. pack('n*', $clockSeq)
|
||||
. $node;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +95,7 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
|
||||
*
|
||||
* @param string|int|null $node A node value that may be used to override the node provider
|
||||
*
|
||||
* @return string Hexadecimal representation of the node ID
|
||||
* @return string 6-byte binary string representation of the node
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
@@ -114,13 +107,13 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
|
||||
|
||||
// Convert the node to hex, if it is still an integer.
|
||||
if (is_int($node)) {
|
||||
$node = sprintf('%012x', $node);
|
||||
$node = dechex($node);
|
||||
}
|
||||
|
||||
if (!ctype_xdigit((string) $node) || strlen((string) $node) > 12) {
|
||||
throw new InvalidArgumentException('Invalid node value');
|
||||
}
|
||||
|
||||
return strtolower(sprintf('%012s', (string) $node));
|
||||
return (string) hex2bin(str_pad((string) $node, 12, '0', STR_PAD_LEFT));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,16 +26,15 @@ class BigNumberTimeConverterTest extends TestCase
|
||||
$maskMid = BigInteger::fromBase('ffff', 16);
|
||||
$maskHi = BigInteger::fromBase('0fff', 16);
|
||||
|
||||
$expectedArray = [
|
||||
'low' => sprintf('%08s', $calculatedTime->and($maskLow)->toBase(16)),
|
||||
'mid' => sprintf('%04s', $calculatedTime->shiftedRight(32)->and($maskMid)->toBase(16)),
|
||||
'hi' => sprintf('%04s', $calculatedTime->shiftedRight(48)->and($maskHi)->toBase(16)),
|
||||
];
|
||||
$expected = sprintf('%04s', $calculatedTime->shiftedRight(48)->and($maskHi)->toBase(16));
|
||||
$expected .= sprintf('%04s', $calculatedTime->shiftedRight(32)->and($maskMid)->toBase(16));
|
||||
$expected .= sprintf('%08s', $calculatedTime->and($maskLow)->toBase(16));
|
||||
|
||||
$converter = new BigNumberTimeConverter();
|
||||
$returned = $converter->calculateTime((string) $seconds, (string) $microSeconds);
|
||||
|
||||
$this->assertSame($expectedArray, $returned);
|
||||
$this->assertInstanceOf(Hexadecimal::class, $returned);
|
||||
$this->assertSame($expected, $returned->toString());
|
||||
}
|
||||
|
||||
public function testConvertTime(): void
|
||||
|
||||
@@ -12,18 +12,16 @@ use Ramsey\Uuid\Type\Hexadecimal;
|
||||
class GenericTimeConverterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @param string[] $expected
|
||||
*
|
||||
* @dataProvider provideCalculateTime
|
||||
*/
|
||||
public function testCalculateTime(string $seconds, string $microSeconds, array $expected): void
|
||||
public function testCalculateTime(string $seconds, string $microSeconds, string $expected): void
|
||||
{
|
||||
$calculator = new BrickMathCalculator();
|
||||
$converter = new GenericTimeConverter($calculator);
|
||||
|
||||
$result = $converter->calculateTime($seconds, $microSeconds);
|
||||
|
||||
$this->assertSame($expected, $result);
|
||||
$this->assertSame($expected, $result->toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,29 +33,17 @@ class GenericTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '-12219146756',
|
||||
'microSeconds' => '0',
|
||||
'expected' => [
|
||||
'low' => '0901e600',
|
||||
'mid' => '0154',
|
||||
'hi' => '0000',
|
||||
],
|
||||
'expected' => '000001540901e600',
|
||||
],
|
||||
[
|
||||
'seconds' => '103072857659',
|
||||
'microseconds' => '999999',
|
||||
'expected' => [
|
||||
'low' => 'ff9785f6',
|
||||
'mid' => 'ffff',
|
||||
'hi' => '0fff',
|
||||
],
|
||||
'expected' => '0fffffffff9785f6',
|
||||
],
|
||||
[
|
||||
'seconds' => '1578612359',
|
||||
'microseconds' => '521023',
|
||||
'expected' => [
|
||||
'low' => '64c71df6',
|
||||
'mid' => '3337',
|
||||
'hi' => '01ea',
|
||||
],
|
||||
'expected' => '01ea333764c71df6',
|
||||
],
|
||||
|
||||
// This is the earliest possible date supported by v1 UUIDs:
|
||||
@@ -65,11 +51,7 @@ class GenericTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '-12219292800',
|
||||
'microSeconds' => '0',
|
||||
'expected' => [
|
||||
'low' => '00000000',
|
||||
'mid' => '0000',
|
||||
'hi' => '0000',
|
||||
],
|
||||
'expected' => '0000000000000000',
|
||||
],
|
||||
|
||||
// This is the last possible time supported by v1 UUIDs:
|
||||
@@ -77,11 +59,7 @@ class GenericTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '1832455114570',
|
||||
'microseconds' => '955161',
|
||||
'expected' => [
|
||||
'low' => 'fffffffa',
|
||||
'mid' => 'ffff',
|
||||
'hi' => 'ffff',
|
||||
],
|
||||
'expected' => 'fffffffffffffffa',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -29,16 +29,14 @@ class PhpTimeConverterTest extends TestCase
|
||||
$maskMid = BigInteger::fromBase('ffff', 16);
|
||||
$maskHi = BigInteger::fromBase('0fff', 16);
|
||||
|
||||
$expectedArray = [
|
||||
'low' => sprintf('%08s', $calculatedTime->and($maskLow)->toBase(16)),
|
||||
'mid' => sprintf('%04s', $calculatedTime->shiftedRight(32)->and($maskMid)->toBase(16)),
|
||||
'hi' => sprintf('%04s', $calculatedTime->shiftedRight(48)->and($maskHi)->toBase(16)),
|
||||
];
|
||||
$expected = sprintf('%04s', $calculatedTime->shiftedRight(48)->and($maskHi)->toBase(16));
|
||||
$expected .= sprintf('%04s', $calculatedTime->shiftedRight(32)->and($maskMid)->toBase(16));
|
||||
$expected .= sprintf('%08s', $calculatedTime->and($maskLow)->toBase(16));
|
||||
|
||||
$converter = new PhpTimeConverter();
|
||||
$returned = $converter->calculateTime((string) $seconds, (string) $microSeconds);
|
||||
|
||||
$this->assertSame($expectedArray, $returned);
|
||||
$this->assertSame($expected, $returned->toString());
|
||||
}
|
||||
|
||||
public function testCalculateTimeThrowsExceptionWhenSecondsIsNotOnlyDigits(): void
|
||||
@@ -134,11 +132,9 @@ class PhpTimeConverterTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $expected
|
||||
*
|
||||
* @dataProvider provideCalculateTime
|
||||
*/
|
||||
public function testCalculateTime(string $seconds, string $microSeconds, array $expected): void
|
||||
public function testCalculateTime(string $seconds, string $microSeconds, string $expected): void
|
||||
{
|
||||
$calculator = new BrickMathCalculator();
|
||||
$fallbackConverter = new GenericTimeConverter($calculator);
|
||||
@@ -146,7 +142,7 @@ class PhpTimeConverterTest extends TestCase
|
||||
|
||||
$result = $converter->calculateTime($seconds, $microSeconds);
|
||||
|
||||
$this->assertSame($expected, $result);
|
||||
$this->assertSame($expected, $result->toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,29 +154,17 @@ class PhpTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '-12219146756',
|
||||
'microSeconds' => '0',
|
||||
'expected' => [
|
||||
'low' => '0901e600',
|
||||
'mid' => '0154',
|
||||
'hi' => '0000',
|
||||
],
|
||||
'expected' => '000001540901e600',
|
||||
],
|
||||
[
|
||||
'seconds' => '103072857659',
|
||||
'microseconds' => '999999',
|
||||
'expected' => [
|
||||
'low' => 'ff9785f6',
|
||||
'mid' => 'ffff',
|
||||
'hi' => '0fff',
|
||||
],
|
||||
'expected' => '0fffffffff9785f6',
|
||||
],
|
||||
[
|
||||
'seconds' => '1578612359',
|
||||
'microseconds' => '521023',
|
||||
'expected' => [
|
||||
'low' => '64c71df6',
|
||||
'mid' => '3337',
|
||||
'hi' => '01ea',
|
||||
],
|
||||
'expected' => '01ea333764c71df6',
|
||||
],
|
||||
|
||||
// This is the earliest possible date supported by v1 UUIDs:
|
||||
@@ -188,11 +172,7 @@ class PhpTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '-12219292800',
|
||||
'microSeconds' => '0',
|
||||
'expected' => [
|
||||
'low' => '00000000',
|
||||
'mid' => '0000',
|
||||
'hi' => '0000',
|
||||
],
|
||||
'expected' => '0000000000000000',
|
||||
],
|
||||
|
||||
// This is the last possible time supported by v1 UUIDs:
|
||||
@@ -200,11 +180,7 @@ class PhpTimeConverterTest extends TestCase
|
||||
[
|
||||
'seconds' => '1832455114570',
|
||||
'microseconds' => '955161',
|
||||
'expected' => [
|
||||
'low' => 'fffffffa',
|
||||
'mid' => 'ffff',
|
||||
'hi' => 'ffff',
|
||||
],
|
||||
'expected' => 'fffffffffffffffa',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use Ramsey\Uuid\DegradedUuid;
|
||||
use Ramsey\Uuid\Generator\CombGenerator;
|
||||
use Ramsey\Uuid\Generator\DefaultTimeGenerator;
|
||||
use Ramsey\Uuid\Math\BrickMathCalculator;
|
||||
use Ramsey\Uuid\Type\Hexadecimal;
|
||||
use Ramsey\Uuid\Type\Time;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\UuidFactory;
|
||||
@@ -532,11 +533,7 @@ class ExpectedBehaviorTest extends TestCase
|
||||
$timeConverter
|
||||
->shouldReceive('calculateTime')
|
||||
->andReturnUsing(function ($seconds, $microSeconds) {
|
||||
return [
|
||||
'low' => dechex($seconds),
|
||||
'mid' => dechex($microSeconds),
|
||||
'hi' => 'abcd',
|
||||
];
|
||||
return new Hexadecimal('abcd' . dechex($microSeconds) . dechex($seconds));
|
||||
});
|
||||
|
||||
$timeProvider = \Mockery::mock('Ramsey\Uuid\Provider\TimeProviderInterface', [
|
||||
|
||||
@@ -16,6 +16,7 @@ use Ramsey\Uuid\Generator\DefaultTimeGenerator;
|
||||
use Ramsey\Uuid\Provider\NodeProviderInterface;
|
||||
use Ramsey\Uuid\Provider\TimeProviderInterface;
|
||||
use Ramsey\Uuid\Test\TestCase;
|
||||
use Ramsey\Uuid\Type\Hexadecimal;
|
||||
use Ramsey\Uuid\Type\Time;
|
||||
|
||||
class DefaultTimeGeneratorTest extends TestCase
|
||||
@@ -46,7 +47,7 @@ class DefaultTimeGeneratorTest extends TestCase
|
||||
private $currentTime;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @var Hexadecimal
|
||||
*/
|
||||
private $calculatedTime;
|
||||
|
||||
@@ -61,7 +62,7 @@ class DefaultTimeGeneratorTest extends TestCase
|
||||
$this->nodeProvider = $this->getMockBuilder(NodeProviderInterface::class)->getMock();
|
||||
$this->timeConverter = $this->getMockBuilder(TimeConverterInterface::class)->getMock();
|
||||
$this->currentTime = ['sec' => 1458733431, 'usec' => 877449];
|
||||
$this->calculatedTime = ['low' => '83cb98e0', 'mid' => '98e0', 'hi' => '03cb'];
|
||||
$this->calculatedTime = new Hexadecimal('03cb98e083cb98e0');
|
||||
|
||||
$time = new Time($this->currentTime['sec'], $this->currentTime['usec']);
|
||||
$this->timeProvider = Mockery::mock(TimeProviderInterface::class, [
|
||||
|
||||
Reference in New Issue
Block a user