|
|
|
@ -38,6 +38,9 @@ use Google\Protobuf\Internal\MapField; |
|
|
|
|
|
|
|
|
|
class GPBUtil |
|
|
|
|
{ |
|
|
|
|
const NANOS_PER_MILLISECOND = 1000000; |
|
|
|
|
const NANOS_PER_MICROSECOND = 1000; |
|
|
|
|
|
|
|
|
|
public static function divideInt64ToInt32($value, &$high, &$low, $trim = false) |
|
|
|
|
{ |
|
|
|
|
$isNeg = (bccomp($value, 0) < 0); |
|
|
|
@ -340,4 +343,81 @@ class GPBUtil |
|
|
|
|
} |
|
|
|
|
return $result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function parseTimestamp($timestamp) |
|
|
|
|
{ |
|
|
|
|
// prevent parsing timestamps containing with the non-existant year "0000" |
|
|
|
|
// DateTime::createFromFormat parses without failing but as a nonsensical date |
|
|
|
|
if (substr($timestamp, 0, 4) === "0000") { |
|
|
|
|
throw new \Exception("Year cannot be zero."); |
|
|
|
|
} |
|
|
|
|
// prevent parsing timestamps ending with a lowercase z |
|
|
|
|
if (substr($timestamp, -1, 1) === "z") { |
|
|
|
|
throw new \Exception("Timezone cannot be a lowercase z."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$nanoseconds = 0; |
|
|
|
|
$periodIndex = strpos($timestamp, "."); |
|
|
|
|
if ($periodIndex !== false) { |
|
|
|
|
$nanosecondsLength = 0; |
|
|
|
|
// find the next non-numeric character in the timestamp to calculate |
|
|
|
|
// the length of the nanoseconds text |
|
|
|
|
for ($i = $periodIndex + 1, $length = strlen($timestamp); $i < $length; $i++) { |
|
|
|
|
if (!is_numeric($timestamp[$i])) { |
|
|
|
|
$nanosecondsLength = $i - ($periodIndex + 1); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if ($nanosecondsLength % 3 !== 0) { |
|
|
|
|
throw new \Exception("Nanoseconds must be disible by 3."); |
|
|
|
|
} |
|
|
|
|
if ($nanosecondsLength > 9) { |
|
|
|
|
throw new \Exception("Nanoseconds must be in the range of 0 to 999,999,999 nanoseconds."); |
|
|
|
|
} |
|
|
|
|
if ($nanosecondsLength > 0) { |
|
|
|
|
$nanoseconds = substr($timestamp, $periodIndex + 1, $nanosecondsLength); |
|
|
|
|
$nanoseconds = intval($nanoseconds); |
|
|
|
|
|
|
|
|
|
// remove the nanoseconds and preceding period from the timestamp |
|
|
|
|
$date = substr($timestamp, 0, $periodIndex - 1); |
|
|
|
|
$timezone = substr($timestamp, $periodIndex + $nanosecondsLength); |
|
|
|
|
$timestamp = $date.$timezone; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$date = \DateTime::createFromFormat(\DateTime::RFC3339, $timestamp, new \DateTimeZone("UTC")); |
|
|
|
|
if ($date === false) { |
|
|
|
|
throw new \Exception("Invalid RFC 3339 timestamp."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$value = new \Google\Protobuf\Timestamp(); |
|
|
|
|
$seconds = $date->format("U"); |
|
|
|
|
$value->setSeconds($seconds); |
|
|
|
|
$value->setNanos($nanoseconds); |
|
|
|
|
return $value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function formatTimestamp($value) |
|
|
|
|
{ |
|
|
|
|
$nanoseconds = static::getNanosecondsForTimestamp($value->getNanos()); |
|
|
|
|
if (!empty($nanoseconds)) { |
|
|
|
|
$nanoseconds = ".".$nanoseconds; |
|
|
|
|
} |
|
|
|
|
$date = new \DateTime('@'.$value->getSeconds(), new \DateTimeZone("UTC")); |
|
|
|
|
return $date->format("Y-m-d\TH:i:s".$nanoseconds."\Z"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function getNanosecondsForTimestamp($nanoseconds) |
|
|
|
|
{ |
|
|
|
|
if ($nanoseconds == 0) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
if ($nanoseconds % static::NANOS_PER_MILLISECOND == 0) { |
|
|
|
|
return sprintf('%03d', $nanoseconds / static::NANOS_PER_MILLISECOND); |
|
|
|
|
} |
|
|
|
|
if ($nanoseconds % static::NANOS_PER_MICROSECOND == 0) { |
|
|
|
|
return sprintf('%06d', $nanoseconds / static::NANOS_PER_MICROSECOND); |
|
|
|
|
} |
|
|
|
|
return sprintf('%09d', $nanoseconds); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|