1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
/*
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Kirti Velankar <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unicode/ustring.h>
#include <math.h>
#include "php_intl.h"
#include "intl_convert.h"
#include "dateformat.h"
#include "dateformat_class.h"
#include "dateformat_data.h"
/* {{{
* Internal function which calls the udat_parse
* param int store_error acts like a boolean
* if set to 1 - store any error encountered in the parameter parse_error
* if set to 0 - no need to store any error encountered in the parameter parse_error
*/
static void internal_parse_to_timestamp(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, bool update_calendar, zval *return_value)
{
double result = 0;
UDate timestamp =0;
UChar* text_utf16 = NULL;
int32_t text_utf16_len = 0;
/* Convert timezone to UTF-16. */
intl_convert_utf8_to_utf16(&text_utf16, &text_utf16_len, text_to_parse, text_len, &INTL_DATA_ERROR_CODE(dfo));
INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" );
if (UNEXPECTED(update_calendar)) {
UCalendar *parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo));
udat_parseCalendar(DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
if (text_utf16) {
efree(text_utf16);
}
INTL_METHOD_CHECK_STATUS( dfo, "Calendar parsing failed" );
timestamp = ucal_getMillis( parsed_calendar, &INTL_DATA_ERROR_CODE(dfo));
} else {
timestamp = udat_parse(DATE_FORMAT_OBJECT(dfo), text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
if (text_utf16) {
efree(text_utf16);
}
}
INTL_METHOD_CHECK_STATUS( dfo, "Date parsing failed" );
/* Since return is in sec. */
result = (double)timestamp / U_MILLIS_PER_SECOND;
if (result > (double)LONG_MAX || result < (double)LONG_MIN) {
ZVAL_DOUBLE(return_value, result<0?ceil(result):floor(result));
} else {
ZVAL_LONG(return_value, (zend_long)result);
}
}
/* }}} */
static void add_to_localtime_arr( IntlDateFormatter_object *dfo, zval* return_value, const UCalendar *parsed_calendar, zend_long calendar_field, char* key_name)
{
zend_long calendar_field_val = ucal_get( parsed_calendar, calendar_field, &INTL_DATA_ERROR_CODE(dfo));
INTL_METHOD_CHECK_STATUS( dfo, "Date parsing - localtime failed : could not get a field from calendar" );
if( strcmp(key_name, CALENDAR_YEAR )==0 ){
/* since tm_year is years from 1900 */
add_assoc_long( return_value, key_name,( calendar_field_val-1900) );
}else if( strcmp(key_name, CALENDAR_WDAY )==0 ){
/* since tm_wday starts from 0 whereas ICU WDAY start from 1 */
add_assoc_long( return_value, key_name,( calendar_field_val-1) );
}else{
add_assoc_long( return_value, key_name, calendar_field_val );
}
}
/* {{{ Internal function which calls the udat_parseCalendar */
static void internal_parse_to_localtime(IntlDateFormatter_object *dfo, char* text_to_parse, size_t text_len, int32_t *parse_pos, zval *return_value)
{
UCalendar *parsed_calendar = NULL;
UChar* text_utf16 = NULL;
int32_t text_utf16_len = 0;
zend_long isInDST = 0;
/* Convert timezone to UTF-16. */
intl_convert_utf8_to_utf16(&text_utf16, &text_utf16_len, text_to_parse, text_len, &INTL_DATA_ERROR_CODE(dfo));
INTL_METHOD_CHECK_STATUS(dfo, "Error converting timezone to UTF-16" );
parsed_calendar = (UCalendar *)udat_getCalendar(DATE_FORMAT_OBJECT(dfo));
udat_parseCalendar( DATE_FORMAT_OBJECT(dfo), parsed_calendar, text_utf16, text_utf16_len, parse_pos, &INTL_DATA_ERROR_CODE(dfo));
if (text_utf16) {
efree(text_utf16);
}
INTL_METHOD_CHECK_STATUS( dfo, "Date parsing failed" );
array_init( return_value );
/* Add entries from various fields of the obtained parsed_calendar */
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_SECOND, CALENDAR_SEC);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_MINUTE, CALENDAR_MIN);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_HOUR_OF_DAY, CALENDAR_HOUR);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_YEAR, CALENDAR_YEAR);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_DAY_OF_MONTH, CALENDAR_MDAY);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_DAY_OF_WEEK, CALENDAR_WDAY);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_DAY_OF_YEAR, CALENDAR_YDAY);
add_to_localtime_arr( dfo, return_value, parsed_calendar, UCAL_MONTH, CALENDAR_MON);
/* Is in DST? */
isInDST = ucal_inDaylightTime(parsed_calendar , &INTL_DATA_ERROR_CODE(dfo));
INTL_METHOD_CHECK_STATUS( dfo, "Date parsing - localtime failed : while checking if currently in DST." );
add_assoc_long( return_value, CALENDAR_ISDST,isInDST==1);
}
/* }}} */
/* {{{ Parse the string $value starting at parse_pos to a Unix timestamp -int */
PHP_FUNCTION(datefmt_parse)
{
char* text_to_parse = NULL;
size_t text_len =0;
zval* z_parse_pos = NULL;
int32_t parse_pos = -1;
DATE_FORMAT_METHOD_INIT_VARS;
/* Parse parameters. */
if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!",
&object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){
RETURN_THROWS();
}
/* Fetch the object. */
DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) {
zval *z_parse_pos_tmp = z_parse_pos;
ZVAL_DEREF(z_parse_pos_tmp);
zend_long long_parse_pos = zval_get_long(z_parse_pos_tmp);
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
intl_error_set_custom_msg(NULL, "String index is out of valid range.", 0);
RETURN_FALSE;
}
parse_pos = (int32_t)long_parse_pos;
if ((size_t)parse_pos > text_len) {
RETURN_FALSE;
}
}
internal_parse_to_timestamp( dfo, text_to_parse, text_len, z_parse_pos ? &parse_pos : NULL, false, return_value);
if (z_parse_pos) {
ZEND_TRY_ASSIGN_REF_LONG(z_parse_pos, parse_pos);
}
}
/* }}} */
PHP_METHOD(IntlDateFormatter, parseToCalendar)
{
zend_string *text_to_parse = NULL;
zval* z_parse_pos = NULL;
int32_t parse_pos = -1;
DATE_FORMAT_METHOD_INIT_VARS;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(text_to_parse)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(z_parse_pos)
ZEND_PARSE_PARAMETERS_END();
object = ZEND_THIS;
/* Fetch the object. */
DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) {
bool failed;
zend_long long_parse_pos = zval_try_get_long(z_parse_pos, &failed);
if (failed) {
zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(z_parse_pos));
RETURN_THROWS();
}
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
intl_error_set_custom_msg(NULL, "String index is out of valid range.", 0);
RETURN_FALSE;
}
parse_pos = (int32_t)long_parse_pos;
if (parse_pos != -1 && (size_t)parse_pos > ZSTR_LEN(text_to_parse)) {
RETURN_FALSE;
}
}
internal_parse_to_timestamp( dfo, ZSTR_VAL(text_to_parse), ZSTR_LEN(text_to_parse), z_parse_pos ? &parse_pos : NULL, true, return_value);
if (z_parse_pos) {
ZEND_TRY_ASSIGN_REF_LONG(z_parse_pos, parse_pos);
}
}
/* {{{ Parse the string $value to a localtime array */
PHP_FUNCTION(datefmt_localtime)
{
char* text_to_parse = NULL;
size_t text_len =0;
zval* z_parse_pos = NULL;
int32_t parse_pos = -1;
DATE_FORMAT_METHOD_INIT_VARS;
/* Parse parameters. */
if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|z!",
&object, IntlDateFormatter_ce_ptr, &text_to_parse, &text_len, &z_parse_pos ) == FAILURE ){
RETURN_THROWS();
}
/* Fetch the object. */
DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) {
zval *z_parse_pos_tmp = z_parse_pos;
ZVAL_DEREF(z_parse_pos_tmp);
zend_long long_parse_pos = zval_get_long(z_parse_pos_tmp);
if (ZEND_LONG_INT_OVFL(long_parse_pos)) {
intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
intl_error_set_custom_msg(NULL, "String index is out of valid range.", 0);
RETURN_FALSE;
}
parse_pos = (int32_t)long_parse_pos;
if((size_t)parse_pos > text_len) {
RETURN_FALSE;
}
}
internal_parse_to_localtime( dfo, text_to_parse, text_len, z_parse_pos?&parse_pos:NULL, return_value);
if (z_parse_pos) {
ZEND_TRY_ASSIGN_REF_LONG(z_parse_pos, parse_pos);
}
}
/* }}} */
|