aboutsummaryrefslogtreecommitdiff
path: root/php
diff options
context:
space:
mode:
authorLeonard Hecker <leonard@hecker.io>2018-07-20 22:03:00 +0200
committerPaul Yang <TeBoring@users.noreply.github.com>2018-07-20 13:03:00 -0700
commite7746f487cb9cca685ffb1b3d7dccc5554b618a4 (patch)
tree851e32ef5032765a8ad61c30b212aefc5f12703a /php
parent656f64ec0b5dff6816886d66a0124ab4f8d1fd4b (diff)
downloadprotobuf-e7746f487cb9cca685ffb1b3d7dccc5554b618a4.tar.gz
protobuf-e7746f487cb9cca685ffb1b3d7dccc5554b618a4.tar.bz2
protobuf-e7746f487cb9cca685ffb1b3d7dccc5554b618a4.zip
php: Added nanosecond support for Timestamp (#3972)
* php: Added nanosecond support for Timestamp * php: Fixed compatibility test
Diffstat (limited to 'php')
-rw-r--r--php/ext/google/protobuf/message.c102
-rw-r--r--php/ext/google/protobuf/protobuf.h4
-rw-r--r--php/src/Google/Protobuf/Timestamp.php9
-rwxr-xr-xphp/tests/compatibility_test.sh1
-rw-r--r--php/tests/memory_leak_test.php2
-rw-r--r--php/tests/well_known_test.php3
6 files changed, 83 insertions, 38 deletions
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
index 9363191d..76d85ab0 100644
--- a/php/ext/google/protobuf/message.c
+++ b/php/ext/google/protobuf/message.c
@@ -30,6 +30,7 @@
#include <php.h>
#include <stdlib.h>
+#include <inttypes.h>
#include "protobuf.h"
#include "utf8.h"
@@ -1249,28 +1250,62 @@ PHP_METHOD(Timestamp, fromDateTime) {
return;
}
- // Get timestamp from Datetime object.
- zval retval;
- zval function_name;
- int64_t timestamp;
+ int64_t timestamp_seconds;
+ {
+ zval retval;
+ zval function_name;
#if PHP_MAJOR_VERSION < 7
- INIT_ZVAL(retval);
- INIT_ZVAL(function_name);
+ INIT_ZVAL(retval);
+ INIT_ZVAL(function_name);
#endif
- PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1);
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1);
- if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
- ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) {
- zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
- return;
+ if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
+ ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) {
+ zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
+ return;
+ }
+
+ protobuf_convert_to_int64(&retval, &timestamp_seconds);
+
+ zval_dtor(&retval);
+ zval_dtor(&function_name);
}
- protobuf_convert_to_int64(&retval, &timestamp);
+ int64_t timestamp_micros;
+ {
+ zval retval;
+ zval function_name;
+ zval format_string;
- zval_dtor(&retval);
- zval_dtor(&function_name);
+#if PHP_MAJOR_VERSION < 7
+ INIT_ZVAL(retval);
+ INIT_ZVAL(function_name);
+ INIT_ZVAL(format_string);
+#endif
+
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_format", 1);
+ PHP_PROTO_ZVAL_STRING(&format_string, "u", 1);
+
+ CACHED_VALUE params[2] = {
+ ZVAL_PTR_TO_CACHED_VALUE(datetime),
+ ZVAL_TO_CACHED_VALUE(format_string),
+ };
+
+ if (call_user_function(EG(function_table), NULL, &function_name, &retval,
+ ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) {
+ zend_error(E_ERROR, "Cannot format DateTime.");
+ return;
+ }
+
+ protobuf_convert_to_int64(&retval, &timestamp_micros);
+
+ zval_dtor(&retval);
+ zval_dtor(&function_name);
+ zval_dtor(&format_string);
+ }
// Set seconds
MessageHeader* self = UNBOX(MessageHeader, getThis());
@@ -1278,13 +1313,13 @@ PHP_METHOD(Timestamp, fromDateTime) {
upb_msgdef_ntofz(self->descriptor->msgdef, "seconds");
void* storage = message_data(self);
void* memory = slot_memory(self->descriptor->layout, storage, field);
- *(int64_t*)memory = timestamp;
+ *(int64_t*)memory = timestamp_seconds;
// Set nanos
field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos");
storage = message_data(self);
memory = slot_memory(self->descriptor->layout, storage, field);
- *(int32_t*)memory = 0;
+ *(int32_t*)memory = timestamp_micros * 1000;
RETURN_NULL();
}
@@ -1303,38 +1338,41 @@ PHP_METHOD(Timestamp, toDateTime) {
memory = slot_memory(self->descriptor->layout, storage, field);
int32_t nanos = *(int32_t*)memory;
- // Get formated time string.
- char formated_time[50];
- time_t raw_time = seconds;
- struct tm *utc_time = gmtime(&raw_time);
- strftime(formated_time, sizeof(formated_time), "%Y-%m-%dT%H:%M:%SUTC",
- utc_time);
+ // Get formatted time string.
+ char formatted_time[32];
+ snprintf(formatted_time, sizeof(formatted_time), "%" PRId64 ".%06" PRId32,
+ seconds, nanos / 1000);
// Create Datetime object.
zval datetime;
- zval formated_time_php;
zval function_name;
- int64_t timestamp = 0;
+ zval format_string;
+ zval formatted_time_php;
#if PHP_MAJOR_VERSION < 7
INIT_ZVAL(function_name);
- INIT_ZVAL(formated_time_php);
+ INIT_ZVAL(format_string);
+ INIT_ZVAL(formatted_time_php);
#endif
- PHP_PROTO_ZVAL_STRING(&function_name, "date_create", 1);
- PHP_PROTO_ZVAL_STRING(&formated_time_php, formated_time, 1);
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_create_from_format", 1);
+ PHP_PROTO_ZVAL_STRING(&format_string, "U.u", 1);
+ PHP_PROTO_ZVAL_STRING(&formatted_time_php, formatted_time, 1);
- CACHED_VALUE params[1] = {ZVAL_TO_CACHED_VALUE(formated_time_php)};
+ CACHED_VALUE params[2] = {
+ ZVAL_TO_CACHED_VALUE(format_string),
+ ZVAL_TO_CACHED_VALUE(formatted_time_php),
+ };
- if (call_user_function(EG(function_table), NULL,
- &function_name, &datetime, 1,
- params TSRMLS_CC) == FAILURE) {
+ if (call_user_function(EG(function_table), NULL, &function_name, &datetime,
+ ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) {
zend_error(E_ERROR, "Cannot create DateTime.");
return;
}
- zval_dtor(&formated_time_php);
zval_dtor(&function_name);
+ zval_dtor(&format_string);
+ zval_dtor(&formatted_time_php);
#if PHP_MAJOR_VERSION < 7
zval* datetime_ptr = &datetime;
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index 20035ab7..3ef4c84b 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -42,6 +42,10 @@
#define MAX_LENGTH_OF_INT64 20
#define SIZEOF_INT64 8
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
// -----------------------------------------------------------------------------
// PHP7 Wrappers
// ----------------------------------------------------------------------------
diff --git a/php/src/Google/Protobuf/Timestamp.php b/php/src/Google/Protobuf/Timestamp.php
index a793c7e3..6d26f6c5 100644
--- a/php/src/Google/Protobuf/Timestamp.php
+++ b/php/src/Google/Protobuf/Timestamp.php
@@ -182,18 +182,19 @@ class Timestamp extends \Google\Protobuf\Internal\Message
*/
public function fromDateTime(\DateTime $datetime)
{
- $this->seconds = $datetime->format('U');
- $this->nanos = 0;
+ $this->seconds = $datetime->getTimestamp();
+ $this->nanos = 1000 * $datetime->format('u');
}
/**
- * Converts Timestamp to PHP DateTime. Nano second is ignored.
+ * Converts Timestamp to PHP DateTime.
*
* @return \DateTime $datetime
*/
public function toDateTime()
{
- return \DateTime::createFromFormat('U', $this->seconds);
+ $time = sprintf('%s.%06d', $this->seconds, $this->nanos / 1000);
+ return \DateTime::createFromFormat('U.u', $time);
}
}
diff --git a/php/tests/compatibility_test.sh b/php/tests/compatibility_test.sh
index b377d85c..c4d6325d 100755
--- a/php/tests/compatibility_test.sh
+++ b/php/tests/compatibility_test.sh
@@ -124,6 +124,7 @@ sed -i.bak '/php_implementation_test.php/d' phpunit.xml
sed -i.bak '/generated_phpdoc_test.php/d' phpunit.xml
sed -i.bak 's/generated_phpdoc_test.php//g' tests/test.sh
sed -i.bak '/memory_leak_test.php/d' tests/test.sh
+sed -i.bak '/^ public function testTimestamp()$/,/^ }$/d' tests/well_known_test.php
for t in "${tests[@]}"
do
remove_error_test tests/$t
diff --git a/php/tests/memory_leak_test.php b/php/tests/memory_leak_test.php
index 4e3874b7..f3bcb963 100644
--- a/php/tests/memory_leak_test.php
+++ b/php/tests/memory_leak_test.php
@@ -152,7 +152,7 @@ date_default_timezone_set('UTC');
$from = new DateTime('2011-01-01T15:03:01.012345UTC');
$timestamp->fromDateTime($from);
assert($from->format('U') == $timestamp->getSeconds());
-assert(0 == $timestamp->getNanos());
+assert(1000 * $from->format('u') == $timestamp->getNanos());
$to = $timestamp->toDateTime();
assert(\DateTime::class == get_class($to));
diff --git a/php/tests/well_known_test.php b/php/tests/well_known_test.php
index 1e8c4f42..9f2661fa 100644
--- a/php/tests/well_known_test.php
+++ b/php/tests/well_known_test.php
@@ -312,11 +312,12 @@ class WellKnownTest extends TestBase {
$from = new DateTime('2011-01-01T15:03:01.012345UTC');
$timestamp->fromDateTime($from);
$this->assertEquals($from->format('U'), $timestamp->getSeconds());
- $this->assertSame(0, $timestamp->getNanos());
+ $this->assertEquals(1000 * $from->format('u'), $timestamp->getNanos());
$to = $timestamp->toDateTime();
$this->assertSame(\DateTime::class, get_class($to));
$this->assertSame($from->format('U'), $to->format('U'));
+ $this->assertSame($from->format('u'), $to->format('u'));
}
public function testType()