@@ -39,10 +39,45 @@ using icu::Locale;
3939using icu::UnicodeString;
4040using icu::StringPiece;
4141
42+ #define ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (argument, zpp_arg_position ) \
43+ if (UNEXPECTED(argument < INT32_MIN || argument > INT32_MAX)) { \
44+ zend_argument_value_error (zpp_arg_position, " must be between %d and %d" , INT32_MIN, INT32_MAX); \
45+ RETURN_THROWS (); \
46+ }
47+
4248static inline GregorianCalendar *fetch_greg (Calendar_object *co) {
4349 return (GregorianCalendar*)co->ucal ;
4450}
4551
52+ static bool set_gregorian_calendar_time_zone (GregorianCalendar *gcal, UErrorCode status)
53+ {
54+ if (U_FAILURE (status)) {
55+ intl_error_set (NULL , status,
56+ " IntlGregorianCalendar: Error creating ICU GregorianCalendar from date" ,
57+ 0
58+ );
59+
60+ return false ;
61+ }
62+
63+ timelib_tzinfo *tzinfo = get_timezone_info ();
64+ UnicodeString tzstr = UnicodeString::fromUTF8 (StringPiece (tzinfo->name ));
65+ if (tzstr.isBogus ()) {
66+ intl_error_set (NULL , U_ILLEGAL_ARGUMENT_ERROR,
67+ " IntlGregorianCalendar: Could not create UTF-8 string "
68+ " from PHP's default timezone name (see date_default_timezone_get())" ,
69+ 0
70+ );
71+
72+ return false ;
73+ }
74+
75+ TimeZone *tz = TimeZone::createTimeZone (tzstr);
76+ gcal->adoptTimeZone (tz);
77+
78+ return true ;
79+ }
80+
4681static void _php_intlgregcal_constructor_body (
4782 INTERNAL_FUNCTION_PARAMETERS, bool is_constructor, zend_error_handling *error_handling, bool *error_handling_replaced)
4883{
@@ -135,11 +170,7 @@ static void _php_intlgregcal_constructor_body(
135170 } else {
136171 // From date/time (3, 5 or 6 arguments)
137172 for (int i = 0 ; i < variant; i++) {
138- if (UNEXPECTED (largs[i] < INT32_MIN || largs[i] > INT32_MAX)) {
139- zend_argument_value_error (getThis () ? (i-1 ) : i,
140- " must be between %d and %d" , INT32_MIN, INT32_MAX);
141- RETURN_THROWS ();
142- }
173+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (largs[i], getThis () ? (i-1 ) : i);
143174 }
144175
145176 if (variant == 3 ) {
@@ -152,37 +183,18 @@ static void _php_intlgregcal_constructor_body(
152183 gcal = new GregorianCalendar ((int32_t )largs[0 ], (int32_t )largs[1 ],
153184 (int32_t )largs[2 ], (int32_t )largs[3 ], (int32_t )largs[4 ], (int32_t )largs[5 ],
154185 status);
155- }
156- if (U_FAILURE (status)) {
157- intl_error_set (NULL , status, " intlgregcal_create_instance: error "
158- " creating ICU GregorianCalendar from date" , 0 );
159- if (gcal) {
160- delete gcal;
161- }
162- if (!is_constructor) {
163- zval_ptr_dtor (return_value);
164- RETVAL_NULL ();
165- }
166- return ;
186+ } else {
187+ ZEND_UNREACHABLE ();
167188 }
168189
169- timelib_tzinfo *tzinfo = get_timezone_info ();
170- UnicodeString tzstr = UnicodeString::fromUTF8 (StringPiece (tzinfo->name ));
171- if (tzstr.isBogus ()) {
172- intl_error_set (NULL , U_ILLEGAL_ARGUMENT_ERROR,
173- " intlgregcal_create_instance: could not create UTF-8 string "
174- " from PHP's default timezone name (see date_default_timezone_get())" ,
175- 0 );
190+ if (!set_gregorian_calendar_time_zone (gcal, status)) {
176191 delete gcal;
177192 if (!is_constructor) {
178193 zval_ptr_dtor (return_value);
179194 RETVAL_NULL ();
180195 }
181196 return ;
182197 }
183-
184- TimeZone *tz = TimeZone::createTimeZone (tzstr);
185- gcal->adoptTimeZone (tz);
186198 }
187199
188200 co->ucal = gcal;
@@ -208,6 +220,82 @@ U_CFUNC PHP_METHOD(IntlGregorianCalendar, __construct)
208220 }
209221}
210222
223+ U_CFUNC PHP_METHOD (IntlGregorianCalendar, createFromDate)
224+ {
225+ zend_long year, month, day;
226+ UErrorCode status = U_ZERO_ERROR;
227+ zend_error_handling error_handling;
228+ Calendar_object *co;
229+ GregorianCalendar *gcal;
230+
231+ intl_error_reset (NULL );
232+
233+ if (zend_parse_parameters (ZEND_NUM_ARGS (), " lll" , &year, &month, &day) == FAILURE) {
234+ RETURN_THROWS ();
235+ }
236+
237+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (year, 1 );
238+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (month, 2 );
239+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (day, 3 );
240+
241+ zend_replace_error_handling (EH_THROW, IntlException_ce_ptr, &error_handling);
242+
243+ gcal = new GregorianCalendar ((int32_t ) year, (int32_t ) month, (int32_t ) day, status);
244+ if (!set_gregorian_calendar_time_zone (gcal, status)) {
245+ delete gcal;
246+ goto cleanup;
247+ }
248+
249+ object_init_ex (return_value, GregorianCalendar_ce_ptr);
250+ co = Z_INTL_CALENDAR_P (return_value);
251+ co->ucal = gcal;
252+
253+ cleanup:
254+ zend_restore_error_handling (&error_handling);
255+ }
256+
257+ U_CFUNC PHP_METHOD (IntlGregorianCalendar, createFromDateTime)
258+ {
259+ zend_long year, month, day, hour, minute, second;
260+ bool second_is_null = 1 ;
261+ UErrorCode status = U_ZERO_ERROR;
262+ zend_error_handling error_handling;
263+ Calendar_object *co;
264+ GregorianCalendar *gcal;
265+
266+ intl_error_reset (NULL );
267+
268+ if (zend_parse_parameters (ZEND_NUM_ARGS (), " lllll|l!" , &year, &month, &day, &hour, &minute, &second, &second_is_null) == FAILURE) {
269+ RETURN_THROWS ();
270+ }
271+
272+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (year, 1 );
273+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (month, 2 );
274+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (day, 3 );
275+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (hour, 4 );
276+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (minute, 5 );
277+
278+ zend_replace_error_handling (EH_THROW, IntlException_ce_ptr, &error_handling);
279+
280+ if (second_is_null) {
281+ gcal = new GregorianCalendar ((int32_t ) year, (int32_t ) month, (int32_t ) day, (int32_t ) hour, (int32_t ) minute, status);
282+ } else {
283+ ZEND_VALUE_ERROR_OUT_OF_BOUND_VALUE (second, 6 );
284+ gcal = new GregorianCalendar ((int32_t ) year, (int32_t ) month, (int32_t ) day, (int32_t ) hour, (int32_t ) minute, (int32_t ) second, status);
285+ }
286+ if (!set_gregorian_calendar_time_zone (gcal, status)) {
287+ delete gcal;
288+ goto cleanup;
289+ }
290+
291+ object_init_ex (return_value, GregorianCalendar_ce_ptr);
292+ co = Z_INTL_CALENDAR_P (return_value);
293+ co->ucal = gcal;
294+
295+ cleanup:
296+ zend_restore_error_handling (&error_handling);
297+ }
298+
211299U_CFUNC PHP_FUNCTION (intlgregcal_set_gregorian_change)
212300{
213301 double date;
0 commit comments