PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.21
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.21
1.10.25 1.10.24 1.10.23 1.10.22 1.10.21 1.10.20 1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 All 169 releases
woocommerce-pos / vendor / ramsey / uuid / src / Converter / Time / PhpTimeConverter.php

PhpTimeConverter.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.21, at vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php

184 lines 5.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the ramsey/uuid library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <[email protected]>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13 declare(strict_types=1);
14
15 namespace Ramsey\Uuid\Converter\Time;
16
17 use Ramsey\Uuid\Converter\TimeConverterInterface;
18 use Ramsey\Uuid\Math\BrickMathCalculator;
19 use Ramsey\Uuid\Math\CalculatorInterface;
20 use Ramsey\Uuid\Type\Hexadecimal;
21 use Ramsey\Uuid\Type\Integer as IntegerObject;
22 use Ramsey\Uuid\Type\Time;
23
24 use function count;
25 use function dechex;
26 use function explode;
27 use function is_float;
28 use function is_int;
29 use function str_pad;
30 use function strlen;
31 use function substr;
32
33 use const STR_PAD_LEFT;
34 use const STR_PAD_RIGHT;
35
36 /**
37 * PhpTimeConverter uses built-in PHP functions and standard math operations
38 * available to the PHP programming language to provide facilities for
39 * converting parts of time into representations that may be used in UUIDs
40 *
41 * @psalm-immutable
42 */
43 class PhpTimeConverter implements TimeConverterInterface
44 {
45 /**
46 * The number of 100-nanosecond intervals from the Gregorian calendar epoch
47 * to the Unix epoch.
48 */
49 private const GREGORIAN_TO_UNIX_INTERVALS = 0x01b21dd213814000;
50
51 /**
52 * The number of 100-nanosecond intervals in one second.
53 */
54 private const SECOND_INTERVALS = 10000000;
55
56 /**
57 * The number of 100-nanosecond intervals in one microsecond.
58 */
59 private const MICROSECOND_INTERVALS = 10;
60
61 /**
62 * @var CalculatorInterface
63 */
64 private $calculator;
65
66 /**
67 * @var TimeConverterInterface
68 */
69 private $fallbackConverter;
70
71 /**
72 * @var int
73 */
74 private $phpPrecision;
75
76 public function __construct(
77 ?CalculatorInterface $calculator = null,
78 ?TimeConverterInterface $fallbackConverter = null
79 ) {
80 if ($calculator === null) {
81 $calculator = new BrickMathCalculator();
82 }
83
84 if ($fallbackConverter === null) {
85 $fallbackConverter = new GenericTimeConverter($calculator);
86 }
87
88 $this->calculator = $calculator;
89 $this->fallbackConverter = $fallbackConverter;
90 $this->phpPrecision = (int) ini_get('precision');
91 }
92
93 public function calculateTime(string $seconds, string $microseconds): Hexadecimal
94 {
95 $seconds = new IntegerObject($seconds);
96 $microseconds = new IntegerObject($microseconds);
97
98 // Calculate the count of 100-nanosecond intervals since the Gregorian
99 // calendar epoch for the given seconds and microseconds.
100 $uuidTime = ((int) $seconds->toString() * self::SECOND_INTERVALS)
101 + ((int) $microseconds->toString() * self::MICROSECOND_INTERVALS)
102 + self::GREGORIAN_TO_UNIX_INTERVALS;
103
104 // Check to see whether we've overflowed the max/min integer size.
105 // If so, we will default to a different time converter.
106 /** @psalm-suppress RedundantCondition */
107 if (!is_int($uuidTime)) {
108 return $this->fallbackConverter->calculateTime(
109 $seconds->toString(),
110 $microseconds->toString()
111 );
112 }
113
114 return new Hexadecimal(str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT));
115 }
116
117 public function convertTime(Hexadecimal $uuidTimestamp): Time
118 {
119 $timestamp = $this->calculator->toInteger($uuidTimestamp);
120
121 // Convert the 100-nanosecond intervals into seconds and microseconds.
122 $splitTime = $this->splitTime(
123 ((int) $timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS)
124 / self::SECOND_INTERVALS
125 );
126
127 if (count($splitTime) === 0) {
128 return $this->fallbackConverter->convertTime($uuidTimestamp);
129 }
130
131 return new Time($splitTime['sec'], $splitTime['usec']);
132 }
133
134 /**
135 * @param int|float $time The time to split into seconds and microseconds
136 *
137 * @return string[]
138 */
139 private function splitTime($time): array
140 {
141 $split = explode('.', (string) $time, 2);
142
143 // If the $time value is a float but $split only has 1 element, then the
144 // float math was rounded up to the next second, so we want to return
145 // an empty array to allow use of the fallback converter.
146 if (is_float($time) && count($split) === 1) {
147 return [];
148 }
149
150 if (count($split) === 1) {
151 return [
152 'sec' => $split[0],
153 'usec' => '0',
154 ];
155 }
156
157 // If the microseconds are less than six characters AND the length of
158 // the number is greater than or equal to the PHP precision, then it's
159 // possible that we lost some precision for the microseconds. Return an
160 // empty array, so that we can choose to use the fallback converter.
161 if (strlen($split[1]) < 6 && strlen((string) $time) >= $this->phpPrecision) {
162 return [];
163 }
164
165 $microseconds = $split[1];
166
167 // Ensure the microseconds are no longer than 6 digits. If they are,
168 // truncate the number to the first 6 digits and round up, if needed.
169 if (strlen($microseconds) > 6) {
170 $roundingDigit = (int) substr($microseconds, 6, 1);
171 $microseconds = (int) substr($microseconds, 0, 6);
172
173 if ($roundingDigit >= 5) {
174 $microseconds++;
175 }
176 }
177
178 return [
179 'sec' => $split[0],
180 'usec' => str_pad((string) $microseconds, 6, '0', STR_PAD_RIGHT),
181 ];
182 }
183 }
184