From: Michael Wallner Date: Tue, 7 Dec 2021 14:30:17 +0000 (+0100) Subject: improve timestamp support X-Git-Tag: v0.1.0~96 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=04f2847752eeaa63ca7d551e4a3875b181ca533b;p=awesomized%2Fext-ion improve timestamp support --- diff --git a/.gitignore b/.gitignore index ae434fe..6c67a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ tests/**/*.log tests/**/*.sh tests/**/*.db tests/**/*.mem +tests/Timestamp/ tmp-php.ini diff --git a/ion.c b/ion.c index 73eee24..1b8340d 100644 --- a/ion.c +++ b/ion.c @@ -88,20 +88,24 @@ ZEND_METHOD(ion_Symbol, equals) } ZEND_METHOD(ion_Timestamp, __construct) { - zend_long precision; - zend_string *fmt = NULL, *dt = NULL; - zval *tz = NULL; php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS)); PTR_CHECK(obj); + zend_long precision; + zend_object *precision_obj; + zend_string *fmt = NULL, *dt = NULL; + zval *tz = NULL; ZEND_PARSE_PARAMETERS_START(1, 4) - Z_PARAM_LONG(precision) + Z_PARAM_OBJ_OF_CLASS_OR_LONG(precision_obj, ce_Timestamp_Precision, precision) Z_PARAM_OPTIONAL Z_PARAM_STR_OR_NULL(fmt) - Z_PARAM_STR(dt) + Z_PARAM_STR_OR_NULL(dt) Z_PARAM_ZVAL(tz) ZEND_PARSE_PARAMETERS_END(); + if (precision_obj) { + precision = Z_LVAL_P(zend_enum_fetch_case_value(precision_obj)); + } php_ion_timestamp_ctor(obj, precision, fmt, dt, tz); } ZEND_METHOD(ion_Timestamp, __toString) @@ -1472,6 +1476,7 @@ PHP_MINIT_FUNCTION(ion) php_ion_register(decimal, Decimal); php_ion_register(decimal_ctx, Decimal_Context); php_ion_register(timestamp, Timestamp, php_date_get_date_ce()); + ce_Timestamp_Precision = register_class_ion_Timestamp_Precision(); php_ion_register(catalog, Catalog); ce_Reader = register_class_ion_Reader(spl_ce_RecursiveIterator); diff --git a/ion.stub.php b/ion.stub.php index 22504c7..cbddd8d 100644 --- a/ion.stub.php +++ b/ion.stub.php @@ -122,12 +122,24 @@ class Decimal { public function toInt() : int {} } +namespace ion\Timestamp; +enum Precision : int { + case Year = 0x1; + case Month = 0x1|0x2; + case Day = 0x1|0x2|0x4; + case Min = 0x1|0x2|0x4|0x10; + case Sec = 0x1|0x2|0x4|0x10|0x20; + case Frac = 0x1|0x2|0x4|0x10|0x20|0x40; +} namespace ion; class Timestamp extends \DateTime { + public readonly int $precision; + public readonly string $format; + public function __construct( - public readonly int $precision, - public readonly string $format = "c", - string $datetime = "now", + Timestamp\Precision|int $precision, + ?string $format = null, + ?string $datetime = null, ?\DateTimeZone $timezone = null, ) {} diff --git a/ion_arginfo.h b/ion_arginfo.h index d11e88a..1b600b5 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: 9972b27bc2f7f20e59aae26777e1a674f1606c11 */ + * Stub hash: 20996b59177d52516ad45582152909be017ba39d */ 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) @@ -51,9 +51,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_toInt, 0, 0, I ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Timestamp___construct, 0, 0, 1) - ZEND_ARG_TYPE_INFO(0, precision, IS_LONG, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 0, "\"c\"") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, datetime, IS_STRING, 0, "\"now\"") + ZEND_ARG_OBJ_TYPE_MASK(0, precision, ion\\Timestamp\\Precision, MAY_BE_LONG, NULL) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, datetime, IS_STRING, 1, "null") ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, timezone, DateTimeZone, 1, "null") ZEND_END_ARG_INFO() @@ -595,6 +595,11 @@ static const zend_function_entry class_ion_Decimal_methods[] = { }; +static const zend_function_entry class_ion_Timestamp_Precision_methods[] = { + ZEND_FE_END +}; + + static const zend_function_entry class_ion_Timestamp_methods[] = { ZEND_ME(ion_Timestamp, __construct, arginfo_class_ion_Timestamp___construct, ZEND_ACC_PUBLIC) ZEND_ME(ion_Timestamp, __toString, arginfo_class_ion_Timestamp___toString, ZEND_ACC_PUBLIC) @@ -1157,6 +1162,37 @@ static zend_class_entry *register_class_ion_Decimal(void) return class_entry; } +static zend_class_entry *register_class_ion_Timestamp_Precision(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("ion\\Timestamp\\Precision", IS_LONG, class_ion_Timestamp_Precision_methods); + + zval enum_case_Year_value; + ZVAL_LONG(&enum_case_Year_value, 1); + zend_enum_add_case_cstr(class_entry, "Year", &enum_case_Year_value); + + zval enum_case_Month_value; + ZVAL_LONG(&enum_case_Month_value, 3); + zend_enum_add_case_cstr(class_entry, "Month", &enum_case_Month_value); + + zval enum_case_Day_value; + ZVAL_LONG(&enum_case_Day_value, 7); + zend_enum_add_case_cstr(class_entry, "Day", &enum_case_Day_value); + + zval enum_case_Min_value; + ZVAL_LONG(&enum_case_Min_value, 23); + zend_enum_add_case_cstr(class_entry, "Min", &enum_case_Min_value); + + zval enum_case_Sec_value; + ZVAL_LONG(&enum_case_Sec_value, 55); + zend_enum_add_case_cstr(class_entry, "Sec", &enum_case_Sec_value); + + zval enum_case_Frac_value; + ZVAL_LONG(&enum_case_Frac_value, 119); + zend_enum_add_case_cstr(class_entry, "Frac", &enum_case_Frac_value); + + return class_entry; +} + static zend_class_entry *register_class_ion_Timestamp(zend_class_entry *class_entry_DateTime) { zend_class_entry ce, *class_entry; diff --git a/ion_private.h b/ion_private.h index 1ac49d9..5b6a461 100644 --- a/ion_private.h +++ b/ion_private.h @@ -151,6 +151,7 @@ static zend_class_entry *ce_Symbol_System_SID, *ce_Symbol_Table, *ce_Timestamp, + *ce_Timestamp_Precision, *ce_Type, *ce_Writer, *ce_Writer_Options, @@ -430,26 +431,6 @@ static inline void php_ion_decimal_dtor(php_ion_decimal *obj) typedef php_date_obj php_ion_timestamp; -static inline void php_ion_timestamp_ctor(php_ion_timestamp *obj, zend_long precision, zend_string *fmt, zend_string *dt, zval *tz) -{ - if (!obj->time) { - php_date_initialize(obj, dt ? dt->val : "now", dt ? dt->len : 3, fmt ? fmt->val : NULL, tz, PHP_DATE_INIT_CTOR); - } - zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("precision"), precision); - if (fmt) { - zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("format"), fmt); - } else { - zend_update_property_stringl(obj->std.ce, &obj->std, ZEND_STRL("format"), ZEND_STRL("c")); - } -} - -static inline void php_ion_timestamp_dtor(php_ion_timestamp *obj) -{ - if (obj->time) { - timelib_time_dtor(obj->time); - } -} - static inline zend_long php_usec_from_ion(const decQuad *frac, decContext *ctx) { decQuad microsecs, result; @@ -463,6 +444,26 @@ static inline decQuad *ion_ts_frac_from_usec(decQuad *frac, zend_long usec, decC return decQuadDivide(frac, decQuadFromInt32(&us, usec), decQuadFromInt32(µsecs, 1000000), ctx); } +static inline zend_string *php_dt_format_from_precision(uint8_t precision) +{ + switch (precision) { + case ION_TS_FRAC: + return zend_string_init(ZEND_STRL("c"), 0); + case ION_TS_SEC: + return zend_string_init(ZEND_STRL("Y-m-d\\TH:i:sP"), 0); + case ION_TS_MIN: + return zend_string_init(ZEND_STRL("Y-m-d\\TH:iP"), 0); + case ION_TS_DAY: + return zend_string_init(ZEND_STRL("Y-m-d\\T"), 0); + case ION_TS_MONTH: + return zend_string_init(ZEND_STRL("Y-m\\T"), 0); + case ION_TS_YEAR: + return zend_string_init(ZEND_STRL("Y\\T"), 0); + default: + return zend_string_init(ZEND_STRL("c"), 0); + } +} + static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx, zend_string **fmt) { timelib_time *time = timelib_time_ctor(); @@ -470,34 +471,30 @@ static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContex switch (ts->precision) { case ION_TS_FRAC: time->us = php_usec_from_ion(&ts->fraction, ctx); - if (fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0); /* fallthrough */ case ION_TS_SEC: time->s = ts->seconds; - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:i:sP"), 0); /* fallthrough */ case ION_TS_MIN: time->i = ts->minutes; time->h = ts->hours; - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:iP"), 0); /* fallthrough */ case ION_TS_DAY: time->d = ts->day; - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\T"), 0); /* fallthrough */ case ION_TS_MONTH: time->m = ts->month; - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m\\T"), 0); /* fallthrough */ case ION_TS_YEAR: time->y = ts->year; - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y\\T"), 0); /* fallthrough */ default: - if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0); time->z = ts->tz_offset * 60; } + if (fmt) { + fmt = php_dt_format_from_precision(ts->precision); + } return time; } @@ -538,6 +535,25 @@ static inline ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_ return buf; } +static inline void php_ion_timestamp_ctor(php_ion_timestamp *obj, zend_long precision, zend_string *fmt, zend_string *dt, zval *tz) +{ + if (!obj->time) { + php_date_initialize(obj, dt ? dt->val : "", dt ? dt->len : 0, fmt ? fmt->val : NULL, tz, PHP_DATE_INIT_CTOR); + } + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("precision"), precision); + + fmt = php_dt_format_from_precision(precision); + zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("format"), fmt); + zend_string_release(fmt); +} + +static inline void php_ion_timestamp_dtor(php_ion_timestamp *obj) +{ + if (obj->time) { + timelib_time_dtor(obj->time); + } +} + typedef struct php_ion_catalog { ION_CATALOG *cat; zend_object std; diff --git a/tests/Timestamp.phpt b/tests/Timestamp.phpt new file mode 100644 index 0000000..cb50cf0 --- /dev/null +++ b/tests/Timestamp.phpt @@ -0,0 +1,53 @@ +--TEST-- +ion\Timestamp +--EXTENSIONS-- +ion +--FILE-- +TEST +value, datetime:$full),(string)$t); +var_dump($t=new Timestamp(Timestamp\Precision::Min, datetime:"2020-10-01"),(string)$t); +var_dump($t=new Timestamp(Timestamp\Precision::Day, "!Y-m", "2000-10"),(string)$t); +?> +DONE +--EXPECTF-- +TEST +caught empty +object(ion\Timestamp)#%d (2) { + ["precision"]=> + int(7) + ["format"]=> + string(7) "Y-m-d\T" +} +string(11) "2021-12-07T" +object(ion\Timestamp)#%d (2) { + ["precision"]=> + int(7) + ["format"]=> + string(7) "Y-m-d\T" +} +string(11) "2021-12-07T" +object(ion\Timestamp)#%d (2) { + ["precision"]=> + int(23) + ["format"]=> + string(11) "Y-m-d\TH:iP" +} +string(22) "2020-10-01T00:00+00:00" +object(ion\Timestamp)#%d (2) { + ["precision"]=> + int(7) + ["format"]=> + string(7) "Y-m-d\T" +} +string(11) "2000-10-01T" +DONE