Skip to content

Commit 99e48d3

Browse files
committed
Merge branch 'datefmt_tz_cal_interop'
* datefmt_tz_cal_interop: Readded accidentally removed line Added IntlDateFormatter::formatObject(). Refactor Refactored internal_get_timestamp() Unified zval -> UDate conversions
2 parents 11a5afe + 2498c90 commit 99e48d3

19 files changed

+810
-245
lines changed

ext/intl/calendar/calendar_methods.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
#include <unicode/locid.h>
2424
#include <unicode/calendar.h>
2525
#include <unicode/ustring.h>
26+
2627
#include "../intl_convertcpp.h"
28+
#include "../common/common_date.h"
29+
2730
extern "C" {
2831
#include "../php_intl.h"
2932
#define USE_TIMEZONE_POINTER 1

ext/intl/common/common_date.cpp

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Authors: Gustavo Lopes <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "../intl_cppshims.h"
18+
19+
#include <unicode/calendar.h>
20+
21+
extern "C" {
22+
#include "../php_intl.h"
23+
#define USE_CALENDAR_POINTER 1
24+
#include "../calendar/calendar_class.h"
25+
#include <ext/date/php_date.h>
26+
}
27+
28+
#ifndef INFINITY
29+
#define INFINITY (DBL_MAX+DBL_MAX)
30+
#endif
31+
32+
#ifndef NAN
33+
#define NAN (INFINITY-INFINITY)
34+
#endif
35+
36+
/* {{{ timezone_convert_datetimezone
37+
* The timezone in DateTime and DateTimeZone is not unified. */
38+
U_CFUNC TimeZone *timezone_convert_datetimezone(int type,
39+
void *object,
40+
int is_datetime,
41+
intl_error *outside_error,
42+
const char *func TSRMLS_DC)
43+
{
44+
char *id = NULL,
45+
offset_id[] = "GMT+00:00";
46+
int id_len = 0;
47+
char *message;
48+
TimeZone *timeZone;
49+
50+
switch (type) {
51+
case TIMELIB_ZONETYPE_ID:
52+
id = is_datetime
53+
? ((php_date_obj*)object)->time->tz_info->name
54+
: ((php_timezone_obj*)object)->tzi.tz->name;
55+
id_len = strlen(id);
56+
break;
57+
case TIMELIB_ZONETYPE_OFFSET: {
58+
int offset_mins = is_datetime
59+
? -((php_date_obj*)object)->time->z
60+
: -(int)((php_timezone_obj*)object)->tzi.utc_offset,
61+
hours = offset_mins / 60,
62+
minutes = offset_mins - hours * 60;
63+
minutes *= minutes > 0 ? 1 : -1;
64+
65+
if (offset_mins <= -24 * 60 || offset_mins >= 24 * 60) {
66+
spprintf(&message, 0, "%s: object has an time zone offset "
67+
"that's too large", func);
68+
intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
69+
message, 1 TSRMLS_CC);
70+
efree(message);
71+
return NULL;
72+
}
73+
74+
id = offset_id;
75+
id_len = slprintf(id, sizeof(offset_id), "GMT%+03d:%02d",
76+
hours, minutes);
77+
break;
78+
}
79+
case TIMELIB_ZONETYPE_ABBR:
80+
id = is_datetime
81+
? ((php_date_obj*)object)->time->tz_abbr
82+
: ((php_timezone_obj*)object)->tzi.z.abbr;
83+
id_len = strlen(id);
84+
break;
85+
}
86+
87+
UnicodeString s = UnicodeString(id, id_len, US_INV);
88+
timeZone = TimeZone::createTimeZone(s);
89+
#if U_ICU_VERSION_MAJOR_NUM >= 49
90+
if (*timeZone == TimeZone::getUnknown()) {
91+
#else
92+
UnicodeString resultingId;
93+
timeZone->getID(resultingId);
94+
if (resultingId == UnicodeString("Etc/Unknown", -1, US_INV)
95+
|| resultingId == UnicodeString("GMT", -1, US_INV)) {
96+
#endif
97+
spprintf(&message, 0, "%s: time zone id '%s' "
98+
"extracted from ext/date DateTimeZone not recognized", func, id);
99+
intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
100+
message, 1 TSRMLS_CC);
101+
efree(message);
102+
delete timeZone;
103+
return NULL;
104+
}
105+
return timeZone;
106+
}
107+
/* }}} */
108+
109+
U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz,
110+
intl_error *err, const char *func TSRMLS_DC)
111+
{
112+
zval retval;
113+
zval *zfuncname;
114+
char *message;
115+
116+
if (err && U_FAILURE(err->code)) {
117+
return FAILURE;
118+
}
119+
120+
if (millis) {
121+
*millis = NAN;
122+
}
123+
if (tz) {
124+
*tz = NULL;
125+
}
126+
127+
if (millis) {
128+
INIT_ZVAL(retval);
129+
MAKE_STD_ZVAL(zfuncname);
130+
ZVAL_STRING(zfuncname, "getTimestamp", 1);
131+
if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC)
132+
!= SUCCESS || Z_TYPE(retval) != IS_LONG) {
133+
spprintf(&message, 0, "%s: error calling ::getTimeStamp() on the "
134+
"object", func);
135+
intl_errors_set(err, U_INTERNAL_PROGRAM_ERROR,
136+
message, 1 TSRMLS_CC);
137+
efree(message);
138+
zval_ptr_dtor(&zfuncname);
139+
return FAILURE;
140+
}
141+
142+
*millis = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval);
143+
zval_ptr_dtor(&zfuncname);
144+
}
145+
146+
if (tz) {
147+
php_date_obj *datetime;
148+
datetime = (php_date_obj*)zend_object_store_get_object(z TSRMLS_CC);
149+
if (!datetime->time) {
150+
spprintf(&message, 0, "%s: the DateTime object is not properly "
151+
"initialized", func);
152+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
153+
message, 1 TSRMLS_CC);
154+
efree(message);
155+
return FAILURE;
156+
}
157+
if (!datetime->time->is_localtime) {
158+
*tz = TimeZone::getGMT()->clone();
159+
} else {
160+
*tz = timezone_convert_datetimezone(datetime->time->zone_type,
161+
datetime, 1, NULL, func TSRMLS_CC);
162+
if (*tz == NULL) {
163+
spprintf(&message, 0, "%s: could not convert DateTime's "
164+
"time zone", func);
165+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
166+
message, 1 TSRMLS_CC);
167+
efree(message);
168+
return FAILURE;
169+
}
170+
}
171+
}
172+
173+
return SUCCESS;
174+
}
175+
176+
U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC)
177+
{
178+
double rv = NAN;
179+
long lv;
180+
int type;
181+
char *message;
182+
183+
if (err && U_FAILURE(err->code)) {
184+
return NAN;
185+
}
186+
187+
switch (Z_TYPE_P(z)) {
188+
case IS_STRING:
189+
type = is_numeric_string(Z_STRVAL_P(z), Z_STRLEN_P(z), &lv, &rv, 0);
190+
if (type == IS_DOUBLE) {
191+
rv *= U_MILLIS_PER_SECOND;
192+
} else if (type == IS_LONG) {
193+
rv = U_MILLIS_PER_SECOND * (double)lv;
194+
} else {
195+
spprintf(&message, 0, "%s: string '%s' is not numeric, "
196+
"which would be required for it to be a valid date", func,
197+
Z_STRVAL_P(z));
198+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
199+
message, 1 TSRMLS_CC);
200+
efree(message);
201+
}
202+
break;
203+
case IS_LONG:
204+
rv = U_MILLIS_PER_SECOND * (double)Z_LVAL_P(z);
205+
break;
206+
case IS_DOUBLE:
207+
rv = U_MILLIS_PER_SECOND * Z_DVAL_P(z);
208+
break;
209+
case IS_OBJECT:
210+
if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) {
211+
intl_datetime_decompose(z, &rv, NULL, err, func TSRMLS_CC);
212+
} else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) {
213+
Calendar_object *co = (Calendar_object *)
214+
zend_object_store_get_object(z TSRMLS_CC );
215+
if (co->ucal == NULL) {
216+
spprintf(&message, 0, "%s: IntlCalendar object is not properly "
217+
"constructed", func);
218+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
219+
message, 1 TSRMLS_CC);
220+
efree(message);
221+
} else {
222+
UErrorCode status = UErrorCode();
223+
rv = (double)co->ucal->getTime(status);
224+
if (U_FAILURE(status)) {
225+
spprintf(&message, 0, "%s: call to internal "
226+
"Calendar::getTime() has failed", func);
227+
intl_errors_set(err, status, message, 1 TSRMLS_CC);
228+
efree(message);
229+
}
230+
}
231+
} else {
232+
/* TODO: try with cast(), get() to obtain a number */
233+
spprintf(&message, 0, "%s: invalid object type for date/time "
234+
"(only IntlCalendar and DateTime permitted)", func);
235+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
236+
message, 1 TSRMLS_CC);
237+
efree(message);
238+
}
239+
break;
240+
default:
241+
spprintf(&message, 0, "%s: invalid PHP type for date", func);
242+
intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR,
243+
message, 1 TSRMLS_CC);
244+
efree(message);
245+
break;
246+
}
247+
248+
return rv;
249+
}
250+

ext/intl/common/common_date.h

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Authors: Gustavo Lopes <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#ifndef COMMON_DATE_H
18+
#define COMMON_DATE_H
19+
20+
#include <unicode/umachine.h>
21+
22+
U_CDECL_BEGIN
23+
#include <php.h>
24+
#include "../intl_error.h"
25+
U_CDECL_END
26+
27+
#ifdef __cplusplus
28+
29+
#include <unicode/timezone.h>
30+
31+
U_CFUNC TimeZone *timezone_convert_datetimezone(int type, void *object, int is_datetime, intl_error *outside_error, const char *func TSRMLS_DC);
32+
U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz,
33+
intl_error *err, const char *func TSRMLS_DC);
34+
35+
#endif
36+
37+
U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC);
38+
39+
#endif /* COMMON_DATE_H */
40+

ext/intl/config.m4

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if test "$PHP_INTL" != "no"; then
3333
collator/collator_error.c \
3434
common/common_error.c \
3535
common/common_enum.cpp \
36+
common/common_date.cpp \
3637
formatter/formatter.c \
3738
formatter/formatter_main.c \
3839
formatter/formatter_class.c \
@@ -51,6 +52,7 @@ if test "$PHP_INTL" != "no"; then
5152
dateformat/dateformat_attr.c \
5253
dateformat/dateformat_data.c \
5354
dateformat/dateformat_format.c \
55+
dateformat/dateformat_format_object.cpp \
5456
dateformat/dateformat_parse.c \
5557
dateformat/dateformat_create.cpp \
5658
dateformat/dateformat_attrcpp.cpp \

ext/intl/config.w32

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ if (PHP_INTL != "no") {
2424
ADD_SOURCES(configure_module_dirname + "/common", "\
2525
common_error.c \
2626
common_enum.cpp \
27+
common_date.cpp \
2728
", "intl");
2829
ADD_SOURCES(configure_module_dirname + "/formatter", "\
2930
formatter.c \
@@ -61,6 +62,7 @@ if (PHP_INTL != "no") {
6162
dateformat_class.c \
6263
dateformat_attr.c \
6364
dateformat_format.c \
65+
dateformat_format_object.cpp \
6466
dateformat_parse.c \
6567
dateformat_data.c \
6668
dateformat_attrcpp.cpp \

ext/intl/dateformat/dateformat_class.c

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "php_intl.h"
2020
#include "dateformat_data.h"
2121
#include "dateformat_format.h"
22+
#include "dateformat_format_object.h"
2223
#include "dateformat_parse.h"
2324
#include "dateformat.h"
2425
#include "dateformat_attr.h"
@@ -121,6 +122,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format, 0, 0, 0)
121122
ZEND_ARG_INFO(0, array)
122123
ZEND_END_ARG_INFO()
123124

125+
ZEND_BEGIN_ARG_INFO_EX(arginfo_intldateformatter_format_object, 0, 0, 1)
126+
ZEND_ARG_INFO(0, object)
127+
ZEND_ARG_INFO(0, format)
128+
ZEND_ARG_INFO(0, locale)
129+
ZEND_END_ARG_INFO()
130+
124131
ZEND_BEGIN_ARG_INFO(arginfo_intldateformatter_getdatetype, 0)
125132
ZEND_END_ARG_INFO()
126133

@@ -171,6 +178,7 @@ static zend_function_entry IntlDateFormatter_class_functions[] = {
171178
PHP_NAMED_FE( setLenient, ZEND_FN( datefmt_set_lenient ), arginfo_intldateformatter_setlenient )
172179
PHP_NAMED_FE( isLenient, ZEND_FN( datefmt_is_lenient ), arginfo_intldateformatter_getdatetype )
173180
PHP_NAMED_FE( format, ZEND_FN( datefmt_format ), arginfo_intldateformatter_format )
181+
PHP_ME_MAPPING( formatObject, datefmt_format_object, arginfo_intldateformatter_format_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
174182
PHP_NAMED_FE( parse, ZEND_FN( datefmt_parse), datefmt_parse_args )
175183
PHP_NAMED_FE( localtime, ZEND_FN( datefmt_localtime ), datefmt_parse_args )
176184
PHP_NAMED_FE( getErrorCode, ZEND_FN( datefmt_get_error_code ), arginfo_intldateformatter_getdatetype )

0 commit comments

Comments
 (0)