From e7746f487cb9cca685ffb1b3d7dccc5554b618a4 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Fri, 20 Jul 2018 22:03:00 +0200 Subject: php: Added nanosecond support for Timestamp (#3972) * php: Added nanosecond support for Timestamp * php: Fixed compatibility test --- php/ext/google/protobuf/message.c | 102 +++++++++++++++++++++++++------------ php/ext/google/protobuf/protobuf.h | 4 ++ 2 files changed, 74 insertions(+), 32 deletions(-) (limited to 'php/ext/google') 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 #include +#include #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, ×tamp_seconds); + + zval_dtor(&retval); + zval_dtor(&function_name); } - protobuf_convert_to_int64(&retval, ×tamp); + 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, ×tamp_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 // ---------------------------------------------------------------------------- -- cgit v1.2.3