aboutsummaryrefslogtreecommitdiffhomepage
path: root/php/src/Google/Protobuf/Internal/GPBUtil.php
diff options
context:
space:
mode:
authorGravatar Jack Wakefield <jackwakefield91@gmail.com>2017-09-10 23:17:50 +0100
committerGravatar Paul Yang <TeBoring@users.noreply.github.com>2017-09-10 15:17:50 -0700
commit174c82d8cef27be5cb9d8491dd1e26d27898870b (patch)
tree88566308f3395a0990e0bd3f54cb0fbe4897daa5 /php/src/Google/Protobuf/Internal/GPBUtil.php
parent2ad5c0a86443f567241e0295c313baf4f0e15379 (diff)
Add well-known timestamps to JSON for PHP (#3564)
Diffstat (limited to 'php/src/Google/Protobuf/Internal/GPBUtil.php')
-rw-r--r--php/src/Google/Protobuf/Internal/GPBUtil.php80
1 files changed, 80 insertions, 0 deletions
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 84e8ecf0..a27220a0 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -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);
+ }
}