diff --git a/src/Converter/Time/GenericTimeConverter.php b/src/Converter/Time/GenericTimeConverter.php index be77d12..e490090 100644 --- a/src/Converter/Time/GenericTimeConverter.php +++ b/src/Converter/Time/GenericTimeConverter.php @@ -32,6 +32,22 @@ use const STR_PAD_LEFT; */ class GenericTimeConverter implements TimeConverterInterface { + /** + * The number of 100-nanosecond intervals from the Gregorian calendar epoch + * to the Unix epoch. + */ + private const GREGORIAN_TO_UNIX_INTERVALS = '122192928000000000'; + + /** + * The number of 100-nanosecond intervals in one second. + */ + private const SECOND_INTERVALS = '10000000'; + + /** + * The number of 100-nanosecond intervals in one microsecond. + */ + private const MICROSECOND_INTERVALS = '10'; + /** * @var CalculatorInterface */ @@ -50,21 +66,28 @@ class GenericTimeConverter implements TimeConverterInterface { $timestamp = new Time($seconds, $microSeconds); + // Convert the seconds into a count of 100-nanosecond intervals. $sec = $this->calculator->multiply( $timestamp->getSeconds(), - new IntegerObject('10000000') + new IntegerObject(self::SECOND_INTERVALS) ); + // Convert the microseconds into a count of 100-nanosecond intervals. $usec = $this->calculator->multiply( $timestamp->getMicroSeconds(), - new IntegerObject('10') + new IntegerObject(self::MICROSECOND_INTERVALS) ); + // Combine the seconds and microseconds intervals and add the count of + // 100-nanosecond intervals from the Gregorian calendar epoch to the + // Unix epoch. This gives us the correct count of 100-nanosecond + // intervals since the Gregorian calendar epoch for the given seconds + // and microseconds. /** @var IntegerObject $uuidTime */ $uuidTime = $this->calculator->add( $sec, $usec, - new IntegerObject('122192928000000000') + new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS) ); $uuidTimeHex = str_pad( @@ -84,19 +107,20 @@ class GenericTimeConverter implements TimeConverterInterface public function convertTime(Hexadecimal $uuidTimestamp): Time { // From the total, subtract the number of 100-nanosecond intervals from - // the UUID epoch (Gregorian calendar date) to the Unix epoch. This - // gives us the number of 100-nanosecond intervals from the Unix epoch, - // which also includes the microtime. + // the Gregorian calendar epoch to the Unix epoch. This gives us the + // number of 100-nanosecond intervals from the Unix epoch, which also + // includes the microtime. $epochNanoseconds = $this->calculator->subtract( $this->calculator->toIntegerValue($uuidTimestamp), - new IntegerObject('122192928000000000') + new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS) ); + // Convert the 100-nanosecond intervals into seconds and microseconds. $unixTimestamp = $this->calculator->divide( RoundingMode::HALF_UP, 6, $epochNanoseconds, - new IntegerObject('10000000') + new IntegerObject(self::SECOND_INTERVALS) ); $split = explode('.', (string) $unixTimestamp, 2); diff --git a/src/Converter/Time/PhpTimeConverter.php b/src/Converter/Time/PhpTimeConverter.php index a690bef..5c70f27 100644 --- a/src/Converter/Time/PhpTimeConverter.php +++ b/src/Converter/Time/PhpTimeConverter.php @@ -40,6 +40,22 @@ use const STR_PAD_RIGHT; */ class PhpTimeConverter implements TimeConverterInterface { + /** + * The number of 100-nanosecond intervals from the Gregorian calendar epoch + * to the Unix epoch. + */ + private const GREGORIAN_TO_UNIX_INTERVALS = 0x01b21dd213814000; + + /** + * The number of 100-nanosecond intervals in one second. + */ + private const SECOND_INTERVALS = 10000000; + + /** + * The number of 100-nanosecond intervals in one microsecond. + */ + private const MICROSECOND_INTERVALS = 10; + /** * @var CalculatorInterface */ @@ -81,15 +97,11 @@ class PhpTimeConverter implements TimeConverterInterface $seconds = new IntegerObject($seconds); $microSeconds = new IntegerObject($microSeconds); - // 0x01b21dd213814000 is the number of 100-nanosecond intervals between the - // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - // - A nanosecond is 1/1,000,000,000 of a second. - // - A nanosecond is 1/1,000 of a microsecond. - // - There are 10,000,000 100-nanosecond intervals within 1 second. - // - There are 10 100-nanosecond intervals within a microsecond. - $uuidTime = ((int) $seconds->toString() * 10000000) - + ((int) $microSeconds->toString() * 10) - + 0x01b21dd213814000; + // Calculate the count of 100-nanosecond intervals since the Gregorian + // calendar epoch for the given seconds and microseconds. + $uuidTime = ((int) $seconds->toString() * self::SECOND_INTERVALS) + + ((int) $microSeconds->toString() * self::MICROSECOND_INTERVALS) + + self::GREGORIAN_TO_UNIX_INTERVALS; // Check to see whether we've overflowed the max/min integer size. // If so, we will default to a different time converter. @@ -111,8 +123,10 @@ class PhpTimeConverter implements TimeConverterInterface { $timestamp = $this->calculator->toIntegerValue($uuidTimestamp); + // Convert the 100-nanosecond intervals into seconds and microseconds. $splitTime = $this->splitTime( - ((int) $timestamp->toString() - 0x01b21dd213814000) / 10000000 + ((int) $timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS) + / self::SECOND_INTERVALS ); if (count($splitTime) === 0) {