From 26a5acf601ef1c18561260c959f0da29923bdfcb Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 16 Dec 2021 09:48:54 +0100 Subject: [PATCH] fix timestamp support --- ion.c | 7 +++++-- ion.stub.php | 3 +++ ion_arginfo.h | 14 +++++++++++++- ion_private.h | 38 +++++++++++++++++++++++--------------- tests/Timestamp.phpt | 36 +++++++++++++++++++++++++++++++----- 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/ion.c b/ion.c index 5a691fd..6bf02f5 100644 --- a/ion.c +++ b/ion.c @@ -1506,6 +1506,9 @@ PHP_MINIT_FUNCTION(ion) // Annotation ce_Annotation = register_class_ion_Annotation(); + // Catalog + php_ion_register(catalog, Catalog); + // Collection ce_Collection = register_class_ion_Collection(); @@ -1539,9 +1542,8 @@ PHP_MINIT_FUNCTION(ion) ce_Symbol_System_SID = register_class_ion_Symbol_System_SID(); // Timestamp - php_ion_register(timestamp, Timestamp, php_date_get_date_ce()); + ce_Timestamp = register_class_ion_Timestamp(php_date_get_date_ce()); ce_Timestamp_Precision = register_class_ion_Timestamp_Precision(); - php_ion_register(catalog, Catalog); // Type php_ion_register(type, Type); @@ -1582,6 +1584,7 @@ PHP_GSHUTDOWN_FUNCTION(ion) } static zend_module_dep ion_module_deps[] = { + ZEND_MOD_REQUIRED("date") ZEND_MOD_REQUIRED("spl") ZEND_MOD_END }; diff --git a/ion.stub.php b/ion.stub.php index e874b92..ef6bbef 100644 --- a/ion.stub.php +++ b/ion.stub.php @@ -162,6 +162,9 @@ enum Precision : int { case Min = 0x1|0x2|0x4|0x10; case Sec = 0x1|0x2|0x4|0x10|0x20; case Frac = 0x1|0x2|0x4|0x10|0x20|0x40; + case MinTZ = 0x1|0x2|0x4|0x10|0x80; + case SecTZ = 0x1|0x2|0x4|0x10|0x20|0x80; + case FracTZ = 0x1|0x2|0x4|0x10|0x20|0x40|0x80; } namespace ion; class Timestamp extends \DateTime { diff --git a/ion_arginfo.h b/ion_arginfo.h index 187891b..5d48e03 100644 --- a/ion_arginfo.h +++ b/ion_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3639336622da610f8866722b870d87563646465f */ + * Stub hash: 31c610f8d923117a4e69635ba3eb9387087f66fd */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_serialize, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0) @@ -1344,6 +1344,18 @@ static zend_class_entry *register_class_ion_Timestamp_Precision(void) ZVAL_LONG(&enum_case_Frac_value, 119); zend_enum_add_case_cstr(class_entry, "Frac", &enum_case_Frac_value); + zval enum_case_MinTZ_value; + ZVAL_LONG(&enum_case_MinTZ_value, 151); + zend_enum_add_case_cstr(class_entry, "MinTZ", &enum_case_MinTZ_value); + + zval enum_case_SecTZ_value; + ZVAL_LONG(&enum_case_SecTZ_value, 183); + zend_enum_add_case_cstr(class_entry, "SecTZ", &enum_case_SecTZ_value); + + zval enum_case_FracTZ_value; + ZVAL_LONG(&enum_case_FracTZ_value, 247); + zend_enum_add_case_cstr(class_entry, "FracTZ", &enum_case_FracTZ_value); + return class_entry; } diff --git a/ion_private.h b/ion_private.h index 809f853..c233333 100644 --- a/ion_private.h +++ b/ion_private.h @@ -544,6 +544,9 @@ typedef php_date_obj php_ion_timestamp; static inline zend_long php_usec_from_ion(const decQuad *frac, decContext *ctx) { + if (!ctx) { + ctx = &g_dec_ctx; + } decQuad microsecs, result; decQuadMultiply(&result, decQuadFromInt32(µsecs, 1000000), frac, ctx); return (zend_long) decQuadToUInt32(&result, ctx, DEC_ROUND_HALF_EVEN); @@ -551,13 +554,16 @@ static inline zend_long php_usec_from_ion(const decQuad *frac, decContext *ctx) static inline decQuad *ion_ts_frac_from_usec(decQuad *frac, zend_long usec, decContext *ctx) { + if (!ctx) { + ctx = &g_dec_ctx; + } decQuad microsecs, us; return decQuadDivide(frac, decQuadFromInt32(&us, usec), decQuadFromInt32(µsecs, 1000000), ctx); } -static inline zend_string *php_dt_format_from_precision(uint8_t precision) +static inline zend_string *php_dt_format_from_precision(int precision) { - switch (precision) { + switch (precision & 0x7f) { case ION_TS_FRAC: return zend_string_init(ZEND_STRL("c"), 0); case ION_TS_SEC: @@ -579,7 +585,9 @@ static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContex { timelib_time *time = timelib_time_ctor(); - switch (ts->precision) { + int precision = ION_TS_FRAC; + ion_timestamp_get_precision(ts, &precision); + switch (precision) { case ION_TS_FRAC: time->us = php_usec_from_ion(&ts->fraction, ctx); /* fallthrough */ @@ -601,10 +609,16 @@ static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContex /* fallthrough */ default: time->z = ts->tz_offset * 60; + if (time->z) { + time->zone_type = TIMELIB_ZONETYPE_OFFSET; + } else { + time->zone_type = TIMELIB_ZONETYPE_ID; + time->tz_info = get_timezone_info(); + } } if (fmt) { - *fmt = php_dt_format_from_precision(ts->precision); + *fmt = php_dt_format_from_precision(precision); } return time; } @@ -614,11 +628,11 @@ static inline ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_ memset(buf, 0, sizeof(*buf)); zval tmp; - uint8_t precision = Z_LVAL_P(zend_read_property(ts->std.ce, &ts->std, ZEND_STRL("precision"), 0, &tmp)); + int precision = Z_LVAL_P(zend_read_property(ts->std.ce, &ts->std, ZEND_STRL("precision"), 0, &tmp)); if (!precision || precision > ION_TS_FRAC) { zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG, - "Invalid precision (%u) of ion\\Timestamp", (unsigned) precision); + "Invalid precision (%d) of ion\\Timestamp", precision); } else switch ((buf->precision = precision)) { case ION_TS_FRAC: ion_ts_frac_from_usec(&buf->fraction, ts->time->us, ctx); @@ -641,6 +655,9 @@ static inline ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_ /* fallthrough */ default: buf->tz_offset = ts->time->z / 60; + if (buf->tz_offset) { + buf->precision |= 0x80; + } } return buf; @@ -658,15 +675,6 @@ static inline void php_ion_timestamp_ctor(php_ion_timestamp *obj, zend_long prec zend_string_release(fmt); } -static inline void php_ion_timestamp_dtor(php_ion_timestamp *obj) -{ - if (obj->time) { - timelib_time_dtor(obj->time); - } -} - -php_ion_decl(timestamp, Timestamp, php_ion_timestamp_dtor(obj)); - typedef struct php_ion_catalog { ION_CATALOG *cat; zend_object std; diff --git a/tests/Timestamp.phpt b/tests/Timestamp.phpt index cb50cf0..6b263ec 100644 --- a/tests/Timestamp.phpt +++ b/tests/Timestamp.phpt @@ -2,6 +2,8 @@ ion\Timestamp --EXTENSIONS-- ion +--INI-- +date.timezone=CET --FILE-- TEST int(7) ["format"]=> string(7) "Y-m-d\T" + ["date"]=> + string(26) "2021-12-07 14:08:51.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" } string(11) "2021-12-07T" -object(ion\Timestamp)#%d (2) { +object(ion\Timestamp)#%d (5) { ["precision"]=> int(7) ["format"]=> string(7) "Y-m-d\T" + ["date"]=> + string(26) "2021-12-07 14:08:51.000000" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "+00:00" } string(11) "2021-12-07T" -object(ion\Timestamp)#%d (2) { +object(ion\Timestamp)#%d (5) { ["precision"]=> int(23) ["format"]=> string(11) "Y-m-d\TH:iP" + ["date"]=> + string(26) "2020-10-01 00:00:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "CET" } -string(22) "2020-10-01T00:00+00:00" -object(ion\Timestamp)#%d (2) { +string(22) "2020-10-01T00:00+02:00" +object(ion\Timestamp)#%d (5) { ["precision"]=> int(7) ["format"]=> string(7) "Y-m-d\T" + ["date"]=> + string(26) "2000-10-01 00:00:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "CET" } string(11) "2000-10-01T" DONE -- 2.30.2