PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/date - php_date.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1871 2085 89.7 %
Date: 2016-05-28 Functions: 151 165 91.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : #include "php.h"
      22             : #include "php_streams.h"
      23             : #include "php_main.h"
      24             : #include "php_globals.h"
      25             : #include "php_ini.h"
      26             : #include "ext/standard/info.h"
      27             : #include "ext/standard/php_versioning.h"
      28             : #include "ext/standard/php_math.h"
      29             : #include "php_date.h"
      30             : #include "zend_interfaces.h"
      31             : #include "lib/timelib.h"
      32             : #include <time.h>
      33             : 
      34             : #ifdef PHP_WIN32
      35             : static __inline __int64 php_date_llabs( __int64 i ) { return i >= 0? i: -i; }
      36             : #elif defined(__GNUC__) && __GNUC__ < 3
      37             : static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i; }
      38             : #else
      39        5749 : static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; }
      40             : #endif
      41             : 
      42             : #ifdef PHP_WIN32
      43             : #define DATE_I64_BUF_LEN 65
      44             : # define DATE_I64A(i, s, len) _i64toa_s(i, s, len, 10)
      45             : # define DATE_A64I(i, s) i = _atoi64(s)
      46             : #else
      47             : #define DATE_I64_BUF_LEN 65
      48             : # define DATE_I64A(i, s, len) \
      49             :         do { \
      50             :                 int st = snprintf(s, len, "%lld", i); \
      51             :                 s[st] = '\0'; \
      52             :         } while (0);
      53             : #ifdef HAVE_ATOLL
      54             : # define DATE_A64I(i, s) i = atoll(s)
      55             : #else
      56             : # define DATE_A64I(i, s) i = strtoll(s, NULL, 10)
      57             : #endif
      58             : #endif
      59             : 
      60             : /* {{{ arginfo */
      61             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
      62             :         ZEND_ARG_INFO(0, format)
      63             :         ZEND_ARG_INFO(0, timestamp)
      64             : ZEND_END_ARG_INFO()
      65             : 
      66             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
      67             :         ZEND_ARG_INFO(0, format)
      68             :         ZEND_ARG_INFO(0, timestamp)
      69             : ZEND_END_ARG_INFO()
      70             : 
      71             : ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
      72             :         ZEND_ARG_INFO(0, format)
      73             :         ZEND_ARG_INFO(0, timestamp)
      74             : ZEND_END_ARG_INFO()
      75             : 
      76             : ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
      77             :         ZEND_ARG_INFO(0, time)
      78             :         ZEND_ARG_INFO(0, now)
      79             : ZEND_END_ARG_INFO()
      80             : 
      81             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
      82             :         ZEND_ARG_INFO(0, hour)
      83             :         ZEND_ARG_INFO(0, min)
      84             :         ZEND_ARG_INFO(0, sec)
      85             :         ZEND_ARG_INFO(0, mon)
      86             :         ZEND_ARG_INFO(0, day)
      87             :         ZEND_ARG_INFO(0, year)
      88             : ZEND_END_ARG_INFO()
      89             : 
      90             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
      91             :         ZEND_ARG_INFO(0, hour)
      92             :         ZEND_ARG_INFO(0, min)
      93             :         ZEND_ARG_INFO(0, sec)
      94             :         ZEND_ARG_INFO(0, mon)
      95             :         ZEND_ARG_INFO(0, day)
      96             :         ZEND_ARG_INFO(0, year)
      97             : ZEND_END_ARG_INFO()
      98             : 
      99             : ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
     100             :         ZEND_ARG_INFO(0, month)
     101             :         ZEND_ARG_INFO(0, day)
     102             :         ZEND_ARG_INFO(0, year)
     103             : ZEND_END_ARG_INFO()
     104             : 
     105             : ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
     106             :         ZEND_ARG_INFO(0, format)
     107             :         ZEND_ARG_INFO(0, timestamp)
     108             : ZEND_END_ARG_INFO()
     109             : 
     110             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
     111             :         ZEND_ARG_INFO(0, format)
     112             :         ZEND_ARG_INFO(0, timestamp)
     113             : ZEND_END_ARG_INFO()
     114             : 
     115             : ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
     116             : ZEND_END_ARG_INFO()
     117             : 
     118             : ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
     119             :         ZEND_ARG_INFO(0, timestamp)
     120             :         ZEND_ARG_INFO(0, associative_array)
     121             : ZEND_END_ARG_INFO()
     122             : 
     123             : ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
     124             :         ZEND_ARG_INFO(0, timestamp)
     125             : ZEND_END_ARG_INFO()
     126             : 
     127             : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
     128             :         ZEND_ARG_INFO(0, timezone_identifier)
     129             : ZEND_END_ARG_INFO()
     130             : 
     131             : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
     132             : ZEND_END_ARG_INFO()
     133             : 
     134             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
     135             :         ZEND_ARG_INFO(0, time)
     136             :         ZEND_ARG_INFO(0, format)
     137             :         ZEND_ARG_INFO(0, latitude)
     138             :         ZEND_ARG_INFO(0, longitude)
     139             :         ZEND_ARG_INFO(0, zenith)
     140             :         ZEND_ARG_INFO(0, gmt_offset)
     141             : ZEND_END_ARG_INFO()
     142             : 
     143             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
     144             :         ZEND_ARG_INFO(0, time)
     145             :         ZEND_ARG_INFO(0, format)
     146             :         ZEND_ARG_INFO(0, latitude)
     147             :         ZEND_ARG_INFO(0, longitude)
     148             :         ZEND_ARG_INFO(0, zenith)
     149             :         ZEND_ARG_INFO(0, gmt_offset)
     150             : ZEND_END_ARG_INFO()
     151             : 
     152             : ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
     153             :         ZEND_ARG_INFO(0, time)
     154             :         ZEND_ARG_INFO(0, latitude)
     155             :         ZEND_ARG_INFO(0, longitude)
     156             : ZEND_END_ARG_INFO()
     157             : 
     158             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
     159             :         ZEND_ARG_INFO(0, time)
     160             :         ZEND_ARG_INFO(0, object)
     161             : ZEND_END_ARG_INFO()
     162             : 
     163             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
     164             :         ZEND_ARG_INFO(0, format)
     165             :         ZEND_ARG_INFO(0, time)
     166             :         ZEND_ARG_INFO(0, object)
     167             : ZEND_END_ARG_INFO()
     168             : 
     169             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1)
     170             :         ZEND_ARG_INFO(0, date)
     171             : ZEND_END_ARG_INFO()
     172             : 
     173             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2)
     174             :         ZEND_ARG_INFO(0, format)
     175             :         ZEND_ARG_INFO(0, date)
     176             : ZEND_END_ARG_INFO()
     177             : 
     178             : ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0)
     179             : ZEND_END_ARG_INFO()
     180             : 
     181             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
     182             :         ZEND_ARG_INFO(0, object)
     183             :         ZEND_ARG_INFO(0, format)
     184             : ZEND_END_ARG_INFO()
     185             : 
     186             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1)
     187             :         ZEND_ARG_INFO(0, format)
     188             : ZEND_END_ARG_INFO()
     189             : 
     190             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
     191             :         ZEND_ARG_INFO(0, object)
     192             :         ZEND_ARG_INFO(0, modify)
     193             : ZEND_END_ARG_INFO()
     194             : 
     195             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1)
     196             :         ZEND_ARG_INFO(0, modify)
     197             : ZEND_END_ARG_INFO()
     198             : 
     199             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
     200             :         ZEND_ARG_INFO(0, object)
     201             :         ZEND_ARG_INFO(0, interval)
     202             : ZEND_END_ARG_INFO()
     203             : 
     204             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1)
     205             :         ZEND_ARG_INFO(0, interval)
     206             : ZEND_END_ARG_INFO()
     207             : 
     208             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2)
     209             :         ZEND_ARG_INFO(0, object)
     210             :         ZEND_ARG_INFO(0, interval)
     211             : ZEND_END_ARG_INFO()
     212             : 
     213             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1)
     214             :         ZEND_ARG_INFO(0, interval)
     215             : ZEND_END_ARG_INFO()
     216             : 
     217             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
     218             :         ZEND_ARG_INFO(0, object)
     219             : ZEND_END_ARG_INFO()
     220             : 
     221             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0)
     222             : ZEND_END_ARG_INFO()
     223             : 
     224             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
     225             :         ZEND_ARG_INFO(0, object)
     226             :         ZEND_ARG_INFO(0, timezone)
     227             : ZEND_END_ARG_INFO()
     228             : 
     229             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1)
     230             :         ZEND_ARG_INFO(0, timezone)
     231             : ZEND_END_ARG_INFO()
     232             : 
     233             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1)
     234             :         ZEND_ARG_INFO(0, object)
     235             : ZEND_END_ARG_INFO()
     236             : 
     237             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0)
     238             : ZEND_END_ARG_INFO()
     239             : 
     240             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
     241             :         ZEND_ARG_INFO(0, object)
     242             :         ZEND_ARG_INFO(0, object2)
     243             :         ZEND_ARG_INFO(0, absolute)
     244             : ZEND_END_ARG_INFO()
     245             : 
     246             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1)
     247             :         ZEND_ARG_INFO(0, object)
     248             :         ZEND_ARG_INFO(0, absolute)
     249             : ZEND_END_ARG_INFO()
     250             : 
     251             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
     252             :         ZEND_ARG_INFO(0, object)
     253             :         ZEND_ARG_INFO(0, hour)
     254             :         ZEND_ARG_INFO(0, minute)
     255             :         ZEND_ARG_INFO(0, second)
     256             : ZEND_END_ARG_INFO()
     257             : 
     258             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_time_set, 0, 0, 2)
     259             :         ZEND_ARG_INFO(0, hour)
     260             :         ZEND_ARG_INFO(0, minute)
     261             :         ZEND_ARG_INFO(0, second)
     262             : ZEND_END_ARG_INFO()
     263             : 
     264             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
     265             :         ZEND_ARG_INFO(0, object)
     266             :         ZEND_ARG_INFO(0, year)
     267             :         ZEND_ARG_INFO(0, month)
     268             :         ZEND_ARG_INFO(0, day)
     269             : ZEND_END_ARG_INFO()
     270             : 
     271             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_date_set, 0, 0, 3)
     272             :         ZEND_ARG_INFO(0, year)
     273             :         ZEND_ARG_INFO(0, month)
     274             :         ZEND_ARG_INFO(0, day)
     275             : ZEND_END_ARG_INFO()
     276             : 
     277             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
     278             :         ZEND_ARG_INFO(0, object)
     279             :         ZEND_ARG_INFO(0, year)
     280             :         ZEND_ARG_INFO(0, week)
     281             :         ZEND_ARG_INFO(0, day)
     282             : ZEND_END_ARG_INFO()
     283             : 
     284             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_isodate_set, 0, 0, 2)
     285             :         ZEND_ARG_INFO(0, year)
     286             :         ZEND_ARG_INFO(0, week)
     287             :         ZEND_ARG_INFO(0, day)
     288             : ZEND_END_ARG_INFO()
     289             : 
     290             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
     291             :         ZEND_ARG_INFO(0, object)
     292             :         ZEND_ARG_INFO(0, unixtimestamp)
     293             : ZEND_END_ARG_INFO()
     294             : 
     295             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1)
     296             :         ZEND_ARG_INFO(0, unixtimestamp)
     297             : ZEND_END_ARG_INFO()
     298             : 
     299             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1)
     300             :         ZEND_ARG_INFO(0, object)
     301             : ZEND_END_ARG_INFO()
     302             : 
     303             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0)
     304             : ZEND_END_ARG_INFO()
     305             : 
     306             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_create_from_mutable, 0, 0, 1)
     307             :         ZEND_ARG_INFO(0, DateTime)
     308             : ZEND_END_ARG_INFO()
     309             : 
     310             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
     311             :         ZEND_ARG_INFO(0, timezone)
     312             : ZEND_END_ARG_INFO()
     313             : 
     314             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
     315             :         ZEND_ARG_INFO(0, object)
     316             : ZEND_END_ARG_INFO()
     317             : 
     318             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0)
     319             : ZEND_END_ARG_INFO()
     320             : 
     321             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
     322             :         ZEND_ARG_INFO(0, abbr)
     323             :         ZEND_ARG_INFO(0, gmtoffset)
     324             :         ZEND_ARG_INFO(0, isdst)
     325             : ZEND_END_ARG_INFO()
     326             : 
     327             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
     328             :         ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
     329             :         ZEND_ARG_OBJ_INFO(0, datetime, DateTimeInterface, 0)
     330             : ZEND_END_ARG_INFO()
     331             : 
     332             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1)
     333             :         ZEND_ARG_INFO(0, object)
     334             : ZEND_END_ARG_INFO()
     335             : 
     336             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
     337             :         ZEND_ARG_INFO(0, object)
     338             :         ZEND_ARG_INFO(0, timestamp_begin)
     339             :         ZEND_ARG_INFO(0, timestamp_end)
     340             : ZEND_END_ARG_INFO()
     341             : 
     342             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
     343             :         ZEND_ARG_INFO(0, timestamp_begin)
     344             :         ZEND_ARG_INFO(0, timestamp_end)
     345             : ZEND_END_ARG_INFO()
     346             : 
     347             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
     348             :         ZEND_ARG_INFO(0, object)
     349             : ZEND_END_ARG_INFO()
     350             : 
     351             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
     352             : ZEND_END_ARG_INFO()
     353             : 
     354             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
     355             :         ZEND_ARG_INFO(0, what)
     356             :         ZEND_ARG_INFO(0, country)
     357             : ZEND_END_ARG_INFO()
     358             : 
     359             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0)
     360             : ZEND_END_ARG_INFO()
     361             : 
     362             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0)
     363             : ZEND_END_ARG_INFO()
     364             : 
     365             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
     366             :         ZEND_ARG_INFO(0, time)
     367             : ZEND_END_ARG_INFO()
     368             : 
     369             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
     370             :         ZEND_ARG_INFO(0, object)
     371             :         ZEND_ARG_INFO(0, format)
     372             : ZEND_END_ARG_INFO()
     373             : 
     374             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0)
     375             :         ZEND_ARG_INFO(0, format)
     376             : ZEND_END_ARG_INFO()
     377             : 
     378             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3)
     379             :         ZEND_ARG_INFO(0, start)
     380             :         ZEND_ARG_INFO(0, interval)
     381             :         ZEND_ARG_INFO(0, end)
     382             : ZEND_END_ARG_INFO()
     383             : 
     384             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 1)
     385             :         ZEND_ARG_INFO(0, interval_spec)
     386             : ZEND_END_ARG_INFO()
     387             : /* }}} */
     388             : 
     389             : /* {{{ Function table */
     390             : const zend_function_entry date_functions[] = {
     391             :         PHP_FE(strtotime, arginfo_strtotime)
     392             :         PHP_FE(date, arginfo_date)
     393             :         PHP_FE(idate, arginfo_idate)
     394             :         PHP_FE(gmdate, arginfo_gmdate)
     395             :         PHP_FE(mktime, arginfo_mktime)
     396             :         PHP_FE(gmmktime, arginfo_gmmktime)
     397             :         PHP_FE(checkdate, arginfo_checkdate)
     398             : 
     399             : #ifdef HAVE_STRFTIME
     400             :         PHP_FE(strftime, arginfo_strftime)
     401             :         PHP_FE(gmstrftime, arginfo_gmstrftime)
     402             : #endif
     403             : 
     404             :         PHP_FE(time, arginfo_time)
     405             :         PHP_FE(localtime, arginfo_localtime)
     406             :         PHP_FE(getdate, arginfo_getdate)
     407             : 
     408             :         /* Advanced Interface */
     409             :         PHP_FE(date_create, arginfo_date_create)
     410             :         PHP_FE(date_create_immutable, arginfo_date_create)
     411             :         PHP_FE(date_create_from_format, arginfo_date_create_from_format)
     412             :         PHP_FE(date_create_immutable_from_format, arginfo_date_create_from_format)
     413             :         PHP_FE(date_parse, arginfo_date_parse)
     414             :         PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
     415             :         PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
     416             :         PHP_FE(date_format, arginfo_date_format)
     417             :         PHP_FE(date_modify, arginfo_date_modify)
     418             :         PHP_FE(date_add, arginfo_date_add)
     419             :         PHP_FE(date_sub, arginfo_date_sub)
     420             :         PHP_FE(date_timezone_get, arginfo_date_timezone_get)
     421             :         PHP_FE(date_timezone_set, arginfo_date_timezone_set)
     422             :         PHP_FE(date_offset_get, arginfo_date_offset_get)
     423             :         PHP_FE(date_diff, arginfo_date_diff)
     424             : 
     425             :         PHP_FE(date_time_set, arginfo_date_time_set)
     426             :         PHP_FE(date_date_set, arginfo_date_date_set)
     427             :         PHP_FE(date_isodate_set, arginfo_date_isodate_set)
     428             :         PHP_FE(date_timestamp_set, arginfo_date_timestamp_set)
     429             :         PHP_FE(date_timestamp_get, arginfo_date_timestamp_get)
     430             : 
     431             :         PHP_FE(timezone_open, arginfo_timezone_open)
     432             :         PHP_FE(timezone_name_get, arginfo_timezone_name_get)
     433             :         PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
     434             :         PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
     435             :         PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
     436             :         PHP_FE(timezone_location_get, arginfo_timezone_location_get)
     437             :         PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
     438             :         PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
     439             :         PHP_FE(timezone_version_get, arginfo_timezone_version_get)
     440             : 
     441             :         PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string)
     442             :         PHP_FE(date_interval_format, arginfo_date_interval_format)
     443             : 
     444             :         /* Options and Configuration */
     445             :         PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
     446             :         PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
     447             : 
     448             :         /* Astronomical functions */
     449             :         PHP_FE(date_sunrise, arginfo_date_sunrise)
     450             :         PHP_FE(date_sunset, arginfo_date_sunset)
     451             :         PHP_FE(date_sun_info, arginfo_date_sun_info)
     452             :         PHP_FE_END
     453             : };
     454             : 
     455             : static const zend_function_entry date_funcs_interface[] = {
     456             :         PHP_ABSTRACT_ME(DateTimeInterface, format, arginfo_date_method_format)
     457             :         PHP_ABSTRACT_ME(DateTimeInterface, getTimezone, arginfo_date_method_timezone_get)
     458             :         PHP_ABSTRACT_ME(DateTimeInterface, getOffset, arginfo_date_method_offset_get)
     459             :         PHP_ABSTRACT_ME(DateTimeInterface, getTimestamp, arginfo_date_method_timestamp_get)
     460             :         PHP_ABSTRACT_ME(DateTimeInterface, diff, arginfo_date_method_diff)
     461             :         PHP_ABSTRACT_ME(DateTimeInterface, __wakeup, NULL)
     462             :         PHP_FE_END
     463             : };
     464             : 
     465             : const zend_function_entry date_funcs_date[] = {
     466             :         PHP_ME(DateTime,                        __construct,            arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     467             :         PHP_ME(DateTime,                        __wakeup,                       NULL, ZEND_ACC_PUBLIC)
     468             :         PHP_ME(DateTime,                        __set_state,            NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     469             :         PHP_ME_MAPPING(createFromFormat, date_create_from_format,       arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     470             :         PHP_ME_MAPPING(getLastErrors, date_get_last_errors,     arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     471             :         PHP_ME_MAPPING(format,          date_format,            arginfo_date_method_format, 0)
     472             :         PHP_ME_MAPPING(modify,          date_modify,            arginfo_date_method_modify, 0)
     473             :         PHP_ME_MAPPING(add,                     date_add,                       arginfo_date_method_add, 0)
     474             :         PHP_ME_MAPPING(sub,                     date_sub,                       arginfo_date_method_sub, 0)
     475             :         PHP_ME_MAPPING(getTimezone, date_timezone_get,  arginfo_date_method_timezone_get, 0)
     476             :         PHP_ME_MAPPING(setTimezone, date_timezone_set,  arginfo_date_method_timezone_set, 0)
     477             :         PHP_ME_MAPPING(getOffset,       date_offset_get,        arginfo_date_method_offset_get, 0)
     478             :         PHP_ME_MAPPING(setTime,         date_time_set,          arginfo_date_method_time_set, 0)
     479             :         PHP_ME_MAPPING(setDate,         date_date_set,          arginfo_date_method_date_set, 0)
     480             :         PHP_ME_MAPPING(setISODate,      date_isodate_set,       arginfo_date_method_isodate_set, 0)
     481             :         PHP_ME_MAPPING(setTimestamp,    date_timestamp_set, arginfo_date_method_timestamp_set, 0)
     482             :         PHP_ME_MAPPING(getTimestamp,    date_timestamp_get, arginfo_date_method_timestamp_get, 0)
     483             :         PHP_ME_MAPPING(diff,                    date_diff, arginfo_date_method_diff, 0)
     484             :         PHP_FE_END
     485             : };
     486             : 
     487             : const zend_function_entry date_funcs_immutable[] = {
     488             :         PHP_ME(DateTimeImmutable, __construct,   arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     489             :         PHP_ME(DateTime, __wakeup,       NULL, ZEND_ACC_PUBLIC)
     490             :         PHP_ME(DateTimeImmutable, __set_state,   NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     491             :         PHP_ME_MAPPING(createFromFormat, date_create_immutable_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     492             :         PHP_ME_MAPPING(getLastErrors,    date_get_last_errors,    arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     493             :         PHP_ME_MAPPING(format,           date_format,             arginfo_date_method_format, 0)
     494             :         PHP_ME_MAPPING(getTimezone, date_timezone_get,  arginfo_date_method_timezone_get, 0)
     495             :         PHP_ME_MAPPING(getOffset,       date_offset_get,        arginfo_date_method_offset_get, 0)
     496             :         PHP_ME_MAPPING(getTimestamp,    date_timestamp_get, arginfo_date_method_timestamp_get, 0)
     497             :         PHP_ME_MAPPING(diff,                    date_diff, arginfo_date_method_diff, 0)
     498             :         PHP_ME(DateTimeImmutable, modify,        arginfo_date_method_modify, 0)
     499             :         PHP_ME(DateTimeImmutable, add,           arginfo_date_method_add, 0)
     500             :         PHP_ME(DateTimeImmutable, sub,           arginfo_date_method_sub, 0)
     501             :         PHP_ME(DateTimeImmutable, setTimezone,   arginfo_date_method_timezone_set, 0)
     502             :         PHP_ME(DateTimeImmutable, setTime,       arginfo_date_method_time_set, 0)
     503             :         PHP_ME(DateTimeImmutable, setDate,       arginfo_date_method_date_set, 0)
     504             :         PHP_ME(DateTimeImmutable, setISODate,    arginfo_date_method_isodate_set, 0)
     505             :         PHP_ME(DateTimeImmutable, setTimestamp,  arginfo_date_method_timestamp_set, 0)
     506             :         PHP_ME(DateTimeImmutable, createFromMutable, arginfo_date_method_create_from_mutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     507             :         PHP_FE_END
     508             : };
     509             : 
     510             : const zend_function_entry date_funcs_timezone[] = {
     511             :         PHP_ME(DateTimeZone,              __construct,                 arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     512             :         PHP_ME(DateTimeZone,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     513             :         PHP_ME(DateTimeZone,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     514             :         PHP_ME_MAPPING(getName,           timezone_name_get,           arginfo_timezone_method_name_get, 0)
     515             :         PHP_ME_MAPPING(getOffset,         timezone_offset_get,         arginfo_timezone_method_offset_get, 0)
     516             :         PHP_ME_MAPPING(getTransitions,    timezone_transitions_get,    arginfo_timezone_method_transitions_get, 0)
     517             :         PHP_ME_MAPPING(getLocation,       timezone_location_get,       arginfo_timezone_method_location_get, 0)
     518             :         PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     519             :         PHP_ME_MAPPING(listIdentifiers,   timezone_identifiers_list,   arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     520             :         PHP_FE_END
     521             : };
     522             : 
     523             : const zend_function_entry date_funcs_interval[] = {
     524             :         PHP_ME(DateInterval,              __construct,                 arginfo_date_interval_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     525             :         PHP_ME(DateInterval,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     526             :         PHP_ME(DateInterval,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     527             :         PHP_ME_MAPPING(format,            date_interval_format,        arginfo_date_method_interval_format, 0)
     528             :         PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string,     arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     529             :         PHP_FE_END
     530             : };
     531             : 
     532             : const zend_function_entry date_funcs_period[] = {
     533             :         PHP_ME(DatePeriod,                __construct,                 arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     534             :         PHP_ME(DatePeriod,                __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     535             :         PHP_ME(DatePeriod,                __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     536             :         PHP_ME(DatePeriod,                getStartDate,                NULL, ZEND_ACC_PUBLIC)
     537             :         PHP_ME(DatePeriod,                getEndDate,                  NULL, ZEND_ACC_PUBLIC)
     538             :         PHP_ME(DatePeriod,                getDateInterval,             NULL, ZEND_ACC_PUBLIC)
     539             :         PHP_FE_END
     540             : };
     541             : 
     542             : static char* guess_timezone(const timelib_tzdb *tzdb);
     543             : static void date_register_classes(void);
     544             : /* }}} */
     545             : 
     546             : ZEND_DECLARE_MODULE_GLOBALS(date)
     547             : static PHP_GINIT_FUNCTION(date);
     548             : 
     549             : /* True global */
     550             : timelib_tzdb *php_date_global_timezone_db;
     551             : int php_date_global_timezone_db_enabled;
     552             : 
     553             : #define DATE_DEFAULT_LATITUDE "31.7667"
     554             : #define DATE_DEFAULT_LONGITUDE "35.2333"
     555             : 
     556             : /* on 90'35; common sunset declaration (start of sun body appear) */
     557             : #define DATE_SUNSET_ZENITH "90.583333"
     558             : 
     559             : /* on 90'35; common sunrise declaration (sun body disappeared) */
     560             : #define DATE_SUNRISE_ZENITH "90.583333"
     561             : 
     562             : static PHP_INI_MH(OnUpdate_date_timezone);
     563             : 
     564             : /* {{{ INI Settings */
     565             : PHP_INI_BEGIN()
     566             :         STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdate_date_timezone, default_timezone, zend_date_globals, date_globals)
     567             :         PHP_INI_ENTRY("date.default_latitude",           DATE_DEFAULT_LATITUDE,        PHP_INI_ALL, NULL)
     568             :         PHP_INI_ENTRY("date.default_longitude",          DATE_DEFAULT_LONGITUDE,       PHP_INI_ALL, NULL)
     569             :         PHP_INI_ENTRY("date.sunset_zenith",              DATE_SUNSET_ZENITH,           PHP_INI_ALL, NULL)
     570             :         PHP_INI_ENTRY("date.sunrise_zenith",             DATE_SUNRISE_ZENITH,          PHP_INI_ALL, NULL)
     571             : PHP_INI_END()
     572             : /* }}} */
     573             : 
     574             : zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
     575             : zend_class_entry *date_ce_immutable, *date_ce_interface;
     576             : 
     577             : 
     578          60 : PHPAPI zend_class_entry *php_date_get_date_ce(void)
     579             : {
     580          60 :         return date_ce_date;
     581             : }
     582             : 
     583           0 : PHPAPI zend_class_entry *php_date_get_immutable_ce(void)
     584             : {
     585           0 :         return date_ce_immutable;
     586             : }
     587             : 
     588          22 : PHPAPI zend_class_entry *php_date_get_timezone_ce(void)
     589             : {
     590          22 :         return date_ce_timezone;
     591             : }
     592             : 
     593             : static zend_object_handlers date_object_handlers_date;
     594             : static zend_object_handlers date_object_handlers_immutable;
     595             : static zend_object_handlers date_object_handlers_timezone;
     596             : static zend_object_handlers date_object_handlers_interval;
     597             : static zend_object_handlers date_object_handlers_period;
     598             : 
     599             : #define DATE_SET_CONTEXT \
     600             :         zval *object; \
     601             :         object = getThis(); \
     602             : 
     603             : #define DATE_FETCH_OBJECT       \
     604             :         php_date_obj *obj;      \
     605             :         DATE_SET_CONTEXT; \
     606             :         if (object) {   \
     607             :                 if (zend_parse_parameters_none() == FAILURE) {  \
     608             :                         return; \
     609             :                 }       \
     610             :         } else {        \
     611             :                 if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "O", &object, date_ce_date) == FAILURE) { \
     612             :                         RETURN_FALSE;   \
     613             :                 }       \
     614             :         }       \
     615             :         obj = Z_PHPDATE_P(object);      \
     616             : 
     617             : #define DATE_CHECK_INITIALIZED(member, class_name) \
     618             :         if (!(member)) { \
     619             :                 php_error_docref(NULL, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
     620             :                 RETURN_FALSE; \
     621             :         }
     622             : 
     623             : static void date_object_free_storage_date(zend_object *object);
     624             : static void date_object_free_storage_timezone(zend_object *object);
     625             : static void date_object_free_storage_interval(zend_object *object);
     626             : static void date_object_free_storage_period(zend_object *object);
     627             : 
     628             : static zend_object *date_object_new_date(zend_class_entry *class_type);
     629             : static zend_object *date_object_new_timezone(zend_class_entry *class_type);
     630             : static zend_object *date_object_new_interval(zend_class_entry *class_type);
     631             : static zend_object *date_object_new_period(zend_class_entry *class_type);
     632             : 
     633             : static zend_object *date_object_clone_date(zval *this_ptr);
     634             : static zend_object *date_object_clone_timezone(zval *this_ptr);
     635             : static zend_object *date_object_clone_interval(zval *this_ptr);
     636             : static zend_object *date_object_clone_period(zval *this_ptr);
     637             : 
     638             : static int date_object_compare_date(zval *d1, zval *d2);
     639             : static HashTable *date_object_get_gc(zval *object, zval **table, int *n);
     640             : static HashTable *date_object_get_properties(zval *object);
     641             : static HashTable *date_object_get_gc_interval(zval *object, zval **table, int *n);
     642             : static HashTable *date_object_get_properties_interval(zval *object);
     643             : static HashTable *date_object_get_gc_period(zval *object, zval **table, int *n);
     644             : static HashTable *date_object_get_properties_period(zval *object);
     645             : static HashTable *date_object_get_properties_timezone(zval *object);
     646             : static HashTable *date_object_get_gc_timezone(zval *object, zval **table, int *n);
     647             : 
     648             : zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv);
     649             : void date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot);
     650             : static zval *date_period_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv);
     651             : static void date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot);
     652             : 
     653             : /* {{{ Module struct */
     654             : zend_module_entry date_module_entry = {
     655             :         STANDARD_MODULE_HEADER_EX,
     656             :         NULL,
     657             :         NULL,
     658             :         "date",                     /* extension name */
     659             :         date_functions,             /* function list */
     660             :         PHP_MINIT(date),            /* process startup */
     661             :         PHP_MSHUTDOWN(date),        /* process shutdown */
     662             :         PHP_RINIT(date),            /* request startup */
     663             :         PHP_RSHUTDOWN(date),        /* request shutdown */
     664             :         PHP_MINFO(date),            /* extension info */
     665             :         PHP_DATE_VERSION,                /* extension version */
     666             :         PHP_MODULE_GLOBALS(date),   /* globals descriptor */
     667             :         PHP_GINIT(date),            /* globals ctor */
     668             :         NULL,                       /* globals dtor */
     669             :         NULL,                       /* post deactivate */
     670             :         STANDARD_MODULE_PROPERTIES_EX
     671             : };
     672             : /* }}} */
     673             : 
     674             : 
     675             : /* {{{ PHP_GINIT_FUNCTION */
     676       22587 : static PHP_GINIT_FUNCTION(date)
     677             : {
     678       22587 :         date_globals->default_timezone = NULL;
     679       22587 :         date_globals->timezone = NULL;
     680       22587 :         date_globals->tzcache = NULL;
     681       22587 :         date_globals->timezone_valid = 0;
     682       22587 : }
     683             : /* }}} */
     684             : 
     685             : 
     686        1947 : static void _php_date_tzinfo_dtor(zval *zv) /* {{{ */
     687             : {
     688        1947 :         timelib_tzinfo *tzi = (timelib_tzinfo*)Z_PTR_P(zv);
     689             : 
     690        1947 :         timelib_tzinfo_dtor(tzi);
     691        1947 : } /* }}} */
     692             : 
     693             : /* {{{ PHP_RINIT_FUNCTION */
     694       22541 : PHP_RINIT_FUNCTION(date)
     695             : {
     696       22541 :         if (DATEG(timezone)) {
     697           0 :                 efree(DATEG(timezone));
     698             :         }
     699       22541 :         DATEG(timezone) = NULL;
     700       22541 :         DATEG(tzcache) = NULL;
     701       22541 :         DATEG(last_errors) = NULL;
     702             : 
     703       22541 :         return SUCCESS;
     704             : }
     705             : /* }}} */
     706             : 
     707             : /* {{{ PHP_RSHUTDOWN_FUNCTION */
     708       22579 : PHP_RSHUTDOWN_FUNCTION(date)
     709             : {
     710       22579 :         if (DATEG(timezone)) {
     711         526 :                 efree(DATEG(timezone));
     712             :         }
     713       22579 :         DATEG(timezone) = NULL;
     714       22579 :         if(DATEG(tzcache)) {
     715         661 :                 zend_hash_destroy(DATEG(tzcache));
     716         661 :                 FREE_HASHTABLE(DATEG(tzcache));
     717         661 :                 DATEG(tzcache) = NULL;
     718             :         }
     719       22579 :         if (DATEG(last_errors)) {
     720         257 :                 timelib_error_container_dtor(DATEG(last_errors));
     721         257 :                 DATEG(last_errors) = NULL;
     722             :         }
     723             : 
     724       22579 :         return SUCCESS;
     725             : }
     726             : /* }}} */
     727             : 
     728             : #define DATE_TIMEZONEDB      php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
     729             : 
     730             : /*
     731             :  * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
     732             :  *  date-time   =  [ day "," ] date time        ; dd mm yy hh:mm:ss zzz
     733             :  *  day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"  /  "Fri"  / "Sat" /  "Sun"
     734             :  *  date        =  1*2DIGIT month 2DIGIT        ; day month year e.g. 20 Jun 82
     735             :  *  month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"  /  "May"  /  "Jun" /  "Jul"  /  "Aug"  /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
     736             :  *  time        =  hour zone                    ; ANSI and Military
     737             :  *  hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
     738             :  *  zone        =  "UT"  / "GMT"  /  "EST" / "EDT"  /  "CST" / "CDT"  /  "MST" / "MDT"  /  "PST" / "PDT"  /  1ALPHA  / ( ("+" / "-") 4DIGIT )
     739             :  */
     740             : #define DATE_FORMAT_RFC822   "D, d M y H:i:s O"
     741             : 
     742             : /*
     743             :  * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
     744             :  *  Format must be acceptable both to the ARPANET and to the getdate routine.
     745             :  *  One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
     746             :  *  TIMEZONE can be any timezone name (3 or more letters)
     747             :  */
     748             : #define DATE_FORMAT_RFC850   "l, d-M-y H:i:s T"
     749             : 
     750             : /*
     751             :  * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
     752             :  *  Its format must be acceptable both in RFC-822 and to the getdate(3)
     753             :  *  Wdy, DD Mon YY HH:MM:SS TIMEZONE
     754             :  *  There is no hope of having a complete list of timezones.  Universal
     755             :  *  Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
     756             :  *  CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
     757             :  */
     758             : #define DATE_FORMAT_RFC1036  "D, d M y H:i:s O"
     759             : 
     760             : /*
     761             :  * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
     762             :  *  RFC-822 Date and Time Specification: RFC-822 Section 5
     763             :  *  The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
     764             :  */
     765             : #define DATE_FORMAT_RFC1123  "D, d M Y H:i:s O"
     766             : 
     767             : /*
     768             :  * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
     769             :  *  FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
     770             :  *  CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
     771             :  *
     772             :  *  date-time       =       [ day-of-week "," ] date FWS time [CFWS]
     773             :  *  day-of-week     =       ([FWS] day-name)
     774             :  *  day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
     775             :  *  date            =       day month year
     776             :  *  year            =       4*DIGIT
     777             :  *  month           =       (FWS month-name FWS)
     778             :  *  month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
     779             :  *  day             =       ([FWS] 1*2DIGIT)
     780             :  *  time            =       time-of-day FWS zone
     781             :  *  time-of-day     =       hour ":" minute [ ":" second ]
     782             :  *  hour            =       2DIGIT
     783             :  *  minute          =       2DIGIT
     784             :  *  second          =       2DIGIT
     785             :  *  zone            =       (( "+" / "-" ) 4DIGIT)
     786             :  */
     787             : #define DATE_FORMAT_RFC2822  "D, d M Y H:i:s O"
     788             : /*
     789             :  * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
     790             :  *  date-fullyear   = 4DIGIT
     791             :  *  date-month      = 2DIGIT  ; 01-12
     792             :  *  date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
     793             :  *
     794             :  *  time-hour       = 2DIGIT  ; 00-23
     795             :  *  time-minute     = 2DIGIT  ; 00-59
     796             :  *  time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
     797             :  *
     798             :  *  time-secfrac    = "." 1*DIGIT
     799             :  *  time-numoffset  = ("+" / "-") time-hour ":" time-minute
     800             :  *  time-offset     = "Z" / time-numoffset
     801             :  *
     802             :  *  partial-time    = time-hour ":" time-minute ":" time-second [time-secfrac]
     803             :  *  full-date       = date-fullyear "-" date-month "-" date-mday
     804             :  *  full-time       = partial-time time-offset
     805             :  *
     806             :  *  date-time       = full-date "T" full-time
     807             :  */
     808             : #define DATE_FORMAT_RFC3339  "Y-m-d\\TH:i:sP"
     809             : 
     810             : #define DATE_FORMAT_ISO8601  "Y-m-d\\TH:i:sO"
     811             : 
     812             : /*
     813             :  * RFC3339, Appendix A: http://www.ietf.org/rfc/rfc3339.txt
     814             :  *  ISO 8601 also requires (in section 5.3.1.3) that a decimal fraction
     815             :  *  be proceeded by a "0" if less than unity.  Annex B.2 of ISO 8601
     816             :  *  gives examples where the decimal fractions are not preceded by a "0".
     817             :  *  This grammar assumes section 5.3.1.3 is correct and that Annex B.2 is
     818             :  *  in error.
     819             :  */
     820             : #define DATE_FORMAT_RFC3339_EXTENDED  "Y-m-d\\TH:i:s.vP"
     821             : 
     822             : /*
     823             :  * This comes from various sources that like to contradict. I'm going with the
     824             :  * format here because of:
     825             :  * http://msdn.microsoft.com/en-us/library/windows/desktop/aa384321%28v=vs.85%29.aspx
     826             :  * and http://curl.haxx.se/rfc/cookie_spec.html
     827             :  */
     828             : #define DATE_FORMAT_COOKIE   "l, d-M-Y H:i:s T"
     829             : 
     830             : #define SUNFUNCS_RET_TIMESTAMP 0
     831             : #define SUNFUNCS_RET_STRING    1
     832             : #define SUNFUNCS_RET_DOUBLE    2
     833             : 
     834             : /* {{{ PHP_MINIT_FUNCTION */
     835       22587 : PHP_MINIT_FUNCTION(date)
     836             : {
     837       22587 :         REGISTER_INI_ENTRIES();
     838       22587 :         date_register_classes();
     839             : /*
     840             :  * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
     841             :  *   A Date construct is an element whose content MUST conform to the
     842             :  *   "date-time" production in [RFC3339].  In addition, an uppercase "T"
     843             :  *   character MUST be used to separate date and time, and an uppercase
     844             :  *   "Z" character MUST be present in the absence of a numeric time zone offset.
     845             :  */
     846       22587 :         REGISTER_STRING_CONSTANT("DATE_ATOM",    DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     847             : /*
     848             :  * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
     849             :  *   "This is based on RFC 822, RFC 850,  RFC 1036, and  RFC 1123,
     850             :  *   with the variations that the only legal time zone is GMT
     851             :  *   and the separators between the elements of the date must be dashes."
     852             :  */
     853       22587 :         REGISTER_STRING_CONSTANT("DATE_COOKIE",  DATE_FORMAT_COOKIE,  CONST_CS | CONST_PERSISTENT);
     854       22587 :         REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
     855             : 
     856       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC822",  DATE_FORMAT_RFC822,  CONST_CS | CONST_PERSISTENT);
     857       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC850",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
     858       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
     859       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
     860       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
     861       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     862       22587 :         REGISTER_STRING_CONSTANT("DATE_RFC3339_EXTENDED", DATE_FORMAT_RFC3339_EXTENDED, CONST_CS | CONST_PERSISTENT);
     863             : 
     864             : /*
     865             :  * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
     866             :  *   "All date-times in RSS conform to the Date and Time Specification of RFC 822,
     867             :  *   with the exception that the year may be expressed with two characters or four characters (four preferred)"
     868             :  */
     869       22587 :         REGISTER_STRING_CONSTANT("DATE_RSS",     DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
     870       22587 :         REGISTER_STRING_CONSTANT("DATE_W3C",     DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     871             : 
     872       22587 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
     873       22587 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
     874       22587 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
     875             : 
     876       22587 :         php_date_global_timezone_db = NULL;
     877       22587 :         php_date_global_timezone_db_enabled = 0;
     878       22587 :         DATEG(last_errors) = NULL;
     879       22587 :         return SUCCESS;
     880             : }
     881             : /* }}} */
     882             : 
     883             : /* {{{ PHP_MSHUTDOWN_FUNCTION */
     884       22623 : PHP_MSHUTDOWN_FUNCTION(date)
     885             : {
     886       22623 :         UNREGISTER_INI_ENTRIES();
     887             : 
     888       22623 :         if (DATEG(last_errors)) {
     889           0 :                 timelib_error_container_dtor(DATEG(last_errors));
     890             :         }
     891             : 
     892             : #ifndef ZTS
     893       22623 :         DATEG(default_timezone) = NULL;
     894             : #endif
     895             : 
     896       22623 :         return SUCCESS;
     897             : }
     898             : /* }}} */
     899             : 
     900             : /* {{{ PHP_MINFO_FUNCTION */
     901         150 : PHP_MINFO_FUNCTION(date)
     902             : {
     903         150 :         const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
     904             : 
     905         150 :         php_info_print_table_start();
     906         150 :         php_info_print_table_row(2, "date/time support", "enabled");
     907         150 :         php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
     908         150 :         php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
     909         150 :         php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb));
     910         150 :         php_info_print_table_end();
     911             : 
     912         150 :         DISPLAY_INI_ENTRIES();
     913         150 : }
     914             : /* }}} */
     915             : 
     916             : /* {{{ Timezone Cache functions */
     917       15774 : static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb)
     918             : {
     919             :         timelib_tzinfo *tzi;
     920             : 
     921       15774 :         if(!DATEG(tzcache)) {
     922         661 :                 ALLOC_HASHTABLE(DATEG(tzcache));
     923         661 :                 zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
     924             :         }
     925             : 
     926       31548 :         if ((tzi = zend_hash_str_find_ptr(DATEG(tzcache), formal_tzname, strlen(formal_tzname))) != NULL) {
     927       13732 :                 return tzi;
     928             :         }
     929             : 
     930        2042 :         tzi = timelib_parse_tzfile(formal_tzname, tzdb);
     931        2042 :         if (tzi) {
     932        1947 :                 zend_hash_str_add_ptr(DATEG(tzcache), formal_tzname, strlen(formal_tzname), tzi);
     933             :         }
     934        2042 :         return tzi;
     935             : }
     936             : 
     937        2758 : timelib_tzinfo *php_date_parse_tzfile_wrapper(char *formal_tzname, const timelib_tzdb *tzdb)
     938             : {
     939        2758 :         return php_date_parse_tzfile(formal_tzname, tzdb);
     940             : }
     941             : /* }}} */
     942             : 
     943             : /* Callback to check the date.timezone only when changed increases performance */
     944             : /* {{{ static PHP_INI_MH(OnUpdate_date_timezone) */
     945       22653 : static PHP_INI_MH(OnUpdate_date_timezone)
     946             : {
     947       22653 :         if (OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
     948           0 :                 return FAILURE;
     949             :         }
     950             : 
     951       22653 :         DATEG(timezone_valid) = 0;
     952       22653 :         if (stage == PHP_INI_STAGE_RUNTIME) {
     953          33 :                 if (!timelib_timezone_id_is_valid(DATEG(default_timezone), DATE_TIMEZONEDB)) {
     954           0 :                         if (DATEG(default_timezone) && *DATEG(default_timezone)) {
     955           0 :                                 php_error_docref(NULL, E_WARNING, "Invalid date.timezone value '%s', we selected the timezone 'UTC' for now.", DATEG(default_timezone));
     956             :                         }
     957             :                 } else {
     958          33 :                         DATEG(timezone_valid) = 1;
     959             :                 }
     960             :         }
     961             : 
     962       22653 :         return SUCCESS;
     963             : }
     964             : /* }}} */
     965             : 
     966             : /* {{{ Helper functions */
     967       13156 : static char* guess_timezone(const timelib_tzdb *tzdb)
     968             : {
     969             :         /* Checking configure timezone */
     970       13156 :         if (DATEG(timezone) && (strlen(DATEG(timezone))) > 0) {
     971       10209 :                 return DATEG(timezone);
     972             :         }
     973             :         /* Check config setting for default timezone */
     974        2947 :         if (!DATEG(default_timezone)) {
     975             :                 /* Special case: ext/date wasn't initialized yet */
     976             :                 zval *ztz;
     977             : 
     978           0 :                 if (NULL != (ztz = cfg_get_entry("date.timezone", sizeof("date.timezone")))
     979           0 :                         && Z_TYPE_P(ztz) == IS_STRING && Z_STRLEN_P(ztz) > 0 && timelib_timezone_id_is_valid(Z_STRVAL_P(ztz), tzdb)) {
     980           0 :                         return Z_STRVAL_P(ztz);
     981             :                 }
     982        2947 :         } else if (*DATEG(default_timezone)) {
     983        2657 :                 if (DATEG(timezone_valid) == 1) {
     984        2525 :                         return DATEG(default_timezone);
     985             :                 }
     986             : 
     987         132 :                 if (!timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
     988           2 :                         php_error_docref(NULL, E_WARNING, "Invalid date.timezone value '%s', we selected the timezone 'UTC' for now.", DATEG(default_timezone));
     989           2 :                         return "UTC";
     990             :                 }
     991             : 
     992         130 :                 DATEG(timezone_valid) = 1;
     993         130 :                 return DATEG(default_timezone);
     994             :         }
     995             :         /* Fallback to UTC */
     996         290 :         return "UTC";
     997             : }
     998             : 
     999       13006 : PHPAPI timelib_tzinfo *get_timezone_info(void)
    1000             : {
    1001             :         char *tz;
    1002             :         timelib_tzinfo *tzi;
    1003             : 
    1004       13006 :         tz = guess_timezone(DATE_TIMEZONEDB);
    1005       13006 :         tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB);
    1006       13006 :         if (! tzi) {
    1007           0 :                 php_error_docref(NULL, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
    1008             :         }
    1009       13006 :         return tzi;
    1010             : }
    1011             : /* }}} */
    1012             : 
    1013             : 
    1014             : /* {{{ date() and gmdate() data */
    1015             : #include "zend_smart_str.h"
    1016             : 
    1017             : static char *mon_full_names[] = {
    1018             :         "January", "February", "March", "April",
    1019             :         "May", "June", "July", "August",
    1020             :         "September", "October", "November", "December"
    1021             : };
    1022             : 
    1023             : static char *mon_short_names[] = {
    1024             :         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    1025             : };
    1026             : 
    1027             : static char *day_full_names[] = {
    1028             :         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
    1029             : };
    1030             : 
    1031             : static char *day_short_names[] = {
    1032             :         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    1033             : };
    1034             : 
    1035          37 : static char *english_suffix(timelib_sll number)
    1036             : {
    1037          37 :         if (number >= 10 && number <= 19) {
    1038          12 :                 return "th";
    1039             :         } else {
    1040          25 :                 switch (number % 10) {
    1041           4 :                         case 1: return "st";
    1042           2 :                         case 2: return "nd";
    1043           2 :                         case 3: return "rd";
    1044             :                 }
    1045             :         }
    1046          17 :         return "th";
    1047             : }
    1048             : /* }}} */
    1049             : 
    1050             : /* {{{ day of week helpers */
    1051         292 : char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
    1052             : {
    1053         292 :         timelib_sll day_of_week = timelib_day_of_week(y, m, d);
    1054         292 :         if (day_of_week < 0) {
    1055           0 :                 return "Unknown";
    1056             :         }
    1057         292 :         return day_full_names[day_of_week];
    1058             : }
    1059             : 
    1060         496 : char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
    1061             : {
    1062         496 :         timelib_sll day_of_week = timelib_day_of_week(y, m, d);
    1063         496 :         if (day_of_week < 0) {
    1064           0 :                 return "Unknown";
    1065             :         }
    1066         496 :         return day_short_names[day_of_week];
    1067             : }
    1068             : /* }}} */
    1069             : 
    1070             : /* {{{ date_format - (gm)date helper */
    1071        9250 : static zend_string *date_format(char *format, size_t format_len, timelib_time *t, int localtime)
    1072             : {
    1073        9250 :         smart_str            string = {0};
    1074        9250 :         int                  i, length = 0;
    1075             :         char                 buffer[97];
    1076        9250 :         timelib_time_offset *offset = NULL;
    1077             :         timelib_sll          isoweek, isoyear;
    1078             :         int                  rfc_colon;
    1079        9250 :         int                  weekYearSet = 0;
    1080             : 
    1081        9250 :         if (!format_len) {
    1082          41 :                 return ZSTR_EMPTY_ALLOC();
    1083             :         }
    1084             : 
    1085        9209 :         if (localtime) {
    1086        8362 :                 if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
    1087        1259 :                         offset = timelib_time_offset_ctor();
    1088        1259 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1089        1259 :                         offset->leap_secs = 0;
    1090        1259 :                         offset->is_dst = t->dst;
    1091        1259 :                         offset->abbr = timelib_strdup(t->tz_abbr);
    1092        7103 :                 } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
    1093         174 :                         offset = timelib_time_offset_ctor();
    1094         174 :                         offset->offset = (t->z) * -60;
    1095         174 :                         offset->leap_secs = 0;
    1096         174 :                         offset->is_dst = 0;
    1097         174 :                         offset->abbr = timelib_malloc(9); /* GMT±xxxx\0 */
    1098         696 :                         snprintf(offset->abbr, 9, "GMT%c%02d%02d",
    1099         174 :                                                   localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1100         174 :                                                   localtime ? abs(offset->offset / 3600) : 0,
    1101         174 :                                                   localtime ? abs((offset->offset % 3600) / 60) : 0 );
    1102             :                 } else {
    1103        6929 :                         offset = timelib_get_time_zone_info(t->sse, t->tz_info);
    1104             :                 }
    1105             :         }
    1106             : 
    1107       86507 :         for (i = 0; i < format_len; i++) {
    1108       77298 :                 rfc_colon = 0;
    1109       77298 :                 switch (format[i]) {
    1110             :                         /* day */
    1111        5662 :                         case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
    1112         437 :                         case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
    1113          86 :                         case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
    1114         257 :                         case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
    1115          37 :                         case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
    1116          12 :                         case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
    1117           8 :                         case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
    1118           6 :                         case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
    1119             : 
    1120             :                         /* week */
    1121             :                         case 'W':
    1122        1044 :                                 if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
    1123        1044 :                                 length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
    1124             :                         case 'o':
    1125        1030 :                                 if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
    1126        1030 :                                 length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
    1127             : 
    1128             :                         /* month */
    1129          65 :                         case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
    1130        5514 :                         case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
    1131         223 :                         case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
    1132          18 :                         case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
    1133          20 :                         case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
    1134             : 
    1135             :                         /* year */
    1136          10 :                         case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
    1137          49 :                         case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
    1138        5749 :                         case 'Y': length = slprintf(buffer, 32, "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
    1139             : 
    1140             :                         /* time */
    1141          39 :                         case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
    1142          10 :                         case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
    1143             :                         case 'B': {
    1144           7 :                                 int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
    1145          14 :                                 while (retval < 0) {
    1146           0 :                                         retval += 1000;
    1147             :                                 }
    1148           7 :                                 retval = retval % 1000;
    1149           7 :                                 length = slprintf(buffer, 32, "%03d", retval);
    1150           7 :                                 break;
    1151             :                         }
    1152          38 :                         case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
    1153          12 :                         case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
    1154           8 :                         case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
    1155        5461 :                         case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
    1156        5502 :                         case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
    1157        5486 :                         case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
    1158        1428 :                         case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break;
    1159           2 :                         case 'v': length = slprintf(buffer, 32, "%03d", (int) floor(t->f * 1000 + 0.5)); break;
    1160             : 
    1161             :                         /* timezone */
    1162         123 :                         case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
    1163          29 :                         case 'P': rfc_colon = 1; /* break intentionally missing */
    1164        2156 :                         case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
    1165         364 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1166         364 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1167             :                                                                                         rfc_colon ? ":" : "",
    1168         364 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1169             :                                                           );
    1170        1064 :                                           break;
    1171        3549 :                         case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
    1172         376 :                         case 'e': if (!localtime) {
    1173           4 :                                               length = slprintf(buffer, 32, "%s", "UTC");
    1174             :                                           } else {
    1175         372 :                                                   switch (t->zone_type) {
    1176             :                                                           case TIMELIB_ZONETYPE_ID:
    1177         171 :                                                                   length = slprintf(buffer, 32, "%s", t->tz_info->name);
    1178         171 :                                                                   break;
    1179             :                                                           case TIMELIB_ZONETYPE_ABBR:
    1180          98 :                                                                   length = slprintf(buffer, 32, "%s", offset->abbr);
    1181          98 :                                                                   break;
    1182             :                                                           case TIMELIB_ZONETYPE_OFFSET:
    1183         309 :                                                                   length = slprintf(buffer, 32, "%c%02d:%02d",
    1184         103 :                                                                                                 ((offset->offset < 0) ? '-' : '+'),
    1185         103 :                                                                                                 abs(offset->offset / 3600),
    1186         103 :                                                                                                 abs((offset->offset % 3600) / 60)
    1187             :                                                                                    );
    1188             :                                                                   break;
    1189             :                                                   }
    1190             :                                           }
    1191         376 :                                           break;
    1192           5 :                         case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
    1193             : 
    1194             :                         /* full date/time */
    1195          40 :                         case 'c': length = slprintf(buffer, 96, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
    1196             :                                                                         (int) t->y, (int) t->m, (int) t->d,
    1197             :                                                                                         (int) t->h, (int) t->i, (int) t->s,
    1198           9 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1199           9 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1200           9 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1201             :                                                           );
    1202          13 :                                           break;
    1203         265 :                         case 'r': length = slprintf(buffer, 96, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
    1204             :                                                                         php_date_short_day_name(t->y, t->m, t->d),
    1205          59 :                                                                                         (int) t->d, mon_short_names[t->m - 1],
    1206             :                                                                                         (int) t->y, (int) t->h, (int) t->i, (int) t->s,
    1207          49 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1208          49 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1209          49 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1210             :                                                           );
    1211          59 :                                           break;
    1212          32 :                         case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
    1213             : 
    1214        1028 :                         case '\\': if (i < format_len) i++; /* break intentionally missing */
    1215             : 
    1216       33857 :                         default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
    1217             :                 }
    1218       77298 :                 smart_str_appendl(&string, buffer, length);
    1219             :         }
    1220             : 
    1221             :         smart_str_0(&string);
    1222             : 
    1223        9209 :         if (localtime) {
    1224        8362 :                 timelib_time_offset_dtor(offset);
    1225             :         }
    1226             : 
    1227        9209 :         return string.s;
    1228             : }
    1229             : 
    1230        3121 : static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
    1231             : {
    1232             :         char   *format;
    1233             :         size_t     format_len;
    1234             :         zend_long    ts;
    1235             : 
    1236        3121 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &format, &format_len, &ts) == FAILURE) {
    1237          44 :                 RETURN_FALSE;
    1238             :         }
    1239        3077 :         if (ZEND_NUM_ARGS() == 1) {
    1240         148 :                 ts = time(NULL);
    1241             :         }
    1242             : 
    1243        3077 :         RETURN_STR(php_format_date(format, format_len, ts, localtime));
    1244             : }
    1245             : /* }}} */
    1246             : 
    1247        3750 : PHPAPI zend_string *php_format_date(char *format, size_t format_len, time_t ts, int localtime) /* {{{ */
    1248             : {
    1249             :         timelib_time   *t;
    1250             :         timelib_tzinfo *tzi;
    1251             :         zend_string *string;
    1252             : 
    1253        3750 :         t = timelib_time_ctor();
    1254             : 
    1255        3750 :         if (localtime) {
    1256        2887 :                 tzi = get_timezone_info();
    1257        2887 :                 t->tz_info = tzi;
    1258        2887 :                 t->zone_type = TIMELIB_ZONETYPE_ID;
    1259        2887 :                 timelib_unixtime2local(t, ts);
    1260             :         } else {
    1261         863 :                 tzi = NULL;
    1262         863 :                 timelib_unixtime2gmt(t, ts);
    1263             :         }
    1264             : 
    1265        3750 :         string = date_format(format, format_len, t, localtime);
    1266             : 
    1267        3750 :         timelib_time_dtor(t);
    1268        3750 :         return string;
    1269             : }
    1270             : /* }}} */
    1271             : 
    1272             : /* {{{ php_idate
    1273             :  */
    1274          81 : PHPAPI int php_idate(char format, time_t ts, int localtime)
    1275             : {
    1276             :         timelib_time   *t;
    1277             :         timelib_tzinfo *tzi;
    1278          81 :         int retval = -1;
    1279          81 :         timelib_time_offset *offset = NULL;
    1280             :         timelib_sll isoweek, isoyear;
    1281             : 
    1282          81 :         t = timelib_time_ctor();
    1283             : 
    1284          81 :         if (!localtime) {
    1285          81 :                 tzi = get_timezone_info();
    1286          81 :                 t->tz_info = tzi;
    1287          81 :                 t->zone_type = TIMELIB_ZONETYPE_ID;
    1288          81 :                 timelib_unixtime2local(t, ts);
    1289             :         } else {
    1290           0 :                 tzi = NULL;
    1291           0 :                 timelib_unixtime2gmt(t, ts);
    1292             :         }
    1293             : 
    1294          81 :         if (!localtime) {
    1295          81 :                 if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
    1296           0 :                         offset = timelib_time_offset_ctor();
    1297           0 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1298           0 :                         offset->leap_secs = 0;
    1299           0 :                         offset->is_dst = t->dst;
    1300           0 :                         offset->abbr = timelib_strdup(t->tz_abbr);
    1301          81 :                 } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
    1302           0 :                         offset = timelib_time_offset_ctor();
    1303           0 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1304           0 :                         offset->leap_secs = 0;
    1305           0 :                         offset->is_dst = t->dst;
    1306           0 :                         offset->abbr = timelib_malloc(9); /* GMT±xxxx\0 */
    1307           0 :                         snprintf(offset->abbr, 9, "GMT%c%02d%02d",
    1308           0 :                                                   !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1309           0 :                                                   !localtime ? abs(offset->offset / 3600) : 0,
    1310           0 :                                                   !localtime ? abs((offset->offset % 3600) / 60) : 0 );
    1311             :                 } else {
    1312          81 :                         offset = timelib_get_time_zone_info(t->sse, t->tz_info);
    1313             :                 }
    1314             :         }
    1315             : 
    1316          81 :         timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
    1317             : 
    1318          81 :         switch (format) {
    1319             :                 /* day */
    1320           4 :                 case 'd': case 'j': retval = (int) t->d; break;
    1321             : 
    1322           3 :                 case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
    1323           3 :                 case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
    1324             : 
    1325             :                 /* week */
    1326           3 :                 case 'W': retval = (int) isoweek; break; /* iso weeknr */
    1327             : 
    1328             :                 /* month */
    1329           4 :                 case 'm': case 'n': retval = (int) t->m; break;
    1330           3 :                 case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
    1331             : 
    1332             :                 /* year */
    1333           3 :                 case 'L': retval = (int) timelib_is_leap((int) t->y); break;
    1334           5 :                 case 'y': retval = (int) (t->y % 100); break;
    1335          15 :                 case 'Y': retval = (int) t->y; break;
    1336             : 
    1337             :                 /* Swatch Beat a.k.a. Internet Time */
    1338             :                 case 'B':
    1339           4 :                         retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
    1340           8 :                         while (retval < 0) {
    1341           0 :                                 retval += 1000;
    1342             :                         }
    1343           4 :                         retval = retval % 1000;
    1344           4 :                         break;
    1345             : 
    1346             :                 /* time */
    1347           4 :                 case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
    1348           4 :                 case 'H': case 'G': retval = (int) t->h; break;
    1349           3 :                 case 'i': retval = (int) t->i; break;
    1350           3 :                 case 's': retval = (int) t->s; break;
    1351             : 
    1352             :                 /* timezone */
    1353           3 :                 case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
    1354           2 :                 case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
    1355             : 
    1356           3 :                 case 'U': retval = (int) t->sse; break;
    1357             :         }
    1358             : 
    1359          81 :         if (!localtime) {
    1360          81 :                 timelib_time_offset_dtor(offset);
    1361             :         }
    1362          81 :         timelib_time_dtor(t);
    1363             : 
    1364          81 :         return retval;
    1365             : }
    1366             : /* }}} */
    1367             : 
    1368             : /* {{{ proto string date(string format [, long timestamp])
    1369             :    Format a local date/time */
    1370        2904 : PHP_FUNCTION(date)
    1371             : {
    1372        2904 :         php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1373        2904 : }
    1374             : /* }}} */
    1375             : 
    1376             : /* {{{ proto string gmdate(string format [, long timestamp])
    1377             :    Format a GMT date/time */
    1378         217 : PHP_FUNCTION(gmdate)
    1379             : {
    1380         217 :         php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1381         217 : }
    1382             : /* }}} */
    1383             : 
    1384             : /* {{{ proto int idate(string format [, int timestamp])
    1385             :    Format a local time/date as integer */
    1386         140 : PHP_FUNCTION(idate)
    1387             : {
    1388             :         char   *format;
    1389             :         size_t     format_len;
    1390         140 :         zend_long    ts = 0;
    1391             :         int ret;
    1392             : 
    1393         140 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &format, &format_len, &ts) == FAILURE) {
    1394          26 :                 RETURN_FALSE;
    1395             :         }
    1396             : 
    1397         114 :         if (format_len != 1) {
    1398          33 :                 php_error_docref(NULL, E_WARNING, "idate format is one char");
    1399          33 :                 RETURN_FALSE;
    1400             :         }
    1401             : 
    1402          81 :         if (ZEND_NUM_ARGS() == 1) {
    1403          24 :                 ts = time(NULL);
    1404             :         }
    1405             : 
    1406          81 :         ret = php_idate(format[0], ts, 0);
    1407          81 :         if (ret == -1) {
    1408          12 :                 php_error_docref(NULL, E_WARNING, "Unrecognized date format token.");
    1409          12 :                 RETURN_FALSE;
    1410             :         }
    1411          69 :         RETURN_LONG(ret);
    1412             : }
    1413             : /* }}} */
    1414             : 
    1415             : /* {{{ php_date_set_tzdb - NOT THREADSAFE */
    1416           0 : PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
    1417             : {
    1418           0 :         const timelib_tzdb *builtin = timelib_builtin_db();
    1419             : 
    1420           0 :         if (php_version_compare(tzdb->version, builtin->version) > 0) {
    1421           0 :                 php_date_global_timezone_db = tzdb;
    1422           0 :                 php_date_global_timezone_db_enabled = 1;
    1423             :         }
    1424           0 : }
    1425             : /* }}} */
    1426             : 
    1427             : /* {{{ php_parse_date: Backwards compatibility function */
    1428          16 : PHPAPI zend_long php_parse_date(char *string, zend_long *now)
    1429             : {
    1430             :         timelib_time *parsed_time;
    1431          16 :         timelib_error_container *error = NULL;
    1432             :         int           error2;
    1433             :         zend_long   retval;
    1434             : 
    1435          16 :         parsed_time = timelib_strtotime(string, strlen(string), &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    1436          16 :         if (error->error_count) {
    1437           1 :                 timelib_time_dtor(parsed_time);
    1438           1 :                 timelib_error_container_dtor(error);
    1439           1 :                 return -1;
    1440             :         }
    1441          15 :         timelib_error_container_dtor(error);
    1442          15 :         timelib_update_ts(parsed_time, NULL);
    1443          15 :         retval = timelib_date_to_int(parsed_time, &error2);
    1444          15 :         timelib_time_dtor(parsed_time);
    1445          15 :         if (error2) {
    1446           0 :                 return -1;
    1447             :         }
    1448          15 :         return retval;
    1449             : }
    1450             : /* }}} */
    1451             : 
    1452             : /* {{{ proto int strtotime(string time [, int now ])
    1453             :    Convert string representation of date and time to a timestamp */
    1454        4092 : PHP_FUNCTION(strtotime)
    1455             : {
    1456             :         char *times;
    1457             :         size_t   time_len;
    1458             :         int error1, error2;
    1459             :         struct timelib_error_container *error;
    1460        4092 :         zend_long preset_ts = 0, ts;
    1461             :         timelib_time *t, *now;
    1462             :         timelib_tzinfo *tzi;
    1463             : 
    1464        4092 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &times, &time_len, &preset_ts) == FAILURE || !time_len) {
    1465           2 :                 RETURN_FALSE;
    1466             :         }
    1467             : 
    1468        4090 :         tzi = get_timezone_info();
    1469             : 
    1470        4090 :         now = timelib_time_ctor();
    1471        4090 :         now->tz_info = tzi;
    1472        4090 :         now->zone_type = TIMELIB_ZONETYPE_ID;
    1473        7992 :         timelib_unixtime2local(now,
    1474        3902 :                 (ZEND_NUM_ARGS() == 2) ? (timelib_sll) preset_ts : (timelib_sll) time(NULL));
    1475             : 
    1476        4090 :         t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    1477        4090 :         error1 = error->error_count;
    1478        4090 :         timelib_error_container_dtor(error);
    1479        4090 :         timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
    1480        4090 :         timelib_update_ts(t, tzi);
    1481        4090 :         ts = timelib_date_to_int(t, &error2);
    1482             : 
    1483        4090 :         timelib_time_dtor(now);
    1484        4090 :         timelib_time_dtor(t);
    1485             : 
    1486        4090 :         if (error1 || error2) {
    1487          11 :                 RETURN_FALSE;
    1488             :         } else {
    1489        4079 :                 RETURN_LONG(ts);
    1490             :         }
    1491             : }
    1492             : /* }}} */
    1493             : 
    1494             : /* {{{ php_mktime - (gm)mktime helper */
    1495         922 : PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
    1496             : {
    1497         922 :         zend_long hou = 0, min = 0, sec = 0, mon = 0, day = 0, yea = 0;
    1498             :         timelib_time *now;
    1499         922 :         timelib_tzinfo *tzi = NULL;
    1500         922 :         zend_long ts, adjust_seconds = 0;
    1501             :         int error;
    1502             : 
    1503         922 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|llllll", &hou, &min, &sec, &mon, &day, &yea) == FAILURE) {
    1504         152 :                 RETURN_FALSE;
    1505             :         }
    1506             :         /* Initialize structure with current time */
    1507         770 :         now = timelib_time_ctor();
    1508         770 :         if (gmt) {
    1509         116 :                 timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
    1510             :         } else {
    1511         654 :                 tzi = get_timezone_info();
    1512         654 :                 now->tz_info = tzi;
    1513         654 :                 now->zone_type = TIMELIB_ZONETYPE_ID;
    1514         654 :                 timelib_unixtime2local(now, (timelib_sll) time(NULL));
    1515             :         }
    1516             :         /* Fill in the new data */
    1517         770 :         switch (ZEND_NUM_ARGS()) {
    1518             :                 case 7:
    1519             :                         /* break intentionally missing */
    1520             :                 case 6:
    1521         713 :                         if (yea >= 0 && yea < 70) {
    1522          25 :                                 yea += 2000;
    1523         663 :                         } else if (yea >= 70 && yea <= 100) {
    1524           8 :                                 yea += 1900;
    1525             :                         }
    1526         688 :                         now->y = yea;
    1527             :                         /* break intentionally missing again */
    1528             :                 case 5:
    1529         704 :                         now->d = day;
    1530             :                         /* break missing intentionally here too */
    1531             :                 case 4:
    1532         720 :                         now->m = mon;
    1533             :                         /* and here */
    1534             :                 case 3:
    1535         736 :                         now->s = sec;
    1536             :                         /* yup, this break isn't here on purpose too */
    1537             :                 case 2:
    1538         752 :                         now->i = min;
    1539             :                         /* last intentionally missing break */
    1540             :                 case 1:
    1541         768 :                         now->h = hou;
    1542         768 :                         break;
    1543             :                 default:
    1544           2 :                         php_error_docref(NULL, E_DEPRECATED, "You should be using the time() function instead");
    1545             :         }
    1546             :         /* Update the timestamp */
    1547         770 :         if (gmt) {
    1548         116 :                 timelib_update_ts(now, NULL);
    1549             :         } else {
    1550         654 :                 timelib_update_ts(now, tzi);
    1551             :         }
    1552             : 
    1553             :         /* Clean up and return */
    1554         770 :         ts = timelib_date_to_int(now, &error);
    1555         770 :         ts += adjust_seconds;
    1556         770 :         timelib_time_dtor(now);
    1557             : 
    1558         770 :         if (error) {
    1559           0 :                 RETURN_FALSE;
    1560             :         } else {
    1561         770 :                 RETURN_LONG(ts);
    1562             :         }
    1563             : }
    1564             : /* }}} */
    1565             : 
    1566             : /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
    1567             :    Get UNIX timestamp for a date */
    1568         733 : PHP_FUNCTION(mktime)
    1569             : {
    1570         733 :         php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1571         733 : }
    1572             : /* }}} */
    1573             : 
    1574             : /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
    1575             :    Get UNIX timestamp for a GMT date */
    1576         189 : PHP_FUNCTION(gmmktime)
    1577             : {
    1578         189 :         php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1579         189 : }
    1580             : /* }}} */
    1581             : 
    1582             : /* {{{ proto bool checkdate(int month, int day, int year)
    1583             :    Returns true(1) if it is a valid date in gregorian calendar */
    1584         100 : PHP_FUNCTION(checkdate)
    1585             : {
    1586             :         zend_long m, d, y;
    1587             : 
    1588         100 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &m, &d, &y) == FAILURE) {
    1589          45 :                 RETURN_FALSE;
    1590             :         }
    1591             : 
    1592          55 :         if (y < 1 || y > 32767 || !timelib_valid_date(y, m, d)) {
    1593          36 :                 RETURN_FALSE;
    1594             :         }
    1595          19 :         RETURN_TRUE;    /* True : This month, day, year arguments are valid */
    1596             : }
    1597             : /* }}} */
    1598             : 
    1599             : #ifdef HAVE_STRFTIME
    1600             : /* {{{ php_strftime - (gm)strftime helper */
    1601         356 : PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
    1602             : {
    1603             :         char                *format;
    1604             :         size_t                  format_len;
    1605         356 :         zend_long                 timestamp = 0;
    1606             :         struct tm            ta;
    1607         356 :         int                  max_reallocs = 5;
    1608         356 :         size_t               buf_len = 256, real_len;
    1609             :         timelib_time        *ts;
    1610             :         timelib_tzinfo      *tzi;
    1611         356 :         timelib_time_offset *offset = NULL;
    1612             :         zend_string             *buf;
    1613             : 
    1614         356 :         timestamp = (zend_long) time(NULL);
    1615             : 
    1616         356 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &format, &format_len, &timestamp) == FAILURE) {
    1617          37 :                 RETURN_FALSE;
    1618             :         }
    1619             : 
    1620         319 :         if (format_len == 0) {
    1621          34 :                 RETURN_FALSE;
    1622             :         }
    1623             : 
    1624         285 :         ts = timelib_time_ctor();
    1625         285 :         if (gmt) {
    1626          97 :                 tzi = NULL;
    1627          97 :                 timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
    1628             :         } else {
    1629         188 :                 tzi = get_timezone_info();
    1630         188 :                 ts->tz_info = tzi;
    1631         188 :                 ts->zone_type = TIMELIB_ZONETYPE_ID;
    1632         188 :                 timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1633             :         }
    1634         285 :         ta.tm_sec   = ts->s;
    1635         285 :         ta.tm_min   = ts->i;
    1636         285 :         ta.tm_hour  = ts->h;
    1637         285 :         ta.tm_mday  = ts->d;
    1638         285 :         ta.tm_mon   = ts->m - 1;
    1639         285 :         ta.tm_year  = ts->y - 1900;
    1640         285 :         ta.tm_wday  = timelib_day_of_week(ts->y, ts->m, ts->d);
    1641         285 :         ta.tm_yday  = timelib_day_of_year(ts->y, ts->m, ts->d);
    1642         285 :         if (gmt) {
    1643          97 :                 ta.tm_isdst = 0;
    1644             : #if HAVE_TM_GMTOFF
    1645          97 :                 ta.tm_gmtoff = 0;
    1646             : #endif
    1647             : #if HAVE_TM_ZONE
    1648          97 :                 ta.tm_zone = "GMT";
    1649             : #endif
    1650             :         } else {
    1651         188 :                 offset = timelib_get_time_zone_info(timestamp, tzi);
    1652             : 
    1653         188 :                 ta.tm_isdst = offset->is_dst;
    1654             : #if HAVE_TM_GMTOFF
    1655         188 :                 ta.tm_gmtoff = offset->offset;
    1656             : #endif
    1657             : #if HAVE_TM_ZONE
    1658         188 :                 ta.tm_zone = offset->abbr;
    1659             : #endif
    1660             :         }
    1661             : 
    1662             :         /* VS2012 crt has a bug where strftime crash with %z and %Z format when the
    1663             :            initial buffer is too small. See
    1664             :            http://connect.microsoft.com/VisualStudio/feedback/details/759720/vs2012-strftime-crash-with-z-formatting-code */
    1665         285 :         buf = zend_string_alloc(buf_len, 0);
    1666         570 :         while ((real_len = strftime(ZSTR_VAL(buf), buf_len, format, &ta)) == buf_len || real_len == 0) {
    1667           0 :                 buf_len *= 2;
    1668           0 :                 buf = zend_string_extend(buf, buf_len, 0);
    1669           0 :                 if (!--max_reallocs) {
    1670           0 :                         break;
    1671             :                 }
    1672             :         }
    1673             : #ifdef PHP_WIN32
    1674             :         /* VS2012 strftime() returns number of characters, not bytes.
    1675             :                 See VC++11 bug id 766205. */
    1676             :         if (real_len > 0) {
    1677             :                 real_len = strlen(buf->val);
    1678             :         }
    1679             : #endif
    1680             : 
    1681         285 :         timelib_time_dtor(ts);
    1682         285 :         if (!gmt) {
    1683         188 :                 timelib_time_offset_dtor(offset);
    1684             :         }
    1685             : 
    1686         285 :         if (real_len && real_len != buf_len) {
    1687         285 :                 buf = zend_string_truncate(buf, real_len, 0);
    1688         285 :                 RETURN_NEW_STR(buf);
    1689             :         }
    1690             :         zend_string_free(buf);
    1691           0 :         RETURN_FALSE;
    1692             : }
    1693             : /* }}} */
    1694             : 
    1695             : /* {{{ proto string strftime(string format [, int timestamp])
    1696             :    Format a local time/date according to locale settings */
    1697         229 : PHP_FUNCTION(strftime)
    1698             : {
    1699         229 :         php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1700         229 : }
    1701             : /* }}} */
    1702             : 
    1703             : /* {{{ proto string gmstrftime(string format [, int timestamp])
    1704             :    Format a GMT/UCT time/date according to locale settings */
    1705         127 : PHP_FUNCTION(gmstrftime)
    1706             : {
    1707         127 :         php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1708         127 : }
    1709             : /* }}} */
    1710             : #endif
    1711             : 
    1712             : /* {{{ proto int time(void)
    1713             :    Return current UNIX timestamp */
    1714      252793 : PHP_FUNCTION(time)
    1715             : {
    1716      252793 :         RETURN_LONG((zend_long)time(NULL));
    1717             : }
    1718             : /* }}} */
    1719             : 
    1720             : /* {{{ proto array localtime([int timestamp [, bool associative_array]])
    1721             :    Returns the results of the C system call localtime as an associative array if the associative_array argument is set to 1 other wise it is a regular array */
    1722          96 : PHP_FUNCTION(localtime)
    1723             : {
    1724          96 :         zend_long timestamp = (zend_long)time(NULL);
    1725          96 :         zend_bool associative = 0;
    1726             :         timelib_tzinfo *tzi;
    1727             :         timelib_time   *ts;
    1728             : 
    1729          96 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lb", &timestamp, &associative) == FAILURE) {
    1730          32 :                 RETURN_FALSE;
    1731             :         }
    1732             : 
    1733          64 :         tzi = get_timezone_info();
    1734          64 :         ts = timelib_time_ctor();
    1735          64 :         ts->tz_info = tzi;
    1736          64 :         ts->zone_type = TIMELIB_ZONETYPE_ID;
    1737          64 :         timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1738             : 
    1739          64 :         array_init(return_value);
    1740             : 
    1741          64 :         if (associative) {
    1742          33 :                 add_assoc_long(return_value, "tm_sec",   ts->s);
    1743          33 :                 add_assoc_long(return_value, "tm_min",   ts->i);
    1744          33 :                 add_assoc_long(return_value, "tm_hour",  ts->h);
    1745          33 :                 add_assoc_long(return_value, "tm_mday",  ts->d);
    1746          33 :                 add_assoc_long(return_value, "tm_mon",   ts->m - 1);
    1747          33 :                 add_assoc_long(return_value, "tm_year",  ts->y - 1900);
    1748          33 :                 add_assoc_long(return_value, "tm_wday",  timelib_day_of_week(ts->y, ts->m, ts->d));
    1749          33 :                 add_assoc_long(return_value, "tm_yday",  timelib_day_of_year(ts->y, ts->m, ts->d));
    1750          33 :                 add_assoc_long(return_value, "tm_isdst", ts->dst);
    1751             :         } else {
    1752          31 :                 add_next_index_long(return_value, ts->s);
    1753          31 :                 add_next_index_long(return_value, ts->i);
    1754          31 :                 add_next_index_long(return_value, ts->h);
    1755          31 :                 add_next_index_long(return_value, ts->d);
    1756          31 :                 add_next_index_long(return_value, ts->m - 1);
    1757          31 :                 add_next_index_long(return_value, ts->y- 1900);
    1758          31 :                 add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
    1759          31 :                 add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
    1760          31 :                 add_next_index_long(return_value, ts->dst);
    1761             :         }
    1762             : 
    1763          64 :         timelib_time_dtor(ts);
    1764             : }
    1765             : /* }}} */
    1766             : 
    1767             : /* {{{ proto array getdate([int timestamp])
    1768             :    Get date/time information */
    1769          49 : PHP_FUNCTION(getdate)
    1770             : {
    1771          49 :         zend_long timestamp = (zend_long)time(NULL);
    1772             :         timelib_tzinfo *tzi;
    1773             :         timelib_time   *ts;
    1774             : 
    1775          49 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &timestamp) == FAILURE) {
    1776          14 :                 RETURN_FALSE;
    1777             :         }
    1778             : 
    1779          35 :         tzi = get_timezone_info();
    1780          35 :         ts = timelib_time_ctor();
    1781          35 :         ts->tz_info = tzi;
    1782          35 :         ts->zone_type = TIMELIB_ZONETYPE_ID;
    1783          35 :         timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1784             : 
    1785          35 :         array_init(return_value);
    1786             : 
    1787          35 :         add_assoc_long(return_value, "seconds", ts->s);
    1788          35 :         add_assoc_long(return_value, "minutes", ts->i);
    1789          35 :         add_assoc_long(return_value, "hours", ts->h);
    1790          35 :         add_assoc_long(return_value, "mday", ts->d);
    1791          35 :         add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
    1792          35 :         add_assoc_long(return_value, "mon", ts->m);
    1793          35 :         add_assoc_long(return_value, "year", ts->y);
    1794          35 :         add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
    1795          35 :         add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d));
    1796          35 :         add_assoc_string(return_value, "month", mon_full_names[ts->m - 1]);
    1797          35 :         add_index_long(return_value, 0, timestamp);
    1798             : 
    1799          35 :         timelib_time_dtor(ts);
    1800             : }
    1801             : /* }}} */
    1802             : 
    1803             : #define PHP_DATE_TIMEZONE_GROUP_AFRICA     0x0001
    1804             : #define PHP_DATE_TIMEZONE_GROUP_AMERICA    0x0002
    1805             : #define PHP_DATE_TIMEZONE_GROUP_ANTARCTICA 0x0004
    1806             : #define PHP_DATE_TIMEZONE_GROUP_ARCTIC     0x0008
    1807             : #define PHP_DATE_TIMEZONE_GROUP_ASIA       0x0010
    1808             : #define PHP_DATE_TIMEZONE_GROUP_ATLANTIC   0x0020
    1809             : #define PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  0x0040
    1810             : #define PHP_DATE_TIMEZONE_GROUP_EUROPE     0x0080
    1811             : #define PHP_DATE_TIMEZONE_GROUP_INDIAN     0x0100
    1812             : #define PHP_DATE_TIMEZONE_GROUP_PACIFIC    0x0200
    1813             : #define PHP_DATE_TIMEZONE_GROUP_UTC        0x0400
    1814             : #define PHP_DATE_TIMEZONE_GROUP_ALL        0x07FF
    1815             : #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC   0x0FFF
    1816             : #define PHP_DATE_TIMEZONE_PER_COUNTRY      0x1000
    1817             : 
    1818             : #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
    1819             : 
    1820             : 
    1821             : /* define an overloaded iterator structure */
    1822             : typedef struct {
    1823             :         zend_object_iterator  intern;
    1824             :         zval                  current;
    1825             :         php_period_obj       *object;
    1826             :         int                   current_index;
    1827             : } date_period_it;
    1828             : 
    1829             : /* {{{ date_period_it_invalidate_current */
    1830          97 : static void date_period_it_invalidate_current(zend_object_iterator *iter)
    1831             : {
    1832          97 :         date_period_it *iterator = (date_period_it *)iter;
    1833             : 
    1834         194 :         if (Z_TYPE(iterator->current) != IS_UNDEF) {
    1835          75 :                 zval_ptr_dtor(&iterator->current);
    1836          75 :                 ZVAL_UNDEF(&iterator->current);
    1837             :         }
    1838          97 : }
    1839             : /* }}} */
    1840             : 
    1841             : /* {{{ date_period_it_dtor */
    1842          11 : static void date_period_it_dtor(zend_object_iterator *iter)
    1843             : {
    1844          11 :         date_period_it *iterator = (date_period_it *)iter;
    1845             : 
    1846          11 :         date_period_it_invalidate_current(iter);
    1847             : 
    1848          11 :         zval_ptr_dtor(&iterator->intern.data);
    1849          11 : }
    1850             : /* }}} */
    1851             : 
    1852             : /* {{{ date_period_it_has_more */
    1853          86 : static int date_period_it_has_more(zend_object_iterator *iter)
    1854             : {
    1855          86 :         date_period_it *iterator = (date_period_it *)iter;
    1856          86 :         php_period_obj *object   = Z_PHPPERIOD_P(&iterator->intern.data);
    1857          86 :         timelib_time   *it_time = object->current;
    1858             : 
    1859             :         /* apply modification if it's not the first iteration */
    1860          86 :         if (!object->include_start_date || iterator->current_index > 0) {
    1861          76 :                 it_time->have_relative = 1;
    1862          76 :                 it_time->relative = *object->interval;
    1863          76 :                 it_time->sse_uptodate = 0;
    1864          76 :                 timelib_update_ts(it_time, NULL);
    1865          76 :                 timelib_update_from_sse(it_time);
    1866             :         }
    1867             : 
    1868          86 :         if (object->end) {
    1869          46 :                 return object->current->sse < object->end->sse ? SUCCESS : FAILURE;
    1870             :         } else {
    1871          40 :                 return (iterator->current_index < object->recurrences) ? SUCCESS : FAILURE;
    1872             :         }
    1873             : }
    1874             : /* }}} */
    1875             : 
    1876             : /* {{{ date_period_it_current_data */
    1877          75 : static zval *date_period_it_current_data(zend_object_iterator *iter)
    1878             : {
    1879          75 :         date_period_it *iterator = (date_period_it *)iter;
    1880          75 :         php_period_obj *object   = Z_PHPPERIOD_P(&iterator->intern.data);
    1881          75 :         timelib_time   *it_time = object->current;
    1882             :         php_date_obj   *newdateobj;
    1883             : 
    1884             :         /* Create new object */
    1885          75 :         php_date_instantiate(object->start_ce, &iterator->current);
    1886          75 :         newdateobj = Z_PHPDATE_P(&iterator->current);
    1887          75 :         newdateobj->time = timelib_time_ctor();
    1888          75 :         *newdateobj->time = *it_time;
    1889          75 :         if (it_time->tz_abbr) {
    1890          63 :                 newdateobj->time->tz_abbr = timelib_strdup(it_time->tz_abbr);
    1891             :         }
    1892          75 :         if (it_time->tz_info) {
    1893          63 :                 newdateobj->time->tz_info = it_time->tz_info;
    1894             :         }
    1895             : 
    1896          75 :         return &iterator->current;
    1897             : }
    1898             : /* }}} */
    1899             : 
    1900             : /* {{{ date_period_it_current_key */
    1901           0 : static void date_period_it_current_key(zend_object_iterator *iter, zval *key)
    1902             : {
    1903           0 :         date_period_it *iterator = (date_period_it *)iter;
    1904           0 :         ZVAL_LONG(key, iterator->current_index);
    1905           0 : }
    1906             : /* }}} */
    1907             : 
    1908             : /* {{{ date_period_it_move_forward */
    1909          75 : static void date_period_it_move_forward(zend_object_iterator *iter)
    1910             : {
    1911          75 :         date_period_it   *iterator = (date_period_it *)iter;
    1912             : 
    1913          75 :         iterator->current_index++;
    1914          75 :         date_period_it_invalidate_current(iter);
    1915          75 : }
    1916             : /* }}} */
    1917             : 
    1918             : /* {{{ date_period_it_rewind */
    1919          11 : static void date_period_it_rewind(zend_object_iterator *iter)
    1920             : {
    1921          11 :         date_period_it *iterator = (date_period_it *)iter;
    1922             : 
    1923          11 :         iterator->current_index = 0;
    1924          11 :         if (iterator->object->current) {
    1925           3 :                 timelib_time_dtor(iterator->object->current);
    1926             :         }
    1927          11 :         iterator->object->current = timelib_time_clone(iterator->object->start);
    1928          11 :         date_period_it_invalidate_current(iter);
    1929          11 : }
    1930             : /* }}} */
    1931             : 
    1932             : /* iterator handler table */
    1933             : zend_object_iterator_funcs date_period_it_funcs = {
    1934             :         date_period_it_dtor,
    1935             :         date_period_it_has_more,
    1936             :         date_period_it_current_data,
    1937             :         date_period_it_current_key,
    1938             :         date_period_it_move_forward,
    1939             :         date_period_it_rewind,
    1940             :         date_period_it_invalidate_current
    1941             : };
    1942             : 
    1943          11 : zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
    1944             : {
    1945          11 :         date_period_it *iterator = emalloc(sizeof(date_period_it));
    1946             : 
    1947          11 :         if (by_ref) {
    1948           0 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
    1949             :         }
    1950             : 
    1951          11 :         zend_iterator_init((zend_object_iterator*)iterator);
    1952             : 
    1953          11 :         ZVAL_COPY(&iterator->intern.data, object);
    1954          11 :         iterator->intern.funcs = &date_period_it_funcs;
    1955          11 :         iterator->object = Z_PHPPERIOD_P(object);
    1956          11 :         ZVAL_UNDEF(&iterator->current);
    1957             : 
    1958          11 :         return (zend_object_iterator*)iterator;
    1959             : } /* }}} */
    1960             : 
    1961       45196 : static int implement_date_interface_handler(zend_class_entry *interface, zend_class_entry *implementor) /* {{{ */
    1962             : {
    1963       45220 :         if (implementor->type == ZEND_USER_CLASS &&
    1964          22 :                 !instanceof_function(implementor, date_ce_date) &&
    1965           2 :                 !instanceof_function(implementor, date_ce_immutable)
    1966             :         ) {
    1967           1 :                 zend_error(E_ERROR, "DateTimeInterface can't be implemented by user classes");
    1968             :         }
    1969             : 
    1970       45195 :         return SUCCESS;
    1971             : } /* }}} */
    1972             : 
    1973       22587 : static void date_register_classes(void) /* {{{ */
    1974             : {
    1975             :         zend_class_entry ce_date, ce_immutable, ce_timezone, ce_interval, ce_period, ce_interface;
    1976             : 
    1977       22587 :         INIT_CLASS_ENTRY(ce_interface, "DateTimeInterface", date_funcs_interface);
    1978       22587 :         date_ce_interface = zend_register_internal_interface(&ce_interface);
    1979       22587 :         date_ce_interface->interface_gets_implemented = implement_date_interface_handler;
    1980             : 
    1981       22587 :         INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
    1982       22587 :         ce_date.create_object = date_object_new_date;
    1983       22587 :         date_ce_date = zend_register_internal_class_ex(&ce_date, NULL);
    1984       22587 :         memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1985       22587 :         date_object_handlers_date.offset = XtOffsetOf(php_date_obj, std);
    1986       22587 :         date_object_handlers_date.free_obj = date_object_free_storage_date;
    1987       22587 :         date_object_handlers_date.clone_obj = date_object_clone_date;
    1988       22587 :         date_object_handlers_date.compare_objects = date_object_compare_date;
    1989       22587 :         date_object_handlers_date.get_properties = date_object_get_properties;
    1990       22587 :         date_object_handlers_date.get_gc = date_object_get_gc;
    1991       22587 :         zend_class_implements(date_ce_date, 1, date_ce_interface);
    1992             : 
    1993             : #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
    1994             :         zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1);
    1995             : 
    1996       22587 :         REGISTER_DATE_CLASS_CONST_STRING("ATOM",             DATE_FORMAT_RFC3339);
    1997       22587 :         REGISTER_DATE_CLASS_CONST_STRING("COOKIE",           DATE_FORMAT_COOKIE);
    1998       22587 :         REGISTER_DATE_CLASS_CONST_STRING("ISO8601",          DATE_FORMAT_ISO8601);
    1999       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC822",           DATE_FORMAT_RFC822);
    2000       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC850",           DATE_FORMAT_RFC850);
    2001       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC1036",          DATE_FORMAT_RFC1036);
    2002       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC1123",          DATE_FORMAT_RFC1123);
    2003       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC2822",          DATE_FORMAT_RFC2822);
    2004       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC3339",          DATE_FORMAT_RFC3339);
    2005       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RFC3339_EXTENDED", DATE_FORMAT_RFC3339_EXTENDED);
    2006       22587 :         REGISTER_DATE_CLASS_CONST_STRING("RSS",              DATE_FORMAT_RFC1123);
    2007       22587 :         REGISTER_DATE_CLASS_CONST_STRING("W3C",              DATE_FORMAT_RFC3339);
    2008             : 
    2009       22587 :         INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable);
    2010       22587 :         ce_immutable.create_object = date_object_new_date;
    2011       22587 :         date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL);
    2012       22587 :         memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2013       22587 :         date_object_handlers_immutable.clone_obj = date_object_clone_date;
    2014       22587 :         date_object_handlers_immutable.compare_objects = date_object_compare_date;
    2015       22587 :         date_object_handlers_immutable.get_properties = date_object_get_properties;
    2016       22587 :         zend_class_implements(date_ce_immutable, 1, date_ce_interface);
    2017             : 
    2018       22587 :         INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
    2019       22587 :         ce_timezone.create_object = date_object_new_timezone;
    2020       22587 :         date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL);
    2021       22587 :         memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2022       22587 :         date_object_handlers_timezone.offset = XtOffsetOf(php_timezone_obj, std);
    2023       22587 :         date_object_handlers_timezone.free_obj = date_object_free_storage_timezone;
    2024       22587 :         date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
    2025       22587 :         date_object_handlers_timezone.get_properties = date_object_get_properties_timezone;
    2026       22587 :         date_object_handlers_timezone.get_gc = date_object_get_gc_timezone;
    2027             : 
    2028             : #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \
    2029             :         zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value);
    2030             : 
    2031       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AFRICA",      PHP_DATE_TIMEZONE_GROUP_AFRICA);
    2032       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AMERICA",     PHP_DATE_TIMEZONE_GROUP_AMERICA);
    2033       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ANTARCTICA",  PHP_DATE_TIMEZONE_GROUP_ANTARCTICA);
    2034       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ARCTIC",      PHP_DATE_TIMEZONE_GROUP_ARCTIC);
    2035       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ASIA",        PHP_DATE_TIMEZONE_GROUP_ASIA);
    2036       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ATLANTIC",    PHP_DATE_TIMEZONE_GROUP_ATLANTIC);
    2037       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AUSTRALIA",   PHP_DATE_TIMEZONE_GROUP_AUSTRALIA);
    2038       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("EUROPE",      PHP_DATE_TIMEZONE_GROUP_EUROPE);
    2039       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("INDIAN",      PHP_DATE_TIMEZONE_GROUP_INDIAN);
    2040       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("PACIFIC",     PHP_DATE_TIMEZONE_GROUP_PACIFIC);
    2041       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC",         PHP_DATE_TIMEZONE_GROUP_UTC);
    2042       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL",         PHP_DATE_TIMEZONE_GROUP_ALL);
    2043       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
    2044       22587 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
    2045             : 
    2046       22587 :         INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
    2047       22587 :         ce_interval.create_object = date_object_new_interval;
    2048       22587 :         date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL);
    2049       22587 :         memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2050       22587 :         date_object_handlers_interval.offset = XtOffsetOf(php_interval_obj, std);
    2051       22587 :         date_object_handlers_interval.free_obj = date_object_free_storage_interval;
    2052       22587 :         date_object_handlers_interval.clone_obj = date_object_clone_interval;
    2053       22587 :         date_object_handlers_interval.read_property = date_interval_read_property;
    2054       22587 :         date_object_handlers_interval.write_property = date_interval_write_property;
    2055       22587 :         date_object_handlers_interval.get_properties = date_object_get_properties_interval;
    2056       22587 :         date_object_handlers_interval.get_property_ptr_ptr = NULL;
    2057       22587 :         date_object_handlers_interval.get_gc = date_object_get_gc_interval;
    2058             : 
    2059       22587 :         INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
    2060       22587 :         ce_period.create_object = date_object_new_period;
    2061       22587 :         date_ce_period = zend_register_internal_class_ex(&ce_period, NULL);
    2062       22587 :         date_ce_period->get_iterator = date_object_period_get_iterator;
    2063       22587 :         date_ce_period->iterator_funcs.funcs = &date_period_it_funcs;
    2064       22587 :         zend_class_implements(date_ce_period, 1, zend_ce_traversable);
    2065       22587 :         memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2066       22587 :         date_object_handlers_period.offset = XtOffsetOf(php_period_obj, std);
    2067       22587 :         date_object_handlers_period.free_obj = date_object_free_storage_period;
    2068       22587 :         date_object_handlers_period.clone_obj = date_object_clone_period;
    2069       22587 :         date_object_handlers_period.get_properties = date_object_get_properties_period;
    2070       22587 :         date_object_handlers_period.get_property_ptr_ptr = NULL;
    2071       22587 :         date_object_handlers_period.get_gc = date_object_get_gc_period;
    2072       22587 :         date_object_handlers_period.read_property = date_period_read_property;
    2073       22587 :         date_object_handlers_period.write_property = date_period_write_property;
    2074             : 
    2075             : #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
    2076             :         zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value);
    2077             : 
    2078       22587 :         REGISTER_PERIOD_CLASS_CONST_STRING("EXCLUDE_START_DATE", PHP_DATE_PERIOD_EXCLUDE_START_DATE);
    2079       22587 : } /* }}} */
    2080             : 
    2081      179287 : static inline zend_object *date_object_new_date_ex(zend_class_entry *class_type, int init_props) /* {{{ */
    2082             : {
    2083             :         php_date_obj *intern;
    2084             : 
    2085      179287 :         intern = ecalloc(1, sizeof(php_date_obj) + zend_object_properties_size(class_type));
    2086             : 
    2087      179287 :         zend_object_std_init(&intern->std, class_type);
    2088      179287 :         if (init_props) {
    2089        5026 :                 object_properties_init(&intern->std, class_type);
    2090             :         }
    2091      179287 :         intern->std.handlers = &date_object_handlers_date;
    2092             : 
    2093      179287 :         return &intern->std;
    2094             : } /* }}} */
    2095             : 
    2096        5026 : static zend_object *date_object_new_date(zend_class_entry *class_type) /* {{{ */
    2097             : {
    2098        5026 :         return date_object_new_date_ex(class_type, 1);
    2099             : } /* }}} */
    2100             : 
    2101      174261 : static zend_object *date_object_clone_date(zval *this_ptr) /* {{{ */
    2102             : {
    2103      174261 :         php_date_obj *old_obj = Z_PHPDATE_P(this_ptr);
    2104      174261 :         php_date_obj *new_obj = php_date_obj_from_obj(date_object_new_date_ex(old_obj->std.ce, 0));
    2105             : 
    2106      174261 :         zend_objects_clone_members(&new_obj->std, &old_obj->std);
    2107      174261 :         if (!old_obj->time) {
    2108           2 :                 return &new_obj->std;
    2109             :         }
    2110             : 
    2111             :         /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
    2112      174259 :         new_obj->time = timelib_time_ctor();
    2113      174259 :         *new_obj->time = *old_obj->time;
    2114      174259 :         if (old_obj->time->tz_abbr) {
    2115      174259 :                 new_obj->time->tz_abbr = timelib_strdup(old_obj->time->tz_abbr);
    2116             :         }
    2117      174259 :         if (old_obj->time->tz_info) {
    2118      174259 :                 new_obj->time->tz_info = old_obj->time->tz_info;
    2119             :         }
    2120             : 
    2121      174259 :         return &new_obj->std;
    2122             : } /* }}} */
    2123             : 
    2124          12 : static void date_clone_immutable(zval *object, zval *new_object) /* {{{ */
    2125             : {
    2126          12 :         ZVAL_OBJ(new_object, date_object_clone_date(object));
    2127          12 : } /* }}} */
    2128             : 
    2129      345627 : static int date_object_compare_date(zval *d1, zval *d2) /* {{{ */
    2130             : {
    2131      345627 :         php_date_obj *o1 = Z_PHPDATE_P(d1);
    2132      345627 :         php_date_obj *o2 = Z_PHPDATE_P(d2);
    2133             : 
    2134      345627 :         if (!o1->time || !o2->time) {
    2135           0 :                 php_error_docref(NULL, E_WARNING, "Trying to compare an incomplete DateTime or DateTimeImmutable object");
    2136           0 :                 return 1;
    2137             :         }
    2138      345627 :         if (!o1->time->sse_uptodate) {
    2139           0 :                 timelib_update_ts(o1->time, o1->time->tz_info);
    2140             :         }
    2141      345627 :         if (!o2->time->sse_uptodate) {
    2142           0 :                 timelib_update_ts(o2->time, o2->time->tz_info);
    2143             :         }
    2144             : 
    2145      345627 :         return timelib_time_compare(o1->time, o2->time);
    2146             : } /* }}} */
    2147             : 
    2148           2 : static HashTable *date_object_get_gc(zval *object, zval **table, int *n) /* {{{ */
    2149             : {
    2150           2 :         *table = NULL;
    2151           2 :         *n = 0;
    2152           2 :         return zend_std_get_properties(object);
    2153             : } /* }}} */
    2154             : 
    2155           0 : static HashTable *date_object_get_gc_timezone(zval *object, zval **table, int *n) /* {{{ */
    2156             : {
    2157           0 :        *table = NULL;
    2158           0 :        *n = 0;
    2159           0 :        return zend_std_get_properties(object);
    2160             : } /* }}} */
    2161             : 
    2162         447 : static HashTable *date_object_get_properties(zval *object) /* {{{ */
    2163             : {
    2164             :         HashTable *props;
    2165             :         zval zv;
    2166             :         php_date_obj     *dateobj;
    2167             : 
    2168             : 
    2169         447 :         dateobj = Z_PHPDATE_P(object);
    2170             : 
    2171         447 :         props = zend_std_get_properties(object);
    2172             : 
    2173         447 :         if (!dateobj->time || GC_G(gc_active)) {
    2174          27 :                 return props;
    2175             :         }
    2176             : 
    2177             :         /* first we add the date and time in ISO format */
    2178         420 :         ZVAL_STR(&zv, date_format("Y-m-d H:i:s.u", sizeof("Y-m-d H:i:s.u")-1, dateobj->time, 1));
    2179         420 :         zend_hash_str_update(props, "date", sizeof("date")-1, &zv);
    2180             : 
    2181             :         /* then we add the timezone name (or similar) */
    2182         420 :         if (dateobj->time->is_localtime) {
    2183         420 :                 ZVAL_LONG(&zv, dateobj->time->zone_type);
    2184         420 :                 zend_hash_str_update(props, "timezone_type", sizeof("timezone_type")-1, &zv);
    2185             : 
    2186         420 :                 switch (dateobj->time->zone_type) {
    2187             :                         case TIMELIB_ZONETYPE_ID:
    2188         762 :                                 ZVAL_STRING(&zv, dateobj->time->tz_info->name);
    2189         381 :                                 break;
    2190             :                         case TIMELIB_ZONETYPE_OFFSET: {
    2191          12 :                                 zend_string *tmpstr = zend_string_alloc(sizeof("UTC+05:00")-1, 0);
    2192          12 :                                 timelib_sll utc_offset = dateobj->time->z;
    2193             : 
    2194          24 :                                 ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), sizeof("+05:00"), "%c%02d:%02d",
    2195             :                                         utc_offset > 0 ? '-' : '+',
    2196          12 :                                         abs(utc_offset / 60),
    2197          12 :                                         abs((utc_offset % 60)));
    2198             : 
    2199          12 :                                 ZVAL_NEW_STR(&zv, tmpstr);
    2200             :                                 }
    2201          12 :                                 break;
    2202             :                         case TIMELIB_ZONETYPE_ABBR:
    2203          54 :                                 ZVAL_STRING(&zv, dateobj->time->tz_abbr);
    2204             :                                 break;
    2205             :                 }
    2206         420 :                 zend_hash_str_update(props, "timezone", sizeof("timezone")-1, &zv);
    2207             :         }
    2208             : 
    2209         420 :         return props;
    2210             : } /* }}} */
    2211             : 
    2212         834 : static inline zend_object *date_object_new_timezone_ex(zend_class_entry *class_type, int init_props) /* {{{ */
    2213             : {
    2214             :         php_timezone_obj *intern;
    2215             : 
    2216         834 :         intern = ecalloc(1, sizeof(php_timezone_obj) + zend_object_properties_size(class_type));
    2217             : 
    2218         834 :         zend_object_std_init(&intern->std, class_type);
    2219         834 :         if (init_props) {
    2220         826 :                 object_properties_init(&intern->std, class_type);
    2221             :         }
    2222         834 :         intern->std.handlers = &date_object_handlers_timezone;
    2223             : 
    2224         834 :         return &intern->std;
    2225             : } /* }}} */
    2226             : 
    2227         826 : static zend_object *date_object_new_timezone(zend_class_entry *class_type) /* {{{ */
    2228             : {
    2229         826 :         return date_object_new_timezone_ex(class_type, 1);
    2230             : } /* }}} */
    2231             : 
    2232           8 : static zend_object *date_object_clone_timezone(zval *this_ptr) /* {{{ */
    2233             : {
    2234           8 :         php_timezone_obj *old_obj = Z_PHPTIMEZONE_P(this_ptr);
    2235           8 :         php_timezone_obj *new_obj = php_timezone_obj_from_obj(date_object_new_timezone_ex(old_obj->std.ce, 0));
    2236             : 
    2237           8 :         zend_objects_clone_members(&new_obj->std, &old_obj->std);
    2238           8 :         if (!old_obj->initialized) {
    2239           1 :                 return &new_obj->std;
    2240             :         }
    2241             : 
    2242           7 :         new_obj->type = old_obj->type;
    2243           7 :         new_obj->initialized = 1;
    2244           7 :         switch (new_obj->type) {
    2245             :                 case TIMELIB_ZONETYPE_ID:
    2246           6 :                         new_obj->tzi.tz = old_obj->tzi.tz;
    2247           6 :                         break;
    2248             :                 case TIMELIB_ZONETYPE_OFFSET:
    2249           0 :                         new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
    2250           0 :                         break;
    2251             :                 case TIMELIB_ZONETYPE_ABBR:
    2252           1 :                         new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
    2253           1 :                         new_obj->tzi.z.dst        = old_obj->tzi.z.dst;
    2254           1 :                         new_obj->tzi.z.abbr       = timelib_strdup(old_obj->tzi.z.abbr);
    2255             :                         break;
    2256             :         }
    2257             : 
    2258           7 :         return &new_obj->std;
    2259             : } /* }}} */
    2260             : 
    2261          66 : static HashTable *date_object_get_properties_timezone(zval *object) /* {{{ */
    2262             : {
    2263             :         HashTable *props;
    2264             :         zval zv;
    2265             :         php_timezone_obj     *tzobj;
    2266             : 
    2267             : 
    2268          66 :         tzobj = Z_PHPTIMEZONE_P(object);
    2269             : 
    2270          66 :         props = zend_std_get_properties(object);
    2271             : 
    2272          66 :         if (!tzobj->initialized) {
    2273           8 :                 return props;
    2274             :         }
    2275             : 
    2276          58 :         ZVAL_LONG(&zv, tzobj->type);
    2277          58 :         zend_hash_str_update(props, "timezone_type", sizeof("timezone_type")-1, &zv);
    2278             : 
    2279          58 :         switch (tzobj->type) {
    2280             :                 case TIMELIB_ZONETYPE_ID:
    2281          90 :                         ZVAL_STRING(&zv, tzobj->tzi.tz->name);
    2282          45 :                         break;
    2283             :                 case TIMELIB_ZONETYPE_OFFSET: {
    2284           5 :                         zend_string *tmpstr = zend_string_alloc(sizeof("UTC+05:00")-1, 0);
    2285             : 
    2286          15 :                         ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), sizeof("+05:00"), "%c%02d:%02d",
    2287           5 :                         tzobj->tzi.utc_offset > 0 ? '-' : '+',
    2288           5 :                         abs(tzobj->tzi.utc_offset / 60),
    2289           5 :                         abs((tzobj->tzi.utc_offset % 60)));
    2290             : 
    2291           5 :                         ZVAL_NEW_STR(&zv, tmpstr);
    2292             :                         }
    2293           5 :                         break;
    2294             :                 case TIMELIB_ZONETYPE_ABBR:
    2295          16 :                         ZVAL_STRING(&zv, tzobj->tzi.z.abbr);
    2296             :                         break;
    2297             :         }
    2298          58 :         zend_hash_str_update(props, "timezone", sizeof("timezone")-1, &zv);
    2299             : 
    2300          58 :         return props;
    2301             : } /* }}} */
    2302             : 
    2303      349106 : static inline zend_object *date_object_new_interval_ex(zend_class_entry *class_type, int init_props) /* {{{ */
    2304             : {
    2305             :         php_interval_obj *intern;
    2306             : 
    2307      349106 :         intern = ecalloc(1, sizeof(php_interval_obj) + zend_object_properties_size(class_type));
    2308             : 
    2309      349106 :         zend_object_std_init(&intern->std, class_type);
    2310      349106 :         if (init_props) {
    2311      349106 :                 object_properties_init(&intern->std, class_type);
    2312             :         }
    2313      349106 :         intern->std.handlers = &date_object_handlers_interval;
    2314             : 
    2315      349106 :         return &intern->std;
    2316             : } /* }}} */
    2317             : 
    2318      349106 : static zend_object *date_object_new_interval(zend_class_entry *class_type) /* {{{ */
    2319             : {
    2320      349106 :         return date_object_new_interval_ex(class_type, 1);
    2321             : } /* }}} */
    2322             : 
    2323           0 : static zend_object *date_object_clone_interval(zval *this_ptr) /* {{{ */
    2324             : {
    2325           0 :         php_interval_obj *old_obj = Z_PHPINTERVAL_P(this_ptr);
    2326           0 :         php_interval_obj *new_obj = php_interval_obj_from_obj(date_object_new_interval_ex(old_obj->std.ce, 0));
    2327             : 
    2328           0 :         zend_objects_clone_members(&new_obj->std, &old_obj->std);
    2329             : 
    2330             :         /** FIX ME ADD CLONE STUFF **/
    2331           0 :         return &new_obj->std;
    2332             : } /* }}} */
    2333             : 
    2334           0 : static HashTable *date_object_get_gc_interval(zval *object, zval **table, int *n) /* {{{ */
    2335             : {
    2336             : 
    2337           0 :         *table = NULL;
    2338           0 :         *n = 0;
    2339           0 :         return zend_std_get_properties(object);
    2340             : } /* }}} */
    2341             : 
    2342          43 : static HashTable *date_object_get_properties_interval(zval *object) /* {{{ */
    2343             : {
    2344             :         HashTable *props;
    2345             :         zval zv;
    2346             :         php_interval_obj     *intervalobj;
    2347             : 
    2348          43 :         intervalobj = Z_PHPINTERVAL_P(object);
    2349             : 
    2350          43 :         props = zend_std_get_properties(object);
    2351             : 
    2352          43 :         if (!intervalobj->initialized) {
    2353          14 :                 return props;
    2354             :         }
    2355             : 
    2356             : #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
    2357             :         ZVAL_LONG(&zv, (zend_long)intervalobj->diff->f); \
    2358             :         zend_hash_str_update(props, n, sizeof(n)-1, &zv);
    2359             : 
    2360          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("y", y);
    2361          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("m", m);
    2362          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("d", d);
    2363          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
    2364          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
    2365          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
    2366          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("weekday", weekday);
    2367          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior);
    2368          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of);
    2369          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
    2370          29 :         if (intervalobj->diff->days != -99999) {
    2371          20 :                 PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
    2372             :         } else {
    2373           9 :                 ZVAL_FALSE(&zv);
    2374           9 :                 zend_hash_str_update(props, "days", sizeof("days")-1, &zv);
    2375             :         }
    2376          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("special_type", special.type);
    2377          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("special_amount", special.amount);
    2378          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("have_weekday_relative", have_weekday_relative);
    2379          29 :         PHP_DATE_INTERVAL_ADD_PROPERTY("have_special_relative", have_special_relative);
    2380             : 
    2381          29 :         return props;
    2382             : } /* }}} */
    2383             : 
    2384          17 : static inline zend_object *date_object_new_period_ex(zend_class_entry *class_type, int init_props) /* {{{ */
    2385             : {
    2386             :         php_period_obj *intern;
    2387             : 
    2388          17 :         intern = ecalloc(1, sizeof(php_period_obj) + zend_object_properties_size(class_type));
    2389             : 
    2390          17 :         zend_object_std_init(&intern->std, class_type);
    2391          17 :         if (init_props) {
    2392          17 :                 object_properties_init(&intern->std, class_type);
    2393             :         }
    2394             : 
    2395          17 :         intern->std.handlers = &date_object_handlers_period;
    2396             : 
    2397          17 :         return &intern->std;
    2398             : } /* }}} */
    2399             : 
    2400          17 : static zend_object *date_object_new_period(zend_class_entry *class_type) /* {{{ */
    2401             : {
    2402          17 :         return date_object_new_period_ex(class_type, 1);
    2403             : } /* }}} */
    2404             : 
    2405           0 : static zend_object *date_object_clone_period(zval *this_ptr) /* {{{ */
    2406             : {
    2407           0 :         php_period_obj *old_obj = Z_PHPPERIOD_P(this_ptr);
    2408           0 :         php_period_obj *new_obj = php_period_obj_from_obj(date_object_new_period_ex(old_obj->std.ce, 0));
    2409             : 
    2410           0 :         zend_objects_clone_members(&new_obj->std, &old_obj->std);
    2411             : 
    2412             :         /** FIX ME ADD CLONE STUFF **/
    2413           0 :         return &new_obj->std;
    2414             : } /* }}} */
    2415             : 
    2416      179287 : static void date_object_free_storage_date(zend_object *object) /* {{{ */
    2417             : {
    2418      179287 :         php_date_obj *intern = php_date_obj_from_obj(object);
    2419             : 
    2420      179287 :         if (intern->time) {
    2421      179178 :                 timelib_time_dtor(intern->time);
    2422             :         }
    2423             : 
    2424      179287 :         zend_object_std_dtor(&intern->std);
    2425      179287 : } /* }}} */
    2426             : 
    2427         834 : static void date_object_free_storage_timezone(zend_object *object) /* {{{ */
    2428             : {
    2429         834 :         php_timezone_obj *intern = php_timezone_obj_from_obj(object);
    2430             : 
    2431         834 :         if (intern->type == TIMELIB_ZONETYPE_ABBR) {
    2432          22 :                 timelib_free(intern->tzi.z.abbr);
    2433             :         }
    2434         834 :         zend_object_std_dtor(&intern->std);
    2435         834 : } /* }}} */
    2436             : 
    2437      349106 : static void date_object_free_storage_interval(zend_object *object) /* {{{ */
    2438             : {
    2439      349106 :         php_interval_obj *intern = php_interval_obj_from_obj(object);
    2440             : 
    2441      349106 :         timelib_rel_time_dtor(intern->diff);
    2442      349106 :         zend_object_std_dtor(&intern->std);
    2443      349106 : } /* }}} */
    2444             : 
    2445          17 : static void date_object_free_storage_period(zend_object *object) /* {{{ */
    2446             : {
    2447          17 :         php_period_obj *intern = php_period_obj_from_obj(object);
    2448             : 
    2449          17 :         if (intern->start) {
    2450          13 :                 timelib_time_dtor(intern->start);
    2451             :         }
    2452             : 
    2453          17 :         if (intern->current) {
    2454           9 :                 timelib_time_dtor(intern->current);
    2455             :         }
    2456             : 
    2457          17 :         if (intern->end) {
    2458           5 :                 timelib_time_dtor(intern->end);
    2459             :         }
    2460             : 
    2461          17 :         timelib_rel_time_dtor(intern->interval);
    2462          17 :         zend_object_std_dtor(&intern->std);
    2463          17 : } /* }}} */
    2464             : 
    2465             : /* Advanced Interface */
    2466      174951 : PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
    2467             : {
    2468      174951 :         object_init_ex(object, pce);
    2469      174951 :         return object;
    2470             : } /* }}} */
    2471             : 
    2472             : /* Helper function used to store the latest found warnings and errors while
    2473             :  * parsing, from either strtotime or parse_from_format. */
    2474        5192 : static void update_errors_warnings(timelib_error_container *last_errors) /* {{{ */
    2475             : {
    2476        5192 :         if (DATEG(last_errors)) {
    2477        4935 :                 timelib_error_container_dtor(DATEG(last_errors));
    2478        4935 :                 DATEG(last_errors) = NULL;
    2479             :         }
    2480        5192 :         DATEG(last_errors) = last_errors;
    2481        5192 : } /* }}} */
    2482             : 
    2483        4892 : PHPAPI int php_date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, size_t time_str_len, char *format, zval *timezone_object, int ctor) /* {{{ */
    2484             : {
    2485             :         timelib_time   *now;
    2486        4892 :         timelib_tzinfo *tzi = NULL;
    2487        4892 :         timelib_error_container *err = NULL;
    2488        4892 :         int type = TIMELIB_ZONETYPE_ID, new_dst = 0;
    2489        4892 :         char *new_abbr = NULL;
    2490        4892 :         timelib_sll new_offset = 0;
    2491             : 
    2492        4892 :         if (dateobj->time) {
    2493           0 :                 timelib_time_dtor(dateobj->time);
    2494             :         }
    2495        4892 :         if (format) {
    2496        1062 :                 dateobj->time = timelib_parse_from_format(format, time_str_len ? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2497             :         } else {
    2498        3830 :                 dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2499             :         }
    2500             : 
    2501             :         /* update last errors and warnings */
    2502        4892 :         update_errors_warnings(err);
    2503             : 
    2504             : 
    2505        4892 :         if (ctor && err && err->error_count) {
    2506             :                 /* spit out the first library error message, at least */
    2507          84 :                 php_error_docref(NULL, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
    2508          84 :                         err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
    2509             :         }
    2510        4892 :         if (err && err->error_count) {
    2511          61 :                 timelib_time_dtor(dateobj->time);
    2512          61 :                 dateobj->time = 0;
    2513          61 :                 return 0;
    2514             :         }
    2515             : 
    2516        4831 :         if (timezone_object) {
    2517             :                 php_timezone_obj *tzobj;
    2518             : 
    2519          61 :                 tzobj = Z_PHPTIMEZONE_P(timezone_object);
    2520          61 :                 switch (tzobj->type) {
    2521             :                         case TIMELIB_ZONETYPE_ID:
    2522          58 :                                 tzi = tzobj->tzi.tz;
    2523          58 :                                 break;
    2524             :                         case TIMELIB_ZONETYPE_OFFSET:
    2525           0 :                                 new_offset = tzobj->tzi.utc_offset;
    2526           0 :                                 break;
    2527             :                         case TIMELIB_ZONETYPE_ABBR:
    2528           3 :                                 new_offset = tzobj->tzi.z.utc_offset;
    2529           3 :                                 new_dst    = tzobj->tzi.z.dst;
    2530           3 :                                 new_abbr   = timelib_strdup(tzobj->tzi.z.abbr);
    2531             :                                 break;
    2532             :                 }
    2533          61 :                 type = tzobj->type;
    2534        4770 :         } else if (dateobj->time->tz_info) {
    2535         535 :                 tzi = dateobj->time->tz_info;
    2536             :         } else {
    2537        4235 :                 tzi = get_timezone_info();
    2538             :         }
    2539             : 
    2540        4831 :         now = timelib_time_ctor();
    2541        4831 :         now->zone_type = type;
    2542        4831 :         switch (type) {
    2543             :                 case TIMELIB_ZONETYPE_ID:
    2544        4828 :                         now->tz_info = tzi;
    2545        4828 :                         break;
    2546             :                 case TIMELIB_ZONETYPE_OFFSET:
    2547           0 :                         now->z = new_offset;
    2548           0 :                         break;
    2549             :                 case TIMELIB_ZONETYPE_ABBR:
    2550           3 :                         now->z = new_offset;
    2551           3 :                         now->dst = new_dst;
    2552           3 :                         now->tz_abbr = new_abbr;
    2553             :                         break;
    2554             :         }
    2555        4831 :         timelib_unixtime2local(now, (timelib_sll) time(NULL));
    2556             : 
    2557        4831 :         timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
    2558        4831 :         timelib_update_ts(dateobj->time, tzi);
    2559        4831 :         timelib_update_from_sse(dateobj->time);
    2560             : 
    2561        4831 :         dateobj->time->have_relative = 0;
    2562             : 
    2563        4831 :         timelib_time_dtor(now);
    2564             : 
    2565        4831 :         return 1;
    2566             : } /* }}} */
    2567             : 
    2568             : /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
    2569             :    Returns new DateTime object
    2570             : */
    2571         245 : PHP_FUNCTION(date_create)
    2572             : {
    2573         245 :         zval           *timezone_object = NULL;
    2574         245 :         char           *time_str = NULL;
    2575         245 :         size_t          time_str_len = 0;
    2576             : 
    2577         245 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2578          38 :                 RETURN_FALSE;
    2579             :         }
    2580             : 
    2581         207 :         php_date_instantiate(date_ce_date, return_value);
    2582         207 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
    2583          25 :                 zval_ptr_dtor(return_value);
    2584          25 :                 RETURN_FALSE;
    2585             :         }
    2586             : }
    2587             : /* }}} */
    2588             : 
    2589             : /* {{{ proto DateTime date_create_immutable([string time[, DateTimeZone object]])
    2590             :    Returns new DateTime object
    2591             : */
    2592          11 : PHP_FUNCTION(date_create_immutable)
    2593             : {
    2594          11 :         zval           *timezone_object = NULL;
    2595          11 :         char           *time_str = NULL;
    2596          11 :         size_t          time_str_len = 0;
    2597             : 
    2598          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2599           0 :                 RETURN_FALSE;
    2600             :         }
    2601             : 
    2602          11 :         php_date_instantiate(date_ce_immutable, return_value);
    2603          11 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) {
    2604           0 :                 zval_ptr_dtor(return_value);
    2605           0 :                 RETURN_FALSE;
    2606             :         }
    2607             : }
    2608             : /* }}} */
    2609             : 
    2610             : /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object])
    2611             :    Returns new DateTime object formatted according to the specified format
    2612             : */
    2613        1061 : PHP_FUNCTION(date_create_from_format)
    2614             : {
    2615        1061 :         zval           *timezone_object = NULL;
    2616        1061 :         char           *time_str = NULL, *format_str = NULL;
    2617        1061 :         size_t             time_str_len = 0, format_str_len = 0;
    2618             : 
    2619        1061 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|O!", &format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2620           1 :                 RETURN_FALSE;
    2621             :         }
    2622             : 
    2623        1060 :         php_date_instantiate(date_ce_date, return_value);
    2624        1060 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, 0)) {
    2625           6 :                 zval_ptr_dtor(return_value);
    2626           6 :                 RETURN_FALSE;
    2627             :         }
    2628             : }
    2629             : /* }}} */
    2630             : 
    2631             : /* {{{ proto DateTime date_create_immutable_from_format(string format, string time[, DateTimeZone object])
    2632             :    Returns new DateTime object formatted according to the specified format
    2633             : */
    2634           2 : PHP_FUNCTION(date_create_immutable_from_format)
    2635             : {
    2636           2 :         zval           *timezone_object = NULL;
    2637           2 :         char           *time_str = NULL, *format_str = NULL;
    2638           2 :         size_t          time_str_len = 0, format_str_len = 0;
    2639             : 
    2640           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|O!", &format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2641           0 :                 RETURN_FALSE;
    2642             :         }
    2643             : 
    2644           2 :         php_date_instantiate(date_ce_immutable, return_value);
    2645           2 :         if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, 0)) {
    2646           0 :                 zval_ptr_dtor(return_value);
    2647           0 :                 RETURN_FALSE;
    2648             :         }
    2649             : }
    2650             : /* }}} */
    2651             : 
    2652             : /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
    2653             :    Creates new DateTime object
    2654             : */
    2655        3634 : PHP_METHOD(DateTime, __construct)
    2656             : {
    2657        3634 :         zval *timezone_object = NULL;
    2658        3634 :         char *time_str = NULL;
    2659        3634 :         size_t time_str_len = 0;
    2660             :         zend_error_handling error_handling;
    2661             : 
    2662        3634 :         if (FAILURE == zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
    2663          38 :                 return;
    2664             :         }
    2665             : 
    2666        3596 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling);
    2667        3596 :         php_date_initialize(Z_PHPDATE_P(getThis()), time_str, time_str_len, NULL, timezone_object, 1);
    2668        3596 :         zend_restore_error_handling(&error_handling);
    2669             : }
    2670             : /* }}} */
    2671             : 
    2672             : /* {{{ proto DateTimeImmutable::__construct([string time[, DateTimeZone object]])
    2673             :    Creates new DateTimeImmutable object
    2674             : */
    2675           7 : PHP_METHOD(DateTimeImmutable, __construct)
    2676             : {
    2677           7 :         zval *timezone_object = NULL;
    2678           7 :         char *time_str = NULL;
    2679           7 :         size_t time_str_len = 0;
    2680             :         zend_error_handling error_handling;
    2681             : 
    2682           7 :         if (FAILURE == zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
    2683           0 :                 return;
    2684             :         }
    2685             : 
    2686           7 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling);
    2687           7 :         php_date_initialize(Z_PHPDATE_P(getThis()), time_str, time_str_len, NULL, timezone_object, 1);
    2688           7 :         zend_restore_error_handling(&error_handling);
    2689             : }
    2690             : /* }}} */
    2691             : 
    2692             : /* {{{ proto DateTimeImmutable::createFromMutable(DateTimeZone object)
    2693             :    Creates new DateTimeImmutable object from an existing mutable DateTime object.
    2694             : */
    2695           2 : PHP_METHOD(DateTimeImmutable, createFromMutable)
    2696             : {
    2697           2 :         zval *datetime_object = NULL;
    2698           2 :         php_date_obj *new_obj = NULL;
    2699           2 :         php_date_obj *old_obj = NULL;
    2700             : 
    2701           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &datetime_object, date_ce_date) == FAILURE) {
    2702           1 :                 return;
    2703             :         }
    2704             : 
    2705           1 :         php_date_instantiate(date_ce_immutable, return_value);
    2706           1 :         old_obj = Z_PHPDATE_P(datetime_object);
    2707           1 :         new_obj = Z_PHPDATE_P(return_value);
    2708             : 
    2709           1 :         new_obj->time = timelib_time_ctor();
    2710           1 :         *new_obj->time = *old_obj->time;
    2711           1 :         if (old_obj->time->tz_abbr) {
    2712           1 :                 new_obj->time->tz_abbr = timelib_strdup(old_obj->time->tz_abbr);
    2713             :         }
    2714           1 :         if (old_obj->time->tz_info) {
    2715           1 :                 new_obj->time->tz_info = old_obj->time->tz_info;
    2716             :         }
    2717             : }
    2718             : /* }}} */
    2719             : 
    2720          13 : static int php_date_initialize_from_hash(php_date_obj **dateobj, HashTable *myht)
    2721             : {
    2722             :         zval             *z_date;
    2723             :         zval             *z_timezone;
    2724             :         zval             *z_timezone_type;
    2725             :         zval              tmp_obj;
    2726             :         timelib_tzinfo   *tzi;
    2727             :         php_timezone_obj *tzobj;
    2728             : 
    2729          13 :         z_date = zend_hash_str_find(myht, "date", sizeof("data")-1);
    2730          25 :         if (z_date && Z_TYPE_P(z_date) == IS_STRING) {
    2731          12 :                 z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type")-1);
    2732          24 :                 if (z_timezone_type && Z_TYPE_P(z_timezone_type) == IS_LONG) {
    2733          11 :                         z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone")-1);
    2734          22 :                         if (z_timezone && Z_TYPE_P(z_timezone) == IS_STRING) {
    2735          11 :                                 switch (Z_LVAL_P(z_timezone_type)) {
    2736             :                                         case TIMELIB_ZONETYPE_OFFSET:
    2737             :                                         case TIMELIB_ZONETYPE_ABBR: {
    2738           0 :                                                 char *tmp = emalloc(Z_STRLEN_P(z_date) + Z_STRLEN_P(z_timezone) + 2);
    2739             :                                                 int ret;
    2740           0 :                                                 snprintf(tmp, Z_STRLEN_P(z_date) + Z_STRLEN_P(z_timezone) + 2, "%s %s", Z_STRVAL_P(z_date), Z_STRVAL_P(z_timezone));
    2741           0 :                                                 ret = php_date_initialize(*dateobj, tmp, Z_STRLEN_P(z_date) + Z_STRLEN_P(z_timezone) + 1, NULL, NULL, 0);
    2742           0 :                                                 efree(tmp);
    2743           0 :                                                 return 1 == ret;
    2744             :                                         }
    2745             : 
    2746             :                                         case TIMELIB_ZONETYPE_ID: {
    2747             :                                                 int ret;
    2748             : 
    2749          10 :                                                 tzi = php_date_parse_tzfile(Z_STRVAL_P(z_timezone), DATE_TIMEZONEDB);
    2750             : 
    2751          10 :                                                 if (tzi == NULL) {
    2752           1 :                                                         return 0;
    2753             :                                                 }
    2754             : 
    2755           9 :                                                 tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, &tmp_obj));
    2756           9 :                                                 tzobj->type = TIMELIB_ZONETYPE_ID;
    2757           9 :                                                 tzobj->tzi.tz = tzi;
    2758           9 :                                                 tzobj->initialized = 1;
    2759             : 
    2760           9 :                                                 ret = php_date_initialize(*dateobj, Z_STRVAL_P(z_date), Z_STRLEN_P(z_date), NULL, &tmp_obj, 0);
    2761           9 :                                                 zval_ptr_dtor(&tmp_obj);
    2762           9 :                                                 return 1 == ret;
    2763             :                                         }
    2764             :                                 }
    2765             :                         }
    2766             :                 }
    2767             :         }
    2768           3 :         return 0;
    2769             : } /* }}} */
    2770             : 
    2771             : /* {{{ proto DateTime::__set_state()
    2772             : */
    2773           0 : PHP_METHOD(DateTime, __set_state)
    2774             : {
    2775             :         php_date_obj     *dateobj;
    2776             :         zval             *array;
    2777             :         HashTable        *myht;
    2778             : 
    2779           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    2780           0 :                 RETURN_FALSE;
    2781             :         }
    2782             : 
    2783           0 :         myht = Z_ARRVAL_P(array);
    2784             : 
    2785           0 :         php_date_instantiate(date_ce_date, return_value);
    2786           0 :         dateobj = Z_PHPDATE_P(return_value);
    2787           0 :         if (!php_date_initialize_from_hash(&dateobj, myht)) {
    2788           0 :                 php_error(E_ERROR, "Invalid serialization data for DateTime object");
    2789             :         }
    2790             : }
    2791             : /* }}} */
    2792             : 
    2793             : /* {{{ proto DateTimeImmutable::__set_state()
    2794             : */
    2795           0 : PHP_METHOD(DateTimeImmutable, __set_state)
    2796             : {
    2797             :         php_date_obj     *dateobj;
    2798             :         zval             *array;
    2799             :         HashTable        *myht;
    2800             : 
    2801           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    2802           0 :                 RETURN_FALSE;
    2803             :         }
    2804             : 
    2805           0 :         myht = Z_ARRVAL_P(array);
    2806             : 
    2807           0 :         php_date_instantiate(date_ce_immutable, return_value);
    2808           0 :         dateobj = Z_PHPDATE_P(return_value);
    2809           0 :         if (!php_date_initialize_from_hash(&dateobj, myht)) {
    2810           0 :                 php_error(E_ERROR, "Invalid serialization data for DateTimeImmutable object");
    2811             :         }
    2812             : }
    2813             : /* }}} */
    2814             : 
    2815             : /* {{{ proto DateTime::__wakeup()
    2816             : */
    2817          13 : PHP_METHOD(DateTime, __wakeup)
    2818             : {
    2819          13 :         zval             *object = getThis();
    2820             :         php_date_obj     *dateobj;
    2821             :         HashTable        *myht;
    2822             : 
    2823          13 :         dateobj = Z_PHPDATE_P(object);
    2824             : 
    2825          13 :         myht = Z_OBJPROP_P(object);
    2826             : 
    2827          13 :         if (!php_date_initialize_from_hash(&dateobj, myht)) {
    2828           6 :                 php_error(E_ERROR, "Invalid serialization data for DateTime object");
    2829             :         }
    2830           7 : }
    2831             : /* }}} */
    2832             : 
    2833             : /* Helper function used to add an associative array of warnings and errors to a zval */
    2834          88 : static void zval_from_error_container(zval *z, timelib_error_container *error) /* {{{ */
    2835             : {
    2836             :         int   i;
    2837             :         zval element;
    2838             : 
    2839          88 :         add_assoc_long(z, "warning_count", error->warning_count);
    2840          88 :         array_init(&element);
    2841         108 :         for (i = 0; i < error->warning_count; i++) {
    2842          20 :                 add_index_string(&element, error->warning_messages[i].position, error->warning_messages[i].message);
    2843             :         }
    2844          88 :         add_assoc_zval(z, "warnings", &element);
    2845             : 
    2846          88 :         add_assoc_long(z, "error_count", error->error_count);
    2847          88 :         array_init(&element);
    2848         144 :         for (i = 0; i < error->error_count; i++) {
    2849          56 :                 add_index_string(&element, error->error_messages[i].position, error->error_messages[i].message);
    2850             :         }
    2851          88 :         add_assoc_zval(z, "errors", &element);
    2852          88 : } /* }}} */
    2853             : 
    2854             : /* {{{ proto array date_get_last_errors()
    2855             :    Returns the warnings and errors found while parsing a date/time string.
    2856             : */
    2857          16 : PHP_FUNCTION(date_get_last_errors)
    2858             : {
    2859          16 :         if (DATEG(last_errors)) {
    2860          15 :                 array_init(return_value);
    2861          15 :                 zval_from_error_container(return_value, DATEG(last_errors));
    2862             :         } else {
    2863           1 :                 RETURN_FALSE;
    2864             :         }
    2865             : }
    2866             : /* }}} */
    2867             : 
    2868          73 : void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error) /* {{{ */
    2869             : {
    2870             :         zval element;
    2871             : 
    2872          73 :         array_init(return_value);
    2873             : #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
    2874             :         if (parsed_time->elem == -99999) {               \
    2875             :                 add_assoc_bool(return_value, #name, 0); \
    2876             :         } else {                                       \
    2877             :                 add_assoc_long(return_value, #name, parsed_time->elem); \
    2878             :         }
    2879          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year,      y);
    2880          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month,     m);
    2881          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day,       d);
    2882          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour,      h);
    2883          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute,    i);
    2884          73 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second,    s);
    2885             : 
    2886          73 :         if (parsed_time->f == -99999) {
    2887          55 :                 add_assoc_bool(return_value, "fraction", 0);
    2888             :         } else {
    2889          18 :                 add_assoc_double(return_value, "fraction", parsed_time->f);
    2890             :         }
    2891             : 
    2892          73 :         zval_from_error_container(return_value, error);
    2893             : 
    2894          73 :         timelib_error_container_dtor(error);
    2895             : 
    2896          73 :         add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
    2897             : 
    2898          73 :         if (parsed_time->is_localtime) {
    2899          19 :                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
    2900          19 :                 switch (parsed_time->zone_type) {
    2901             :                         case TIMELIB_ZONETYPE_OFFSET:
    2902           5 :                                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
    2903           5 :                                 add_assoc_bool(return_value, "is_dst", parsed_time->dst);
    2904           5 :                                 break;
    2905             :                         case TIMELIB_ZONETYPE_ID:
    2906           0 :                                 if (parsed_time->tz_abbr) {
    2907           0 :                                         add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr);
    2908             :                                 }
    2909           0 :                                 if (parsed_time->tz_info) {
    2910           0 :                                         add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name);
    2911             :                                 }
    2912           0 :                                 break;
    2913             :                         case TIMELIB_ZONETYPE_ABBR:
    2914           7 :                                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
    2915           7 :                                 add_assoc_bool(return_value, "is_dst", parsed_time->dst);
    2916           7 :                                 add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr);
    2917             :                                 break;
    2918             :                 }
    2919             :         }
    2920          73 :         if (parsed_time->have_relative) {
    2921           7 :                 array_init(&element);
    2922           7 :                 add_assoc_long(&element, "year",   parsed_time->relative.y);
    2923           7 :                 add_assoc_long(&element, "month",  parsed_time->relative.m);
    2924           7 :                 add_assoc_long(&element, "day",    parsed_time->relative.d);
    2925           7 :                 add_assoc_long(&element, "hour",   parsed_time->relative.h);
    2926           7 :                 add_assoc_long(&element, "minute", parsed_time->relative.i);
    2927           7 :                 add_assoc_long(&element, "second", parsed_time->relative.s);
    2928           7 :                 if (parsed_time->relative.have_weekday_relative) {
    2929           0 :                         add_assoc_long(&element, "weekday", parsed_time->relative.weekday);
    2930             :                 }
    2931           7 :                 if (parsed_time->relative.have_special_relative && (parsed_time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY)) {
    2932           0 :                         add_assoc_long(&element, "weekdays", parsed_time->relative.special.amount);
    2933             :                 }
    2934           7 :                 if (parsed_time->relative.first_last_day_of) {
    2935           2 :                         add_assoc_bool(&element, parsed_time->relative.first_last_day_of == TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH ? "first_day_of_month" : "last_day_of_month", 1);
    2936             :                 }
    2937           7 :                 add_assoc_zval(return_value, "relative", &element);
    2938             :         }
    2939          73 :         timelib_time_dtor(parsed_time);
    2940          73 : } /* }}} */
    2941             : 
    2942             : /* {{{ proto array date_parse(string date)
    2943             :    Returns associative array with detailed info about given date
    2944             : */
    2945          63 : PHP_FUNCTION(date_parse)
    2946             : {
    2947             :         char                           *date;
    2948             :         size_t                          date_len;
    2949             :         struct timelib_error_container *error;
    2950             :         timelib_time                   *parsed_time;
    2951             : 
    2952          63 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &date, &date_len) == FAILURE) {
    2953           9 :                 RETURN_FALSE;
    2954             :         }
    2955             : 
    2956          54 :         parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2957          54 :         php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
    2958             : }
    2959             : /* }}} */
    2960             : 
    2961             : /* {{{ proto array date_parse_from_format(string format, string date)
    2962             :    Returns associative array with detailed info about given date
    2963             : */
    2964          20 : PHP_FUNCTION(date_parse_from_format)
    2965             : {
    2966             :         char                           *date, *format;
    2967             :         size_t                          date_len, format_len;
    2968             :         struct timelib_error_container *error;
    2969             :         timelib_time                   *parsed_time;
    2970             : 
    2971          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &format, &format_len, &date, &date_len) == FAILURE) {
    2972           1 :                 RETURN_FALSE;
    2973             :         }
    2974             : 
    2975          19 :         parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2976          19 :         php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
    2977             : }
    2978             : /* }}} */
    2979             : 
    2980             : /* {{{ proto string date_format(DateTimeInterface object, string format)
    2981             :    Returns date formatted according to given format
    2982             : */
    2983        5132 : PHP_FUNCTION(date_format)
    2984             : {
    2985             :         zval         *object;
    2986             :         php_date_obj *dateobj;
    2987             :         char         *format;
    2988             :         size_t       format_len;
    2989             : 
    2990        5132 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_interface, &format, &format_len) == FAILURE) {
    2991          48 :                 RETURN_FALSE;
    2992             :         }
    2993        5084 :         dateobj = Z_PHPDATE_P(object);
    2994        5084 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    2995        5080 :         RETURN_STR(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime));
    2996             : }
    2997             : /* }}} */
    2998             : 
    2999         300 : static int php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{ */
    3000             : {
    3001             :         php_date_obj *dateobj;
    3002             :         timelib_time *tmp_time;
    3003         300 :         timelib_error_container *err = NULL;
    3004             : 
    3005         300 :         dateobj = Z_PHPDATE_P(object);
    3006             : 
    3007         300 :         if (!(dateobj->time)) {
    3008           0 :                 php_error_docref(NULL, E_WARNING, "The DateTime object has not been correctly initialized by its constructor");
    3009           0 :                 return 0;
    3010             :         }
    3011             : 
    3012         300 :         tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3013             : 
    3014             :         /* update last errors and warnings */
    3015         300 :         update_errors_warnings(err);
    3016         300 :         if (err && err->error_count) {
    3017             :                 /* spit out the first library error message, at least */
    3018         123 :                 php_error_docref(NULL, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
    3019         123 :                         err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
    3020          41 :                 timelib_time_dtor(tmp_time);
    3021          41 :                 return 0;
    3022             :         }
    3023             : 
    3024         259 :         memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
    3025         259 :         dateobj->time->have_relative = tmp_time->have_relative;
    3026         259 :         dateobj->time->sse_uptodate = 0;
    3027             : 
    3028         259 :         if (tmp_time->y != -99999) {
    3029           2 :                 dateobj->time->y = tmp_time->y;
    3030             :         }
    3031         259 :         if (tmp_time->m != -99999) {
    3032           7 :                 dateobj->time->m = tmp_time->m;
    3033             :         }
    3034         259 :         if (tmp_time->d != -99999) {
    3035           7 :                 dateobj->time->d = tmp_time->d;
    3036             :         }
    3037             : 
    3038         259 :         if (tmp_time->h != -99999) {
    3039         222 :                 dateobj->time->h = tmp_time->h;
    3040         222 :                 if (tmp_time->i != -99999) {
    3041         220 :                         dateobj->time->i = tmp_time->i;
    3042         220 :                         if (tmp_time->s != -99999) {
    3043         220 :                                 dateobj->time->s = tmp_time->s;
    3044             :                         } else {
    3045           0 :                                 dateobj->time->s = 0;
    3046             :                         }
    3047             :                 } else {
    3048           2 :                         dateobj->time->i = 0;
    3049           2 :                         dateobj->time->s = 0;
    3050             :                 }
    3051             :         }
    3052         259 :         timelib_time_dtor(tmp_time);
    3053             : 
    3054         259 :         timelib_update_ts(dateobj->time, NULL);
    3055         259 :         timelib_update_from_sse(dateobj->time);
    3056         259 :         dateobj->time->have_relative = 0;
    3057         259 :         memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
    3058             : 
    3059         259 :         return 1;
    3060             : } /* }}} */
    3061             : 
    3062             : /* {{{ proto DateTime date_modify(DateTime object, string modify)
    3063             :    Alters the timestamp.
    3064             : */
    3065         344 : PHP_FUNCTION(date_modify)
    3066             : {
    3067             :         zval         *object;
    3068             :         char         *modify;
    3069             :         size_t        modify_len;
    3070             : 
    3071         344 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
    3072          48 :                 RETURN_FALSE;
    3073             :         }
    3074             : 
    3075         296 :         if (!php_date_modify(object, modify, modify_len)) {
    3076          41 :                 RETURN_FALSE;
    3077             :         }
    3078             : 
    3079         255 :         Z_ADDREF_P(object);
    3080         255 :         ZVAL_COPY_VALUE(return_value, object);
    3081             : }
    3082             : /* }}} */
    3083             : 
    3084             : /* {{{ proto DateTimeImmutable::modify()
    3085             : */
    3086           4 : PHP_METHOD(DateTimeImmutable, modify)
    3087             : {
    3088             :         zval *object, new_object;
    3089             :         char *modify;
    3090             :         size_t   modify_len;
    3091             : 
    3092           4 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_immutable, &modify, &modify_len) == FAILURE) {
    3093           0 :                 RETURN_FALSE;
    3094             :         }
    3095             : 
    3096           4 :         date_clone_immutable(object, &new_object);
    3097           4 :         if (!php_date_modify(&new_object, modify, modify_len)) {
    3098           0 :                 RETURN_FALSE;
    3099             :         }
    3100             : 
    3101           4 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3102             : }
    3103             : /* }}} */
    3104             : 
    3105      167470 : static void php_date_add(zval *object, zval *interval, zval *return_value) /* {{{ */
    3106             : {
    3107             :         php_date_obj     *dateobj;
    3108             :         php_interval_obj *intobj;
    3109             :         timelib_time     *new_time;
    3110             : 
    3111      167470 :         dateobj = Z_PHPDATE_P(object);
    3112      167470 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3113      167470 :         intobj = Z_PHPINTERVAL_P(interval);
    3114      167470 :         DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
    3115             : 
    3116      167470 :         new_time = timelib_add(dateobj->time, intobj->diff);
    3117      167470 :         timelib_time_dtor(dateobj->time);
    3118      167470 :         dateobj->time = new_time;
    3119             : } /* }}} */
    3120             : 
    3121             : /* {{{ proto DateTime date_add(DateTime object, DateInterval interval)
    3122             :    Adds an interval to the current date in object.
    3123             : */
    3124      167470 : PHP_FUNCTION(date_add)
    3125             : {
    3126             :         zval *object, *interval;
    3127             : 
    3128      167470 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
    3129           1 :                 RETURN_FALSE;
    3130             :         }
    3131             : 
    3132      167469 :         php_date_add(object, interval, return_value);
    3133             : 
    3134      167469 :         Z_ADDREF_P(object);
    3135      167469 :         ZVAL_COPY_VALUE(return_value, object);
    3136             : }
    3137             : /* }}} */
    3138             : 
    3139             : /* {{{ proto DateTimeImmutable::add()
    3140             : */
    3141           1 : PHP_METHOD(DateTimeImmutable, add)
    3142             : {
    3143             :         zval *object, *interval, new_object;
    3144             : 
    3145           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
    3146           0 :                 RETURN_FALSE;
    3147             :         }
    3148             : 
    3149           1 :         date_clone_immutable(object, &new_object);
    3150           1 :         php_date_add(&new_object, interval, return_value);
    3151             : 
    3152           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3153             : }
    3154             : /* }}} */
    3155             : 
    3156        7509 : static void php_date_sub(zval *object, zval *interval, zval *return_value) /* {{{ */
    3157             : {
    3158             :         php_date_obj     *dateobj;
    3159             :         php_interval_obj *intobj;
    3160             :         timelib_time     *new_time;
    3161             : 
    3162        7509 :         dateobj = Z_PHPDATE_P(object);
    3163        7509 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3164        7509 :         intobj = Z_PHPINTERVAL_P(interval);
    3165        7509 :         DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
    3166             : 
    3167        7509 :         if (intobj->diff->have_special_relative) {
    3168           2 :                 php_error_docref(NULL, E_WARNING, "Only non-special relative time specifications are supported for subtraction");
    3169           2 :                 return;
    3170             :         }
    3171             : 
    3172        7507 :         new_time = timelib_sub(dateobj->time, intobj->diff);
    3173        7507 :         timelib_time_dtor(dateobj->time);
    3174        7507 :         dateobj->time = new_time;
    3175             : } /* }}} */
    3176             : 
    3177             : /* {{{ proto DateTime date_sub(DateTime object, DateInterval interval)
    3178             :    Subtracts an interval to the current date in object.
    3179             : */
    3180        7508 : PHP_FUNCTION(date_sub)
    3181             : {
    3182             :         zval *object, *interval;
    3183             : 
    3184        7508 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
    3185           0 :                 RETURN_FALSE;
    3186             :         }
    3187             : 
    3188        7508 :         php_date_sub(object, interval, return_value);
    3189             : 
    3190        7508 :         Z_ADDREF_P(object);
    3191        7508 :         ZVAL_COPY_VALUE(return_value, object);
    3192             : }
    3193             : /* }}} */
    3194             : 
    3195             : /* {{{ proto DateTimeImmutable::sub()
    3196             : */
    3197           1 : PHP_METHOD(DateTimeImmutable, sub)
    3198             : {
    3199             :         zval *object, *interval, new_object;
    3200             : 
    3201           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
    3202           0 :                 RETURN_FALSE;
    3203             :         }
    3204             : 
    3205           1 :         date_clone_immutable(object, &new_object);
    3206           1 :         php_date_sub(&new_object, interval, return_value);
    3207             : 
    3208           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3209             : }
    3210             : /* }}} */
    3211             : 
    3212         761 : static void set_timezone_from_timelib_time(php_timezone_obj *tzobj, timelib_time *t)
    3213             : {
    3214         761 :        tzobj->initialized = 1;
    3215         761 :        tzobj->type = t->zone_type;
    3216         761 :        switch (t->zone_type) {
    3217             :                case TIMELIB_ZONETYPE_ID:
    3218         722 :                        tzobj->tzi.tz = t->tz_info;
    3219         722 :                        break;
    3220             :                case TIMELIB_ZONETYPE_OFFSET:
    3221          18 :                        tzobj->tzi.utc_offset = t->z;
    3222          18 :                        break;
    3223             :                case TIMELIB_ZONETYPE_ABBR:
    3224          21 :                        tzobj->tzi.z.utc_offset = t->z;
    3225          21 :                        tzobj->tzi.z.dst = t->dst;
    3226          21 :                        tzobj->tzi.z.abbr = timelib_strdup(t->tz_abbr);
    3227             :                        break;
    3228             :        }
    3229         761 : }
    3230             : 
    3231             : 
    3232             : /* {{{ proto DateTimeZone date_timezone_get(DateTimeInterface object)
    3233             :    Return new DateTimeZone object relative to give DateTime
    3234             : */
    3235          82 : PHP_FUNCTION(date_timezone_get)
    3236             : {
    3237             :         zval             *object;
    3238             :         php_date_obj     *dateobj;
    3239             :         php_timezone_obj *tzobj;
    3240             : 
    3241          82 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3242          33 :                 RETURN_FALSE;
    3243             :         }
    3244          49 :         dateobj = Z_PHPDATE_P(object);
    3245          49 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3246          49 :         if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
    3247          49 :                 php_date_instantiate(date_ce_timezone, return_value);
    3248          49 :                 tzobj = Z_PHPTIMEZONE_P(return_value);
    3249          49 :                 set_timezone_from_timelib_time(tzobj, dateobj->time);
    3250             :         } else {
    3251           0 :                 RETURN_FALSE;
    3252             :         }
    3253             : }
    3254             : /* }}} */
    3255             : 
    3256         262 : static void php_date_timezone_set(zval *object, zval *timezone_object, zval *return_value) /* {{{ */
    3257             : {
    3258             :         php_date_obj     *dateobj;
    3259             :         php_timezone_obj *tzobj;
    3260             : 
    3261         262 :         dateobj = Z_PHPDATE_P(object);
    3262         262 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3263         262 :         tzobj = Z_PHPTIMEZONE_P(timezone_object);
    3264             : 
    3265         262 :         switch (tzobj->type) {
    3266             :                 case TIMELIB_ZONETYPE_OFFSET:
    3267           1 :                         timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset);
    3268           1 :                         break;
    3269             :                 case TIMELIB_ZONETYPE_ABBR:
    3270           3 :                         timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z);
    3271           3 :                         break;
    3272             :                 case TIMELIB_ZONETYPE_ID:
    3273         258 :                         timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
    3274             :                         break;
    3275             :         }
    3276         262 :         timelib_unixtime2local(dateobj->time, dateobj->time->sse);
    3277             : } /* }}} */
    3278             : 
    3279             : /* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object)
    3280             :    Sets the timezone for the DateTime object.
    3281             : */
    3282         352 : PHP_FUNCTION(date_timezone_set)
    3283             : {
    3284             :         zval *object;
    3285             :         zval *timezone_object;
    3286             : 
    3287         352 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
    3288          92 :                 RETURN_FALSE;
    3289             :         }
    3290             : 
    3291         260 :         php_date_timezone_set(object, timezone_object, return_value);
    3292             : 
    3293         260 :         Z_ADDREF_P(object);
    3294         260 :         ZVAL_COPY_VALUE(return_value, object);
    3295             : }
    3296             : /* }}} */
    3297             : 
    3298             : /* {{{ proto DateTimeImmutable::setTimezone()
    3299             : */
    3300           2 : PHP_METHOD(DateTimeImmutable, setTimezone)
    3301             : {
    3302             :         zval *object, new_object;
    3303             :         zval *timezone_object;
    3304             : 
    3305           2 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_immutable, &timezone_object, date_ce_timezone) == FAILURE) {
    3306           0 :                 RETURN_FALSE;
    3307             :         }
    3308             : 
    3309           2 :         date_clone_immutable(object, &new_object);
    3310           2 :         php_date_timezone_set(&new_object, timezone_object, return_value);
    3311             : 
    3312           2 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3313             : }
    3314             : /* }}} */
    3315             : 
    3316             : /* {{{ proto long date_offset_get(DateTimeInterface object)
    3317             :    Returns the DST offset.
    3318             : */
    3319          60 : PHP_FUNCTION(date_offset_get)
    3320             : {
    3321             :         zval                *object;
    3322             :         php_date_obj        *dateobj;
    3323             :         timelib_time_offset *offset;
    3324             : 
    3325          60 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3326          34 :                 RETURN_FALSE;
    3327             :         }
    3328          26 :         dateobj = Z_PHPDATE_P(object);
    3329          26 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3330          26 :         if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
    3331          26 :                 switch (dateobj->time->zone_type) {
    3332             :                         case TIMELIB_ZONETYPE_ID:
    3333           6 :                                 offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
    3334           6 :                                 RETVAL_LONG(offset->offset);
    3335           6 :                                 timelib_time_offset_dtor(offset);
    3336           6 :                                 break;
    3337             :                         case TIMELIB_ZONETYPE_OFFSET:
    3338          18 :                                 RETVAL_LONG(dateobj->time->z * -60);
    3339          18 :                                 break;
    3340             :                         case TIMELIB_ZONETYPE_ABBR:
    3341           2 :                                 RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
    3342             :                                 break;
    3343             :                 }
    3344          26 :                 return;
    3345             :         } else {
    3346           0 :                 RETURN_LONG(0);
    3347             :         }
    3348             : }
    3349             : /* }}} */
    3350             : 
    3351         133 : static void php_date_time_set(zval *object, zend_long h, zend_long i, zend_long s, zval *return_value) /* {{{ */
    3352             : {
    3353             :         php_date_obj *dateobj;
    3354             : 
    3355         133 :         dateobj = Z_PHPDATE_P(object);
    3356         133 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3357         133 :         dateobj->time->h = h;
    3358         133 :         dateobj->time->i = i;
    3359         133 :         dateobj->time->s = s;
    3360         133 :         timelib_update_ts(dateobj->time, NULL);
    3361             : } /* }}} */
    3362             : 
    3363             : /* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second])
    3364             :    Sets the time.
    3365             : */
    3366         248 : PHP_FUNCTION(date_time_set)
    3367             : {
    3368             :         zval *object;
    3369         248 :         zend_long  h, i, s = 0;
    3370             : 
    3371         248 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
    3372         116 :                 RETURN_FALSE;
    3373             :         }
    3374             : 
    3375         132 :         php_date_time_set(object, h, i, s, return_value);
    3376             : 
    3377         132 :         Z_ADDREF_P(object);
    3378         132 :         ZVAL_COPY_VALUE(return_value, object);
    3379             : }
    3380             : /* }}} */
    3381             : 
    3382             : /* {{{ proto DateTimeImmutable::setTime()
    3383             : */
    3384           1 : PHP_METHOD(DateTimeImmutable, setTime)
    3385             : {
    3386             :         zval *object, new_object;
    3387           1 :         zend_long  h, i, s = 0;
    3388             : 
    3389           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll|l", &object, date_ce_immutable, &h, &i, &s) == FAILURE) {
    3390           0 :                 RETURN_FALSE;
    3391             :         }
    3392             : 
    3393           1 :         date_clone_immutable(object, &new_object);
    3394           1 :         php_date_time_set(&new_object, h, i, s, return_value);
    3395             : 
    3396           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3397             : }
    3398             : /* }}} */
    3399             : 
    3400         118 : static void php_date_date_set(zval *object, zend_long y, zend_long m, zend_long d, zval *return_value) /* {{{ */
    3401             : {
    3402             :         php_date_obj *dateobj;
    3403             : 
    3404         118 :         dateobj = Z_PHPDATE_P(object);
    3405         118 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3406         118 :         dateobj->time->y = y;
    3407         118 :         dateobj->time->m = m;
    3408         118 :         dateobj->time->d = d;
    3409         118 :         timelib_update_ts(dateobj->time, NULL);
    3410             : } /* }}} */
    3411             : 
    3412             : /* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day)
    3413             :    Sets the date.
    3414             : */
    3415         234 : PHP_FUNCTION(date_date_set)
    3416             : {
    3417             :         zval *object;
    3418             :         zend_long  y, m, d;
    3419             : 
    3420         234 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
    3421         117 :                 RETURN_FALSE;
    3422             :         }
    3423             : 
    3424         117 :         php_date_date_set(object, y, m, d, return_value);
    3425             : 
    3426         117 :         Z_ADDREF_P(object);
    3427         117 :         ZVAL_COPY_VALUE(return_value, object);
    3428             : }
    3429             : /* }}} */
    3430             : 
    3431             : /* {{{ proto DateTimeImmutable::setDate()
    3432             : */
    3433           1 : PHP_METHOD(DateTimeImmutable, setDate)
    3434             : {
    3435             :         zval *object, new_object;
    3436             :         zend_long  y, m, d;
    3437             : 
    3438           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Olll", &object, date_ce_immutable, &y, &m, &d) == FAILURE) {
    3439           0 :                 RETURN_FALSE;
    3440             :         }
    3441             : 
    3442           1 :         date_clone_immutable(object, &new_object);
    3443           1 :         php_date_date_set(&new_object, y, m, d, return_value);
    3444             : 
    3445           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3446             : }
    3447             : /* }}} */
    3448             : 
    3449         104 : static void php_date_isodate_set(zval *object, zend_long y, zend_long w, zend_long d, zval *return_value) /* {{{ */
    3450             : {
    3451             :         php_date_obj *dateobj;
    3452             : 
    3453         104 :         dateobj = Z_PHPDATE_P(object);
    3454         104 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3455         104 :         dateobj->time->y = y;
    3456         104 :         dateobj->time->m = 1;
    3457         104 :         dateobj->time->d = 1;
    3458         104 :         memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
    3459         104 :         dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
    3460         104 :         dateobj->time->have_relative = 1;
    3461             : 
    3462         104 :         timelib_update_ts(dateobj->time, NULL);
    3463             : } /* }}} */
    3464             : 
    3465             : /* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day])
    3466             :    Sets the ISO date.
    3467             : */
    3468         220 : PHP_FUNCTION(date_isodate_set)
    3469             : {
    3470             :         zval *object;
    3471         220 :         zend_long  y, w, d = 1;
    3472             : 
    3473         220 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
    3474         117 :                 RETURN_FALSE;
    3475             :         }
    3476             : 
    3477         103 :         php_date_isodate_set(object, y, w, d, return_value);
    3478             : 
    3479         103 :         Z_ADDREF_P(object);
    3480         103 :         ZVAL_COPY_VALUE(return_value, object);
    3481             : }
    3482             : /* }}} */
    3483             : 
    3484             : /* {{{ proto DateTimeImmutable::setISODate()
    3485             : */
    3486           1 : PHP_METHOD(DateTimeImmutable, setISODate)
    3487             : {
    3488             :         zval *object, new_object;
    3489           1 :         zend_long  y, w, d = 1;
    3490             : 
    3491           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oll|l", &object, date_ce_immutable, &y, &w, &d) == FAILURE) {
    3492           0 :                 RETURN_FALSE;
    3493             :         }
    3494             : 
    3495           1 :         date_clone_immutable(object, &new_object);
    3496           1 :         php_date_isodate_set(&new_object, y, w, d, return_value);
    3497             : 
    3498           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3499             : }
    3500             : /* }}} */
    3501             : 
    3502           7 : static void php_date_timestamp_set(zval *object, zend_long timestamp, zval *return_value) /* {{{ */
    3503             : {
    3504             :         php_date_obj *dateobj;
    3505             : 
    3506           7 :         dateobj = Z_PHPDATE_P(object);
    3507           7 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3508           7 :         timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp);
    3509           7 :         timelib_update_ts(dateobj->time, NULL);
    3510             : } /* }}} */
    3511             : 
    3512             : /* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp)
    3513             :    Sets the date and time based on an Unix timestamp.
    3514             : */
    3515          11 : PHP_FUNCTION(date_timestamp_set)
    3516             : {
    3517             :         zval *object;
    3518             :         zend_long  timestamp;
    3519             : 
    3520          11 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &object, date_ce_date, &timestamp) == FAILURE) {
    3521           5 :                 RETURN_FALSE;
    3522             :         }
    3523             : 
    3524           6 :         php_date_timestamp_set(object, timestamp, return_value);
    3525             : 
    3526           6 :         Z_ADDREF_P(object);
    3527           6 :         ZVAL_COPY_VALUE(return_value, object);
    3528             : }
    3529             : /* }}} */
    3530             : 
    3531             : /* {{{ proto DateTimeImmutable::setTimestamp()
    3532             : */
    3533           1 : PHP_METHOD(DateTimeImmutable, setTimestamp)
    3534             : {
    3535             :         zval *object, new_object;
    3536             :         zend_long  timestamp;
    3537             : 
    3538           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &object, date_ce_immutable, &timestamp) == FAILURE) {
    3539           0 :                 RETURN_FALSE;
    3540             :         }
    3541             : 
    3542           1 :         date_clone_immutable(object, &new_object);
    3543           1 :         php_date_timestamp_set(&new_object, timestamp, return_value);
    3544             : 
    3545           1 :         ZVAL_COPY_VALUE(return_value, &new_object);
    3546             : }
    3547             : /* }}} */
    3548             : 
    3549             : /* {{{ proto long date_timestamp_get(DateTimeInterface object)
    3550             :    Gets the Unix timestamp.
    3551             : */
    3552          45 : PHP_FUNCTION(date_timestamp_get)
    3553             : {
    3554             :         zval         *object;
    3555             :         php_date_obj *dateobj;
    3556             :         zend_long          timestamp;
    3557             :         int           error;
    3558             : 
    3559          45 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3560           1 :                 RETURN_FALSE;
    3561             :         }
    3562          44 :         dateobj = Z_PHPDATE_P(object);
    3563          44 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3564          43 :         timelib_update_ts(dateobj->time, NULL);
    3565             : 
    3566          43 :         timestamp = timelib_date_to_int(dateobj->time, &error);
    3567          43 :         if (error) {
    3568           0 :                 RETURN_FALSE;
    3569             :         } else {
    3570          43 :                 RETVAL_LONG(timestamp);
    3571             :         }
    3572             : }
    3573             : /* }}} */
    3574             : 
    3575             : /* {{{ proto DateInterval date_diff(DateTime object [, bool absolute])
    3576             :    Returns the difference between two DateTime objects.
    3577             : */
    3578      173476 : PHP_FUNCTION(date_diff)
    3579             : {
    3580             :         zval         *object1, *object2;
    3581             :         php_date_obj *dateobj1, *dateobj2;
    3582             :         php_interval_obj *interval;
    3583      173476 :         zend_bool      absolute = 0;
    3584             : 
    3585      173476 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO|b", &object1, date_ce_interface, &object2, date_ce_interface, &absolute) == FAILURE) {
    3586           0 :                 RETURN_FALSE;
    3587             :         }
    3588      173476 :         dateobj1 = Z_PHPDATE_P(object1);
    3589      173476 :         dateobj2 = Z_PHPDATE_P(object2);
    3590      173476 :         DATE_CHECK_INITIALIZED(dateobj1->time, DateTimeInterface);
    3591      173476 :         DATE_CHECK_INITIALIZED(dateobj2->time, DateTimeInterface);
    3592      173476 :         timelib_update_ts(dateobj1->time, NULL);
    3593      173476 :         timelib_update_ts(dateobj2->time, NULL);
    3594             : 
    3595      173476 :         php_date_instantiate(date_ce_interval, return_value);
    3596      173476 :         interval = Z_PHPINTERVAL_P(return_value);
    3597      173476 :         interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
    3598      173476 :         if (absolute) {
    3599           4 :                 interval->diff->invert = 0;
    3600             :         }
    3601      173476 :         interval->initialized = 1;
    3602             : }
    3603             : /* }}} */
    3604             : 
    3605         757 : static int timezone_initialize(php_timezone_obj *tzobj, /*const*/ char *tz, size_t tz_len) /* {{{ */
    3606             : {
    3607         757 :         timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time));
    3608             :         int           dst, not_found;
    3609         757 :         char         *orig_tz = tz;
    3610             : 
    3611         757 :         if (strlen(tz) != tz_len) {
    3612           2 :                 php_error_docref(NULL, E_WARNING, "Timezone must not contain null bytes");
    3613           2 :                 return FAILURE;
    3614             :         }
    3615             : 
    3616         755 :         dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, &not_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3617         755 :         if (not_found) {
    3618          43 :                 php_error_docref(NULL, E_WARNING, "Unknown or bad timezone (%s)", orig_tz);
    3619          43 :                 efree(dummy_t);
    3620          43 :                 return FAILURE;
    3621             :         } else {
    3622         712 :                 set_timezone_from_timelib_time(tzobj, dummy_t);
    3623         712 :                 timelib_free(dummy_t->tz_abbr);
    3624         712 :                 efree(dummy_t);
    3625         712 :                 return SUCCESS;
    3626             :         }
    3627             : } /* }}} */
    3628             : 
    3629             : /* {{{ proto DateTimeZone timezone_open(string timezone)
    3630             :    Returns new DateTimeZone object
    3631             : */
    3632          49 : PHP_FUNCTION(timezone_open)
    3633             : {
    3634             :         char *tz;
    3635             :         size_t tz_len;
    3636             :         php_timezone_obj *tzobj;
    3637             : 
    3638          49 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &tz, &tz_len) == FAILURE) {
    3639           8 :                 RETURN_FALSE;
    3640             :         }
    3641          41 :         tzobj = Z_PHPTIMEZONE_P(php_date_instantiate(date_ce_timezone, return_value));
    3642          41 :         if (SUCCESS != timezone_initialize(tzobj, tz, tz_len)) {
    3643          21 :                 zval_ptr_dtor(return_value);
    3644          21 :                 RETURN_FALSE;
    3645             :         }
    3646             : }
    3647             : /* }}} */
    3648             : 
    3649             : /* {{{ proto DateTimeZone::__construct(string timezone)
    3650             :    Creates new DateTimeZone object.
    3651             : */
    3652         720 : PHP_METHOD(DateTimeZone, __construct)
    3653             : {
    3654             :         char *tz;
    3655             :         size_t tz_len;
    3656             :         php_timezone_obj *tzobj;
    3657             :         zend_error_handling error_handling;
    3658             : 
    3659         720 :         if (FAILURE == zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &tz, &tz_len)) {
    3660           7 :                 return;
    3661             :         }
    3662             : 
    3663         713 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling);
    3664         713 :         tzobj = Z_PHPTIMEZONE_P(getThis());
    3665         713 :         timezone_initialize(tzobj, tz, tz_len);
    3666         713 :         zend_restore_error_handling(&error_handling);
    3667             : }
    3668             : /* }}} */
    3669             : 
    3670           4 : static int php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht) /* {{{ */
    3671             : {
    3672             :         zval            *z_timezone;
    3673             :         zval            *z_timezone_type;
    3674             : 
    3675           4 :         if ((z_timezone_type = zend_hash_str_find(myht, "timezone_type", sizeof("timezone_type") - 1)) != NULL) {
    3676           4 :                 if ((z_timezone = zend_hash_str_find(myht, "timezone", sizeof("timezone") - 1)) != NULL) {
    3677           4 :                         if (Z_TYPE_P(z_timezone_type) != IS_LONG) {
    3678           1 :                                 return FAILURE;
    3679             :                         }
    3680           3 :                         if (Z_TYPE_P(z_timezone) != IS_STRING) {
    3681           0 :                                 return FAILURE;
    3682             :                         }
    3683           3 :                         if (SUCCESS == timezone_initialize(*tzobj, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone))) {
    3684           3 :                                 return SUCCESS;
    3685             :                         }
    3686             :                 }
    3687             :         }
    3688           0 :         return FAILURE;
    3689             : } /* }}} */
    3690             : 
    3691             : /* {{{ proto DateTimeZone::__set_state()
    3692             :  *  */
    3693           0 : PHP_METHOD(DateTimeZone, __set_state)
    3694             : {
    3695             :         php_timezone_obj *tzobj;
    3696             :         zval             *array;
    3697             :         HashTable        *myht;
    3698             : 
    3699           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    3700           0 :                 RETURN_FALSE;
    3701             :         }
    3702             : 
    3703           0 :         myht = Z_ARRVAL_P(array);
    3704             : 
    3705           0 :         php_date_instantiate(date_ce_timezone, return_value);
    3706           0 :         tzobj = Z_PHPTIMEZONE_P(return_value);
    3707           0 :         if(php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht) != SUCCESS) {
    3708           0 :                 php_error_docref(NULL, E_ERROR, "Timezone initialization failed");
    3709             :         }
    3710             : }
    3711             : /* }}} */
    3712             : 
    3713             : /* {{{ proto DateTimeZone::__wakeup()
    3714             :  *  */
    3715           4 : PHP_METHOD(DateTimeZone, __wakeup)
    3716             : {
    3717           4 :         zval             *object = getThis();
    3718             :         php_timezone_obj *tzobj;
    3719             :         HashTable        *myht;
    3720             : 
    3721           4 :         tzobj = Z_PHPTIMEZONE_P(object);
    3722             : 
    3723           4 :         myht = Z_OBJPROP_P(object);
    3724             : 
    3725           4 :         if(php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht) != SUCCESS) {
    3726           1 :                 php_error_docref(NULL, E_ERROR, "Timezone initialization failed");
    3727             :         }
    3728           3 : }
    3729             : /* }}} */
    3730             : 
    3731             : /* {{{ proto string timezone_name_get(DateTimeZone object)
    3732             :    Returns the name of the timezone.
    3733             : */
    3734          53 : PHP_FUNCTION(timezone_name_get)
    3735             : {
    3736             :         zval             *object;
    3737             :         php_timezone_obj *tzobj;
    3738             : 
    3739          53 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_timezone) == FAILURE) {
    3740           6 :                 RETURN_FALSE;
    3741             :         }
    3742          47 :         tzobj = Z_PHPTIMEZONE_P(object);
    3743          47 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3744             : 
    3745          46 :         switch (tzobj->type) {
    3746             :                 case TIMELIB_ZONETYPE_ID:
    3747          70 :                         RETURN_STRING(tzobj->tzi.tz->name);
    3748             :                         break;
    3749             :                 case TIMELIB_ZONETYPE_OFFSET: {
    3750           8 :                         zend_string *tmpstr = zend_string_alloc(sizeof("UTC+05:00")-1, 0);
    3751           8 :                         timelib_sll utc_offset = tzobj->tzi.utc_offset;
    3752             : 
    3753          16 :                         ZSTR_LEN(tmpstr) = snprintf(ZSTR_VAL(tmpstr), sizeof("+05:00"), "%c%02d:%02d",
    3754             :                                 utc_offset > 0 ? '-' : '+',
    3755           8 :                                 abs(utc_offset / 60),
    3756           8 :                                 abs((utc_offset % 60)));
    3757             : 
    3758           8 :                         RETURN_NEW_STR(tmpstr);
    3759             :                         }
    3760             :                         break;
    3761             :                 case TIMELIB_ZONETYPE_ABBR:
    3762           6 :                         RETURN_STRING(tzobj->tzi.z.abbr);
    3763             :                         break;
    3764             :         }
    3765             : }
    3766             : /* }}} */
    3767             : 
    3768             : /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
    3769             :    Returns the timezone name from abbrevation
    3770             : */
    3771         107 : PHP_FUNCTION(timezone_name_from_abbr)
    3772             : {
    3773             :         char    *abbr;
    3774             :         char    *tzid;
    3775             :         size_t      abbr_len;
    3776         107 :         zend_long     gmtoffset = -1;
    3777         107 :         zend_long     isdst = -1;
    3778             : 
    3779         107 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
    3780          35 :                 RETURN_FALSE;
    3781             :         }
    3782          72 :         tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
    3783             : 
    3784          72 :         if (tzid) {
    3785         136 :                 RETURN_STRING(tzid);
    3786             :         } else {
    3787           4 :                 RETURN_FALSE;
    3788             :         }
    3789             : }
    3790             : /* }}} */
    3791             : 
    3792             : /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTimeInterface datetime)
    3793             :    Returns the timezone offset.
    3794             : */
    3795          57 : PHP_FUNCTION(timezone_offset_get)
    3796             : {
    3797             :         zval                *object, *dateobject;
    3798             :         php_timezone_obj    *tzobj;
    3799             :         php_date_obj        *dateobj;
    3800             :         timelib_time_offset *offset;
    3801             : 
    3802          57 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_interface) == FAILURE) {
    3803          35 :                 RETURN_FALSE;
    3804             :         }
    3805          22 :         tzobj = Z_PHPTIMEZONE_P(object);
    3806          22 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3807          22 :         dateobj = Z_PHPDATE_P(dateobject);
    3808          22 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTimeInterface);
    3809             : 
    3810          22 :         switch (tzobj->type) {
    3811             :                 case TIMELIB_ZONETYPE_ID:
    3812          13 :                         offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
    3813          13 :                         RETVAL_LONG(offset->offset);
    3814          13 :                         timelib_time_offset_dtor(offset);
    3815          13 :                         break;
    3816             :                 case TIMELIB_ZONETYPE_OFFSET:
    3817           6 :                         RETURN_LONG(tzobj->tzi.utc_offset * -60);
    3818             :                         break;
    3819             :                 case TIMELIB_ZONETYPE_ABBR:
    3820           3 :                         RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
    3821             :                         break;
    3822             :         }
    3823             : }
    3824             : /* }}} */
    3825             : 
    3826             : /* {{{ proto array timezone_transitions_get(DateTimeZone object [, long timestamp_begin [, long timestamp_end ]])
    3827             :    Returns numerically indexed array containing associative array for all transitions in the specified range for the timezone.
    3828             : */
    3829          94 : PHP_FUNCTION(timezone_transitions_get)
    3830             : {
    3831             :         zval                *object, element;
    3832             :         php_timezone_obj    *tzobj;
    3833          94 :         unsigned int         i, begin = 0, found;
    3834          94 :         zend_long            timestamp_begin = ZEND_LONG_MIN, timestamp_end = ZEND_LONG_MAX;
    3835             : 
    3836          94 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
    3837          60 :                 RETURN_FALSE;
    3838             :         }
    3839          34 :         tzobj = Z_PHPTIMEZONE_P(object);
    3840          34 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3841          34 :         if (tzobj->type != TIMELIB_ZONETYPE_ID) {
    3842           0 :                 RETURN_FALSE;
    3843             :         }
    3844             : 
    3845             : #define add_nominal() \
    3846             :                 array_init(&element); \
    3847             :                 add_assoc_long(&element, "ts",     timestamp_begin); \
    3848             :                 add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0)); \
    3849             :                 add_assoc_long(&element, "offset", tzobj->tzi.tz->type[0].offset); \
    3850             :                 add_assoc_bool(&element, "isdst",  tzobj->tzi.tz->type[0].isdst); \
    3851             :                 add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx]); \
    3852             :                 add_next_index_zval(return_value, &element);
    3853             : 
    3854             : #define add(i,ts) \
    3855             :                 array_init(&element); \
    3856             :                 add_assoc_long(&element, "ts",     ts); \
    3857             :                 add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0)); \
    3858             :                 add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
    3859             :                 add_assoc_bool(&element, "isdst",  tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
    3860             :                 add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
    3861             :                 add_next_index_zval(return_value, &element);
    3862             : 
    3863             : #define add_last() add(tzobj->tzi.tz->bit32.timecnt - 1, timestamp_begin)
    3864             : 
    3865          34 :         array_init(return_value);
    3866             : 
    3867          34 :         if (timestamp_begin == ZEND_LONG_MIN) {
    3868           2 :                 add_nominal();
    3869           2 :                 begin = 0;
    3870           2 :                 found = 1;
    3871             :         } else {
    3872          32 :                 begin = 0;
    3873          32 :                 found = 0;
    3874          32 :                 if (tzobj->tzi.tz->bit32.timecnt > 0) {
    3875             :                         do {
    3876        3591 :                                 if (tzobj->tzi.tz->trans[begin] > timestamp_begin) {
    3877          32 :                                         if (begin > 0) {
    3878          32 :                                                 add(begin - 1, timestamp_begin);
    3879             :                                         } else {
    3880           0 :                                                 add_nominal();
    3881             :                                         }
    3882          32 :                                         found = 1;
    3883          32 :                                         break;
    3884             :                                 }
    3885        3559 :                                 begin++;
    3886        3559 :                         } while (begin < tzobj->tzi.tz->bit32.timecnt);
    3887             :                 }
    3888             :         }
    3889             : 
    3890          34 :         if (!found) {
    3891           0 :                 if (tzobj->tzi.tz->bit32.timecnt > 0) {
    3892           0 :                         add_last();
    3893             :                 } else {
    3894           0 :                         add_nominal();
    3895             :                 }
    3896             :         } else {
    3897        4737 :                 for (i = begin; i < tzobj->tzi.tz->bit32.timecnt; ++i) {
    3898        4703 :                         if (tzobj->tzi.tz->trans[i] < timestamp_end) {
    3899         625 :                                 add(i, tzobj->tzi.tz->trans[i]);
    3900             :                         }
    3901             :                 }
    3902             :         }
    3903             : }
    3904             : /* }}} */
    3905             : 
    3906             : /* {{{ proto array timezone_location_get()
    3907             :    Returns location information for a timezone, including country code, latitude/longitude and comments
    3908             : */
    3909         351 : PHP_FUNCTION(timezone_location_get)
    3910             : {
    3911             :         zval                *object;
    3912             :         php_timezone_obj    *tzobj;
    3913             : 
    3914         351 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &object, date_ce_timezone) == FAILURE) {
    3915           0 :                 RETURN_FALSE;
    3916             :         }
    3917         351 :         tzobj = Z_PHPTIMEZONE_P(object);
    3918         351 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3919         350 :         if (tzobj->type != TIMELIB_ZONETYPE_ID) {
    3920           0 :                 RETURN_FALSE;
    3921             :         }
    3922             : 
    3923         350 :         array_init(return_value);
    3924         350 :         add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code);
    3925         350 :         add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
    3926         350 :         add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
    3927         350 :         add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments);
    3928             : }
    3929             : /* }}} */
    3930             : 
    3931      175602 : static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, size_t format_length) /* {{{ */
    3932             : {
    3933      175602 :         timelib_time     *b = NULL, *e = NULL;
    3934      175602 :         timelib_rel_time *p = NULL;
    3935      175602 :         int               r = 0;
    3936      175602 :         int               retval = 0;
    3937             :         struct timelib_error_container *errors;
    3938             : 
    3939      175602 :         timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
    3940             : 
    3941      175602 :         if (errors->error_count > 0) {
    3942           2 :                 php_error_docref(NULL, E_WARNING, "Unknown or bad format (%s)", format);
    3943           2 :                 retval = FAILURE;
    3944             :         } else {
    3945      175600 :                 if(p) {
    3946      175595 :                         *rt = p;
    3947      175595 :                         retval = SUCCESS;
    3948             :                 } else {
    3949           8 :                         if(b && e) {
    3950           3 :                                 timelib_update_ts(b, NULL);
    3951           3 :                                 timelib_update_ts(e, NULL);
    3952           3 :                                 *rt = timelib_diff(b, e);
    3953           3 :                                 retval = SUCCESS;
    3954             :                         } else {
    3955           2 :                                 php_error_docref(NULL, E_WARNING, "Failed to parse interval (%s)", format);
    3956           2 :                                 retval = FAILURE;
    3957             :                         }
    3958             :                 }
    3959             :         }
    3960      175602 :         timelib_error_container_dtor(errors);
    3961      175602 :         timelib_free(b);
    3962      175602 :         timelib_free(e);
    3963      175602 :         return retval;
    3964             : } /* }}} */
    3965             : 
    3966             : /* {{{ date_interval_read_property */
    3967          44 : zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv)
    3968             : {
    3969             :         php_interval_obj *obj;
    3970             :         zval *retval;
    3971             :         zval tmp_member;
    3972          44 :         timelib_sll value = -1;
    3973             : 
    3974          44 :         if (Z_TYPE_P(member) != IS_STRING) {
    3975           0 :                 tmp_member = *member;
    3976             :                 zval_copy_ctor(&tmp_member);
    3977           0 :                 convert_to_string(&tmp_member);
    3978           0 :                 member = &tmp_member;
    3979           0 :                 cache_slot = NULL;
    3980             :         }
    3981             : 
    3982          44 :         obj = Z_PHPINTERVAL_P(object);
    3983             : 
    3984          44 :         if (!obj->initialized) {
    3985           3 :                 retval = (zend_get_std_object_handlers())->read_property(object, member, type, cache_slot, rv);
    3986           3 :                 if (member == &tmp_member) {
    3987             :                         zval_dtor(member);
    3988             :                 }
    3989           3 :                 return retval;
    3990             :         }
    3991             : 
    3992             : #define GET_VALUE_FROM_STRUCT(n,m)            \
    3993             :         if (strcmp(Z_STRVAL_P(member), m) == 0) { \
    3994             :                 value = obj->diff->n;                 \
    3995             :                 break;                                                            \
    3996             :         }
    3997             :         do {
    3998          41 :                 GET_VALUE_FROM_STRUCT(y, "y");
    3999          35 :                 GET_VALUE_FROM_STRUCT(m, "m");
    4000          30 :                 GET_VALUE_FROM_STRUCT(d, "d");
    4001          22 :                 GET_VALUE_FROM_STRUCT(h, "h");
    4002          18 :                 GET_VALUE_FROM_STRUCT(i, "i");
    4003          14 :                 GET_VALUE_FROM_STRUCT(s, "s");
    4004          10 :                 GET_VALUE_FROM_STRUCT(invert, "invert");
    4005           9 :                 GET_VALUE_FROM_STRUCT(days, "days");
    4006             :                 /* didn't find any */
    4007           4 :                 retval = (zend_get_std_object_handlers())->read_property(object, member, type, cache_slot, rv);
    4008             : 
    4009           4 :                 if (member == &tmp_member) {
    4010             :                         zval_dtor(member);
    4011             :                 }
    4012             : 
    4013           4 :                 return retval;
    4014             :         } while(0);
    4015             : 
    4016          37 :         retval = rv;
    4017             : 
    4018          37 :         if (value != -99999) {
    4019          36 :                 ZVAL_LONG(retval, value);
    4020             :         } else {
    4021           1 :                 ZVAL_FALSE(retval);
    4022             :         }
    4023             : 
    4024          37 :         if (member == &tmp_member) {
    4025             :                 zval_dtor(member);
    4026             :         }
    4027             : 
    4028          37 :         return retval;
    4029             : }
    4030             : /* }}} */
    4031             : 
    4032             : /* {{{ date_interval_write_property */
    4033         536 : void date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot)
    4034             : {
    4035             :         php_interval_obj *obj;
    4036             :         zval tmp_member;
    4037             : 
    4038         536 :         if (Z_TYPE_P(member) != IS_STRING) {
    4039           0 :                 tmp_member = *member;
    4040             :                 zval_copy_ctor(&tmp_member);
    4041           0 :                 convert_to_string(&tmp_member);
    4042           0 :                 member = &tmp_member;
    4043           0 :                 cache_slot = NULL;
    4044             :         }
    4045             : 
    4046         536 :         obj = Z_PHPINTERVAL_P(object);
    4047             : 
    4048         536 :         if (!obj->initialized) {
    4049           1 :                 (zend_get_std_object_handlers())->write_property(object, member, value, cache_slot);
    4050           1 :                 if (member == &tmp_member) {
    4051             :                         zval_dtor(member);
    4052             :                 }
    4053           1 :                 return;
    4054             :         }
    4055             : 
    4056             : #define SET_VALUE_FROM_STRUCT(n,m)            \
    4057             :         if (strcmp(Z_STRVAL_P(member), m) == 0) { \
    4058             :                 obj->diff->n = zval_get_long(value); \
    4059             :                 break;                                                            \
    4060             :         }
    4061             : 
    4062             :         do {
    4063         535 :                 SET_VALUE_FROM_STRUCT(y, "y");
    4064         535 :                 SET_VALUE_FROM_STRUCT(m, "m");
    4065         536 :                 SET_VALUE_FROM_STRUCT(d, "d");
    4066         534 :                 SET_VALUE_FROM_STRUCT(h, "h");
    4067         534 :                 SET_VALUE_FROM_STRUCT(i, "i");
    4068         534 :                 SET_VALUE_FROM_STRUCT(s, "s");
    4069        1066 :                 SET_VALUE_FROM_STRUCT(invert, "invert");
    4070             :                 /* didn't find any */
    4071           2 :                 (zend_get_std_object_handlers())->write_property(object, member, value, cache_slot);
    4072             :         } while(0);
    4073             : 
    4074         535 :         if (member == &tmp_member) {
    4075             :                 zval_dtor(member);
    4076             :         }
    4077             : }
    4078             : /* }}} */
    4079             : 
    4080             : 
    4081             : /* {{{ proto DateInterval::__construct([string interval_spec])
    4082             :    Creates new DateInterval object.
    4083             : */
    4084      175602 : PHP_METHOD(DateInterval, __construct)
    4085             : {
    4086      175602 :         char *interval_string = NULL;
    4087             :         size_t   interval_string_length;
    4088             :         php_interval_obj *diobj;
    4089             :         timelib_rel_time *reltime;
    4090             :         zend_error_handling error_handling;
    4091             : 
    4092      175602 :         if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &interval_string, &interval_string_length) == FAILURE) {
    4093           0 :                 return;
    4094             :         }
    4095             : 
    4096      175602 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling);
    4097      175602 :         if (date_interval_initialize(&reltime, interval_string, interval_string_length) == SUCCESS) {
    4098      175598 :                 diobj = Z_PHPINTERVAL_P(getThis());
    4099      175598 :                 diobj->diff = reltime;
    4100      175598 :                 diobj->initialized = 1;
    4101             :         }
    4102      175602 :         zend_restore_error_handling(&error_handling);
    4103             : }
    4104             : /* }}} */
    4105             : 
    4106             : 
    4107           8 : static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht) /* {{{ */
    4108             : {
    4109           8 :         (*intobj)->diff = timelib_rel_time_ctor();
    4110             : 
    4111             : #define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \
    4112             :         do { \
    4113             :                 zval *z_arg = zend_hash_str_find(myht, element, sizeof(element) - 1); \
    4114             :                 if (z_arg) { \
    4115             :                         (*intobj)->diff->member = (itype)zval_get_long(z_arg); \
    4116             :                 } else { \
    4117             :                         (*intobj)->diff->member = (itype)def; \
    4118             :                 } \
    4119             :         } while (0);
    4120             : 
    4121             : #define PHP_DATE_INTERVAL_READ_PROPERTY_I64(element, member) \
    4122             :         do { \
    4123             :                 zval *z_arg = zend_hash_str_find(myht, element, sizeof(element) - 1); \
    4124             :                 if (z_arg) { \
    4125             :                         zend_string *str = zval_get_string(z_arg); \
    4126             :                         DATE_A64I((*intobj)->diff->member, ZSTR_VAL(str)); \
    4127             :                         zend_string_release(str); \
    4128             :                 } else { \
    4129             :                         (*intobj)->diff->member = -1LL; \
    4130             :                 } \
    4131             :         } while (0);
    4132             : 
    4133          15 :         PHP_DATE_INTERVAL_READ_PROPERTY("y", y, timelib_sll, -1)
    4134          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("m", m, timelib_sll, -1)
    4135          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("d", d, timelib_sll, -1)
    4136          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("h", h, timelib_sll, -1)
    4137          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1)
    4138          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1)
    4139          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1)
    4140          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("weekday_behavior", weekday_behavior, int, -1)
    4141          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("first_last_day_of", first_last_day_of, int, -1)
    4142          14 :         PHP_DATE_INTERVAL_READ_PROPERTY("invert", invert, int, 0);
    4143          16 :         PHP_DATE_INTERVAL_READ_PROPERTY_I64("days", days);
    4144          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("special_type", special.type, unsigned int, 0);
    4145          16 :         PHP_DATE_INTERVAL_READ_PROPERTY_I64("special_amount", special.amount);
    4146          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0);
    4147          13 :         PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0);
    4148           8 :         (*intobj)->initialized = 1;
    4149             : 
    4150           8 :         return 0;
    4151             : } /* }}} */
    4152             : 
    4153             : /* {{{ proto DateInterval::__set_state()
    4154             : */
    4155           1 : PHP_METHOD(DateInterval, __set_state)
    4156             : {
    4157             :         php_interval_obj *intobj;
    4158             :         zval             *array;
    4159             :         HashTable        *myht;
    4160             : 
    4161           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    4162           0 :                 RETURN_FALSE;
    4163             :         }
    4164             : 
    4165           1 :         myht = Z_ARRVAL_P(array);
    4166             : 
    4167           1 :         php_date_instantiate(date_ce_interval, return_value);
    4168           1 :         intobj = Z_PHPINTERVAL_P(return_value);
    4169           1 :         php_date_interval_initialize_from_hash(&return_value, &intobj, myht);
    4170             : }
    4171             : /* }}} */
    4172             : 
    4173             : /* {{{ proto DateInterval::__wakeup()
    4174             : */
    4175           7 : PHP_METHOD(DateInterval, __wakeup)
    4176             : {
    4177           7 :         zval             *object = getThis();
    4178             :         php_interval_obj *intobj;
    4179             :         HashTable        *myht;
    4180             : 
    4181           7 :         intobj = Z_PHPINTERVAL_P(object);
    4182             : 
    4183           7 :         myht = Z_OBJPROP_P(object);
    4184             : 
    4185           7 :         php_date_interval_initialize_from_hash(&return_value, &intobj, myht);
    4186           7 : }
    4187             : /* }}} */
    4188             : 
    4189             : /* {{{ proto DateInterval date_interval_create_from_date_string(string time)
    4190             :    Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string
    4191             : */
    4192          16 : PHP_FUNCTION(date_interval_create_from_date_string)
    4193             : {
    4194          16 :         char           *time_str = NULL;
    4195          16 :         size_t          time_str_len = 0;
    4196             :         timelib_time   *time;
    4197          16 :         timelib_error_container *err = NULL;
    4198             :         php_interval_obj *diobj;
    4199             : 
    4200          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &time_str, &time_str_len) == FAILURE) {
    4201           2 :                 RETURN_FALSE;
    4202             :         }
    4203             : 
    4204          14 :         php_date_instantiate(date_ce_interval, return_value);
    4205             : 
    4206          14 :         time = timelib_strtotime(time_str, time_str_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    4207          14 :         diobj = Z_PHPINTERVAL_P(return_value);
    4208          14 :         diobj->diff = timelib_rel_time_clone(&time->relative);
    4209          14 :         diobj->initialized = 1;
    4210          14 :         timelib_time_dtor(time);
    4211          14 :         timelib_error_container_dtor(err);
    4212             : }
    4213             : /* }}} */
    4214             : 
    4215             : /* {{{ date_interval_format -  */
    4216      173489 : static zend_string *date_interval_format(char *format, size_t format_len, timelib_rel_time *t)
    4217             : {
    4218      173489 :         smart_str            string = {0};
    4219      173489 :         int                  i, length, have_format_spec = 0;
    4220             :         char                 buffer[33];
    4221             : 
    4222      173489 :         if (!format_len) {
    4223           0 :                 return ZSTR_EMPTY_ALLOC();
    4224             :         }
    4225             : 
    4226     1909458 :         for (i = 0; i < format_len; i++) {
    4227     1735969 :                 if (have_format_spec) {
    4228      520999 :                         switch (format[i]) {
    4229           1 :                                 case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
    4230      173110 :                                 case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
    4231             : 
    4232           1 :                                 case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
    4233      173110 :                                 case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
    4234             : 
    4235           1 :                                 case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
    4236      173153 :                                 case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
    4237             : 
    4238           1 :                                 case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
    4239         358 :                                 case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
    4240             : 
    4241           1 :                                 case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
    4242         318 :                                 case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
    4243             : 
    4244           1 :                                 case 'S': length = slprintf(buffer, 32, "%02" ZEND_LONG_FMT_SPEC, (zend_long) t->s); break;
    4245         317 :                                 case 's': length = slprintf(buffer, 32, ZEND_LONG_FMT, (zend_long) t->s); break;
    4246             : 
    4247             :                                 case 'a': {
    4248         311 :                                         if ((int) t->days != -99999) {
    4249         309 :                                                 length = slprintf(buffer, 32, "%d", (int) t->days);
    4250             :                                         } else {
    4251           2 :                                                 length = slprintf(buffer, 32, "(unknown)");
    4252             :                                         }
    4253         311 :                                 } break;
    4254           2 :                                 case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
    4255         311 :                                 case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
    4256             : 
    4257           1 :                                 case '%': length = slprintf(buffer, 32, "%%"); break;
    4258           2 :                                 default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
    4259             :                         }
    4260      520999 :                         smart_str_appendl(&string, buffer, length);
    4261      520999 :                         have_format_spec = 0;
    4262             :                 } else {
    4263     1214970 :                         if (format[i] == '%') {
    4264      520999 :                                 have_format_spec = 1;
    4265             :                         } else {
    4266      693971 :                                 smart_str_appendc(&string, format[i]);
    4267             :                         }
    4268             :                 }
    4269             :         }
    4270             : 
    4271             :         smart_str_0(&string);
    4272             : 
    4273      173489 :         return string.s;
    4274             : }
    4275             : /* }}} */
    4276             : 
    4277             : /* {{{ proto string date_interval_format(DateInterval object, string format)
    4278             :    Formats the interval.
    4279             : */
    4280      173489 : PHP_FUNCTION(date_interval_format)
    4281             : {
    4282             :         zval             *object;
    4283             :         php_interval_obj *diobj;
    4284             :         char             *format;
    4285             :         size_t            format_len;
    4286             : 
    4287      173489 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
    4288           0 :                 RETURN_FALSE;
    4289             :         }
    4290      173489 :         diobj = Z_PHPINTERVAL_P(object);
    4291      173489 :         DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
    4292             : 
    4293      173489 :         RETURN_STR(date_interval_format(format, format_len, diobj->diff));
    4294             : }
    4295             : /* }}} */
    4296             : 
    4297           3 : static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, zend_long *recurrences, /*const*/ char *format, size_t format_length) /* {{{ */
    4298             : {
    4299           3 :         timelib_time     *b = NULL, *e = NULL;
    4300           3 :         timelib_rel_time *p = NULL;
    4301           3 :         int               r = 0;
    4302           3 :         int               retval = 0;
    4303             :         struct timelib_error_container *errors;
    4304             : 
    4305           3 :         timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
    4306             : 
    4307           3 :         if (errors->error_count > 0) {
    4308           2 :                 php_error_docref(NULL, E_WARNING, "Unknown or bad format (%s)", format);
    4309           2 :                 retval = FAILURE;
    4310             :         } else {
    4311           1 :                 *st = b;
    4312           1 :                 *et = e;
    4313           1 :                 *d  = p;
    4314           1 :                 *recurrences = r;
    4315           1 :                 retval = SUCCESS;
    4316             :         }
    4317           3 :         timelib_error_container_dtor(errors);
    4318           3 :         return retval;
    4319             : } /* }}} */
    4320             : 
    4321             : /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end)
    4322             :    Creates new DatePeriod object.
    4323             : */
    4324          15 : PHP_METHOD(DatePeriod, __construct)
    4325             : {
    4326             :         php_period_obj   *dpobj;
    4327             :         php_date_obj     *dateobj;
    4328             :         php_interval_obj *intobj;
    4329          15 :         zval *start, *end = NULL, *interval;
    4330          15 :         zend_long  recurrences = 0, options = 0;
    4331          15 :         char *isostr = NULL;
    4332          15 :         size_t   isostr_len = 0;
    4333             :         timelib_time *clone;
    4334             :         zend_error_handling error_handling;
    4335             : 
    4336          15 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling);
    4337          15 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
    4338           9 :                 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) {
    4339           4 :                         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s|l", &isostr, &isostr_len, &options) == FAILURE) {
    4340           1 :                                 php_error_docref(NULL, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
    4341           1 :                                 zend_restore_error_handling(&error_handling);
    4342           1 :                                 return;
    4343             :                         }
    4344             :                 }
    4345             :         }
    4346             : 
    4347          14 :         dpobj = Z_PHPPERIOD_P(getThis());
    4348          14 :         dpobj->current = NULL;
    4349             : 
    4350          14 :         if (isostr) {
    4351           3 :                 date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len);
    4352           3 :                 if (dpobj->start == NULL) {
    4353           2 :                         php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
    4354             :                 }
    4355           3 :                 if (dpobj->interval == NULL) {
    4356           2 :                         php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
    4357             :                 }
    4358           3 :                 if (dpobj->end == NULL && recurrences == 0) {
    4359           2 :                         php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
    4360             :                 }
    4361             : 
    4362           3 :                 if (dpobj->start) {
    4363           1 :                         timelib_update_ts(dpobj->start, NULL);
    4364             :                 }
    4365           3 :                 if (dpobj->end) {
    4366           0 :                         timelib_update_ts(dpobj->end, NULL);
    4367             :                 }
    4368           3 :                 dpobj->start_ce = date_ce_date;
    4369             :         } else {
    4370             :                 /* init */
    4371          11 :                 intobj  = Z_PHPINTERVAL_P(interval);
    4372             : 
    4373             :                 /* start date */
    4374          11 :                 dateobj = Z_PHPDATE_P(start);
    4375          11 :                 clone = timelib_time_ctor();
    4376          11 :                 memcpy(clone, dateobj->time, sizeof(timelib_time));
    4377          11 :                 if (dateobj->time->tz_abbr) {
    4378          11 :                         clone->tz_abbr = timelib_strdup(dateobj->time->tz_abbr);
    4379             :                 }
    4380          11 :                 if (dateobj->time->tz_info) {
    4381          11 :                         clone->tz_info = dateobj->time->tz_info;
    4382             :                 }
    4383          11 :                 dpobj->start = clone;
    4384          11 :                 dpobj->start_ce = Z_OBJCE_P(start);
    4385             : 
    4386             :                 /* interval */
    4387          11 :                 dpobj->interval = timelib_rel_time_clone(intobj->diff);
    4388             : 
    4389             :                 /* end date */
    4390          11 :                 if (end) {
    4391           5 :                         dateobj = Z_PHPDATE_P(end);
    4392           5 :                         clone = timelib_time_clone(dateobj->time);
    4393           5 :                         dpobj->end = clone;
    4394             :                 }
    4395             :         }
    4396             : 
    4397             :         /* options */
    4398          14 :         dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
    4399             : 
    4400             :         /* recurrrences */
    4401          14 :         dpobj->recurrences = recurrences + dpobj->include_start_date;
    4402             : 
    4403          14 :         dpobj->initialized = 1;
    4404             : 
    4405          14 :         zend_restore_error_handling(&error_handling);
    4406             : }
    4407             : /* }}} */
    4408             : 
    4409             : /* {{{ proto DatePeriod::getStartDate()
    4410             :    Get start date.
    4411             : */
    4412           2 : PHP_METHOD(DatePeriod, getStartDate)
    4413             : {
    4414             :         php_period_obj   *dpobj;
    4415             :         php_date_obj     *dateobj;
    4416             : 
    4417           2 :         if (zend_parse_parameters_none() == FAILURE) {
    4418           0 :                 return;
    4419             :         }
    4420             : 
    4421           2 :         dpobj = Z_PHPPERIOD_P(getThis());
    4422             : 
    4423           2 :         php_date_instantiate(dpobj->start_ce, return_value);
    4424           2 :         dateobj = Z_PHPDATE_P(return_value);
    4425           2 :         dateobj->time = timelib_time_ctor();
    4426           2 :         *dateobj->time = *dpobj->start;
    4427           2 :         if (dpobj->start->tz_abbr) {
    4428           2 :                 dateobj->time->tz_abbr = timelib_strdup(dpobj->start->tz_abbr);
    4429             :         }
    4430           2 :         if (dpobj->start->tz_info) {
    4431           2 :                 dateobj->time->tz_info = dpobj->start->tz_info;
    4432             :         }
    4433             : }
    4434             : /* }}} */
    4435             : 
    4436             : /* {{{ proto DatePeriod::getEndDate()
    4437             :    Get end date.
    4438             : */
    4439           2 : PHP_METHOD(DatePeriod, getEndDate)
    4440             : {
    4441             :         php_period_obj   *dpobj;
    4442             :         php_date_obj     *dateobj;
    4443             : 
    4444           2 :         if (zend_parse_parameters_none() == FAILURE) {
    4445           0 :                 return;
    4446             :         }
    4447             : 
    4448           2 :         dpobj = Z_PHPPERIOD_P(getThis());
    4449             : 
    4450           2 :         php_date_instantiate(dpobj->start_ce, return_value);
    4451           2 :         dateobj = Z_PHPDATE_P(return_value);
    4452           2 :         dateobj->time = timelib_time_ctor();
    4453           2 :         *dateobj->time = *dpobj->end;
    4454           2 :         if (dpobj->end->tz_abbr) {
    4455           2 :                 dateobj->time->tz_abbr = timelib_strdup(dpobj->end->tz_abbr);
    4456             :         }
    4457           2 :         if (dpobj->end->tz_info) {
    4458           2 :                 dateobj->time->tz_info = dpobj->end->tz_info;
    4459             :         }
    4460             : }
    4461             : /* }}} */
    4462             : 
    4463             : /* {{{ proto DatePeriod::getDateInterval()
    4464             :    Get date interval.
    4465             : */
    4466           1 : PHP_METHOD(DatePeriod, getDateInterval)
    4467             : {
    4468             :         php_period_obj   *dpobj;
    4469             :         php_interval_obj *diobj;
    4470             : 
    4471           1 :         if (zend_parse_parameters_none() == FAILURE) {
    4472           0 :                 return;
    4473             :         }
    4474             : 
    4475           1 :         dpobj = Z_PHPPERIOD_P(getThis());
    4476             : 
    4477           1 :         php_date_instantiate(date_ce_interval, return_value);
    4478           1 :         diobj = Z_PHPINTERVAL_P(return_value);
    4479           1 :         diobj->diff = timelib_rel_time_clone(dpobj->interval);
    4480           1 :         diobj->initialized = 1;
    4481             : }
    4482             : /* }}} */
    4483             : 
    4484        3504 : static int check_id_allowed(char *id, zend_long what) /* {{{ */
    4485             : {
    4486        3504 :         if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA     && strncasecmp(id, "Africa/",      7) == 0) return 1;
    4487        3288 :         if (what & PHP_DATE_TIMEZONE_GROUP_AMERICA    && strncasecmp(id, "America/",     8) == 0) return 1;
    4488        2463 :         if (what & PHP_DATE_TIMEZONE_GROUP_ANTARCTICA && strncasecmp(id, "Antarctica/", 11) == 0) return 1;
    4489        2415 :         if (what & PHP_DATE_TIMEZONE_GROUP_ARCTIC     && strncasecmp(id, "Arctic/",      7) == 0) return 1;
    4490        2411 :         if (what & PHP_DATE_TIMEZONE_GROUP_ASIA       && strncasecmp(id, "Asia/",        5) == 0) return 1;
    4491        2039 :         if (what & PHP_DATE_TIMEZONE_GROUP_ATLANTIC   && strncasecmp(id, "Atlantic/",    9) == 0) return 1;
    4492        1991 :         if (what & PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  && strncasecmp(id, "Australia/",  10) == 0) return 1;
    4493        1899 :         if (what & PHP_DATE_TIMEZONE_GROUP_EUROPE     && strncasecmp(id, "Europe/",      7) == 0) return 1;
    4494        1604 :         if (what & PHP_DATE_TIMEZONE_GROUP_INDIAN     && strncasecmp(id, "Indian/",      7) == 0) return 1;
    4495        1560 :         if (what & PHP_DATE_TIMEZONE_GROUP_PACIFIC    && strncasecmp(id, "Pacific/",     8) == 0) return 1;
    4496        1388 :         if (what & PHP_DATE_TIMEZONE_GROUP_UTC        && strncasecmp(id, "UTC",          3) == 0) return 1;
    4497        1383 :         return 0;
    4498             : } /* }}} */
    4499             : 
    4500             : /* {{{ proto array timezone_identifiers_list([long what[, string country]])
    4501             :    Returns numerically index array with all timezone identifiers.
    4502             : */
    4503           8 : PHP_FUNCTION(timezone_identifiers_list)
    4504             : {
    4505             :         const timelib_tzdb             *tzdb;
    4506             :         const timelib_tzdb_index_entry *table;
    4507             :         int                             i, item_count;
    4508           8 :         zend_long                            what = PHP_DATE_TIMEZONE_GROUP_ALL;
    4509           8 :         char                           *option = NULL;
    4510           8 :         size_t                             option_len = 0;
    4511             : 
    4512           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ls", &what, &option, &option_len) == FAILURE) {
    4513           0 :                 RETURN_FALSE;
    4514             :         }
    4515             : 
    4516             :         /* Extra validation */
    4517           8 :         if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
    4518           1 :                 php_error_docref(NULL, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
    4519           1 :                 RETURN_FALSE;
    4520             :         }
    4521             : 
    4522           7 :         tzdb = DATE_TIMEZONEDB;
    4523           7 :         item_count = tzdb->index_size;
    4524           7 :         table = tzdb->index;
    4525             : 
    4526           7 :         array_init(return_value);
    4527             : 
    4528        4095 :         for (i = 0; i < item_count; ++i) {
    4529        4088 :                 if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
    4530           0 :                         if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
    4531           0 :                                 add_next_index_string(return_value, table[i].id);
    4532             :                         }
    4533        4088 :                 } else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
    4534        2455 :                         add_next_index_string(return_value, table[i].id);
    4535             :                 }
    4536             :         };
    4537             : }
    4538             : /* }}} */
    4539             : 
    4540             : /* {{{ proto array timezone_version_get()
    4541             :    Returns the Olson database version number.
    4542             : */
    4543           2 : PHP_FUNCTION(timezone_version_get)
    4544             : {
    4545             :         const timelib_tzdb *tzdb;
    4546             : 
    4547           2 :         tzdb = DATE_TIMEZONEDB;
    4548           4 :         RETURN_STRING(tzdb->version);
    4549             : }
    4550             : /* }}} */
    4551             : 
    4552             : /* {{{ proto array timezone_abbreviations_list()
    4553             :    Returns associative array containing dst, offset and the timezone name
    4554             : */
    4555           5 : PHP_FUNCTION(timezone_abbreviations_list)
    4556             : {
    4557             :         const timelib_tz_lookup_table *table, *entry;
    4558             :         zval                          element, *abbr_array_p, abbr_array;
    4559             : 
    4560           5 :         table = timelib_timezone_abbreviations_list();
    4561           5 :         array_init(return_value);
    4562           5 :         entry = table;
    4563             : 
    4564             :         do {
    4565        9150 :                 array_init(&element);
    4566        9150 :                 add_assoc_bool_ex(&element, "dst", sizeof("dst") -1, entry->type);
    4567        9150 :                 add_assoc_long_ex(&element, "offset", sizeof("offset") - 1, entry->gmtoffset);
    4568        9150 :                 if (entry->full_tz_name) {
    4569        9025 :                         add_assoc_string_ex(&element, "timezone_id", sizeof("timezone_id") - 1, entry->full_tz_name);
    4570             :                 } else {
    4571         125 :                         add_assoc_null_ex(&element, "timezone_id", sizeof("timezone_id") - 1);
    4572             :                 }
    4573             : 
    4574        9150 :                 abbr_array_p = zend_hash_str_find(Z_ARRVAL_P(return_value), entry->name, strlen(entry->name));
    4575        9150 :                 if (!abbr_array_p) {
    4576        1870 :                         array_init(&abbr_array);
    4577        1870 :                         add_assoc_zval(return_value, entry->name, &abbr_array);
    4578             :                 } else {
    4579        7280 :                         ZVAL_COPY_VALUE(&abbr_array, abbr_array_p);
    4580             :                 }
    4581        9150 :                 add_next_index_zval(&abbr_array, &element);
    4582        9150 :                 entry++;
    4583        9150 :         } while (entry->name);
    4584           5 : }
    4585             : /* }}} */
    4586             : 
    4587             : /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
    4588             :    Sets the default timezone used by all date/time functions in a script */
    4589         674 : PHP_FUNCTION(date_default_timezone_set)
    4590             : {
    4591             :         char *zone;
    4592             :         size_t   zone_len;
    4593             : 
    4594         674 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &zone, &zone_len) == FAILURE) {
    4595           4 :                 RETURN_FALSE;
    4596             :         }
    4597         670 :         if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
    4598          25 :                 php_error_docref(NULL, E_NOTICE, "Timezone ID '%s' is invalid", zone);
    4599          25 :                 RETURN_FALSE;
    4600             :         }
    4601         645 :         if (DATEG(timezone)) {
    4602         119 :                 efree(DATEG(timezone));
    4603         119 :                 DATEG(timezone) = NULL;
    4604             :         }
    4605         645 :         DATEG(timezone) = estrndup(zone, zone_len);
    4606         645 :         RETURN_TRUE;
    4607             : }
    4608             : /* }}} */
    4609             : 
    4610             : /* {{{ proto string date_default_timezone_get()
    4611             :    Gets the default timezone used by all date/time functions in a script */
    4612          19 : PHP_FUNCTION(date_default_timezone_get)
    4613             : {
    4614             :         timelib_tzinfo *default_tz;
    4615             : 
    4616          19 :         default_tz = get_timezone_info();
    4617          38 :         RETVAL_STRING(default_tz->name);
    4618          19 : }
    4619             : /* }}} */
    4620             : 
    4621             : /* {{{ php_do_date_sunrise_sunset
    4622             :  *  Common for date_sunrise() and date_sunset() functions
    4623             :  */
    4624         902 : static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
    4625             : {
    4626         902 :         double latitude = 0.0, longitude = 0.0, zenith = 0.0, gmt_offset = 0, altitude;
    4627             :         double h_rise, h_set, N;
    4628             :         timelib_sll rise, set, transit;
    4629         902 :         zend_long time, retformat = 0;
    4630             :         int             rs;
    4631             :         timelib_time   *t;
    4632             :         timelib_tzinfo *tzi;
    4633             :         zend_string    *retstr;
    4634             : 
    4635         902 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
    4636         366 :                 RETURN_FALSE;
    4637             :         }
    4638             : 
    4639         536 :         switch (ZEND_NUM_ARGS()) {
    4640             :                 case 1:
    4641           0 :                         retformat = SUNFUNCS_RET_STRING;
    4642             :                 case 2:
    4643           0 :                         latitude = INI_FLT("date.default_latitude");
    4644             :                 case 3:
    4645           0 :                         longitude = INI_FLT("date.default_longitude");
    4646             :                 case 4:
    4647          48 :                         if (calc_sunset) {
    4648          24 :                                 zenith = INI_FLT("date.sunset_zenith");
    4649             :                         } else {
    4650          24 :                                 zenith = INI_FLT("date.sunrise_zenith");
    4651             :                         }
    4652             :                 case 5:
    4653             :                 case 6:
    4654         536 :                         break;
    4655             :                 default:
    4656           0 :                         php_error_docref(NULL, E_WARNING, "invalid format");
    4657           0 :                         RETURN_FALSE;
    4658             :                         break;
    4659             :         }
    4660        1072 :         if (retformat != SUNFUNCS_RET_TIMESTAMP &&
    4661         370 :                 retformat != SUNFUNCS_RET_STRING &&
    4662         166 :                 retformat != SUNFUNCS_RET_DOUBLE)
    4663             :         {
    4664           0 :                 php_error_docref(NULL, E_WARNING, "Wrong return format given, pick one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING or SUNFUNCS_RET_DOUBLE");
    4665           0 :                 RETURN_FALSE;
    4666             :         }
    4667         536 :         altitude = 90 - zenith;
    4668             : 
    4669             :         /* Initialize time struct */
    4670         536 :         t = timelib_time_ctor();
    4671         536 :         tzi = get_timezone_info();
    4672         536 :         t->tz_info = tzi;
    4673         536 :         t->zone_type = TIMELIB_ZONETYPE_ID;
    4674             : 
    4675         536 :         if (ZEND_NUM_ARGS() <= 5) {
    4676          48 :                 gmt_offset = timelib_get_current_offset(t) / 3600;
    4677             :         }
    4678             : 
    4679         536 :         timelib_unixtime2local(t, time);
    4680         536 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
    4681         536 :         timelib_time_dtor(t);
    4682             : 
    4683         536 :         if (rs != 0) {
    4684         120 :                 RETURN_FALSE;
    4685             :         }
    4686             : 
    4687         416 :         if (retformat == SUNFUNCS_RET_TIMESTAMP) {
    4688         126 :                 RETURN_LONG(calc_sunset ? set : rise);
    4689             :         }
    4690         290 :         N = (calc_sunset ? h_set : h_rise) + gmt_offset;
    4691             : 
    4692         290 :         if (N > 24 || N < 0) {
    4693          28 :                 N -= floor(N / 24) * 24;
    4694             :         }
    4695             : 
    4696         290 :         switch (retformat) {
    4697             :                 case SUNFUNCS_RET_STRING:
    4698         164 :                         retstr = strpprintf(0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
    4699         164 :                         RETURN_NEW_STR(retstr);
    4700             :                         break;
    4701             :                 case SUNFUNCS_RET_DOUBLE:
    4702         126 :                         RETURN_DOUBLE(N);
    4703             :                         break;
    4704             :         }
    4705             : }
    4706             : /* }}} */
    4707             : 
    4708             : /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
    4709             :    Returns time of sunrise for a given day and location */
    4710         450 : PHP_FUNCTION(date_sunrise)
    4711             : {
    4712         450 :         php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4713         450 : }
    4714             : /* }}} */
    4715             : 
    4716             : /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
    4717             :    Returns time of sunset for a given day and location */
    4718         452 : PHP_FUNCTION(date_sunset)
    4719             : {
    4720         452 :         php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4721         452 : }
    4722             : /* }}} */
    4723             : 
    4724             : /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
    4725             :    Returns an array with information about sun set/rise and twilight begin/end */
    4726          79 : PHP_FUNCTION(date_sun_info)
    4727             : {
    4728             :         zend_long       time;
    4729             :         double          latitude, longitude;
    4730             :         timelib_time   *t, *t2;
    4731             :         timelib_tzinfo *tzi;
    4732             :         int             rs;
    4733             :         timelib_sll     rise, set, transit;
    4734             :         int             dummy;
    4735             :         double          ddummy;
    4736             : 
    4737          79 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ldd", &time, &latitude, &longitude) == FAILURE) {
    4738          24 :                 RETURN_FALSE;
    4739             :         }
    4740             :         /* Initialize time struct */
    4741          55 :         t = timelib_time_ctor();
    4742          55 :         tzi = get_timezone_info();
    4743          55 :         t->tz_info = tzi;
    4744          55 :         t->zone_type = TIMELIB_ZONETYPE_ID;
    4745          55 :         timelib_unixtime2local(t, time);
    4746             : 
    4747             :         /* Setup */
    4748          55 :         t2 = timelib_time_ctor();
    4749          55 :         array_init(return_value);
    4750             : 
    4751             :         /* Get sun up/down and transit */
    4752          55 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
    4753          55 :         switch (rs) {
    4754             :                 case -1: /* always below */
    4755           1 :                         add_assoc_bool(return_value, "sunrise", 0);
    4756           1 :                         add_assoc_bool(return_value, "sunset", 0);
    4757           1 :                         break;
    4758             :                 case 1: /* always above */
    4759           2 :                         add_assoc_bool(return_value, "sunrise", 1);
    4760           2 :                         add_assoc_bool(return_value, "sunset", 1);
    4761           2 :                         break;
    4762             :                 default:
    4763          52 :                         t2->sse = rise;
    4764          52 :                         add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
    4765          52 :                         t2->sse = set;
    4766          52 :                         add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
    4767             :         }
    4768          55 :         t2->sse = transit;
    4769          55 :         add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
    4770             : 
    4771             :         /* Get civil twilight */
    4772          55 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4773          55 :         switch (rs) {
    4774             :                 case -1: /* always below */
    4775           1 :                         add_assoc_bool(return_value, "civil_twilight_begin", 0);
    4776           1 :                         add_assoc_bool(return_value, "civil_twilight_end", 0);
    4777           1 :                         break;
    4778             :                 case 1: /* always above */
    4779           2 :                         add_assoc_bool(return_value, "civil_twilight_begin", 1);
    4780           2 :                         add_assoc_bool(return_value, "civil_twilight_end", 1);
    4781           2 :                         break;
    4782             :                 default:
    4783          52 :                         t2->sse = rise;
    4784          52 :                         add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
    4785          52 :                         t2->sse = set;
    4786          52 :                         add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
    4787             :         }
    4788             : 
    4789             :         /* Get nautical twilight */
    4790          55 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4791          55 :         switch (rs) {
    4792             :                 case -1: /* always below */
    4793           1 :                         add_assoc_bool(return_value, "nautical_twilight_begin", 0);
    4794           1 :                         add_assoc_bool(return_value, "nautical_twilight_end", 0);
    4795           1 :                         break;
    4796             :                 case 1: /* always above */
    4797           1 :                         add_assoc_bool(return_value, "nautical_twilight_begin", 1);
    4798           1 :                         add_assoc_bool(return_value, "nautical_twilight_end", 1);
    4799           1 :                         break;
    4800             :                 default:
    4801          53 :                         t2->sse = rise;
    4802          53 :                         add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
    4803          53 :                         t2->sse = set;
    4804          53 :                         add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
    4805             :         }
    4806             : 
    4807             :         /* Get astronomical twilight */
    4808          55 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4809          55 :         switch (rs) {
    4810             :                 case -1: /* always below */
    4811           1 :                         add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
    4812           1 :                         add_assoc_bool(return_value, "astronomical_twilight_end", 0);
    4813           1 :                         break;
    4814             :                 case 1: /* always above */
    4815           1 :                         add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
    4816           1 :                         add_assoc_bool(return_value, "astronomical_twilight_end", 1);
    4817           1 :                         break;
    4818             :                 default:
    4819          53 :                         t2->sse = rise;
    4820          53 :                         add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
    4821          53 :                         t2->sse = set;
    4822          53 :                         add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
    4823             :         }
    4824          55 :         timelib_time_dtor(t);
    4825          55 :         timelib_time_dtor(t2);
    4826             : }
    4827             : /* }}} */
    4828             : 
    4829           0 : static HashTable *date_object_get_gc_period(zval *object, zval **table, int *n) /* {{{ */
    4830             : {
    4831           0 :         *table = NULL;
    4832           0 :         *n = 0;
    4833           0 :         return zend_std_get_properties(object);
    4834             : } /* }}} */
    4835             : 
    4836           9 : static HashTable *date_object_get_properties_period(zval *object) /* {{{ */
    4837             : {
    4838             :         HashTable               *props;
    4839             :         zval                     zv;
    4840             :         php_period_obj  *period_obj;
    4841             : 
    4842           9 :         period_obj = Z_PHPPERIOD_P(object);
    4843             : 
    4844           9 :         props = zend_std_get_properties(object);
    4845             : 
    4846           9 :         if (!period_obj->start || GC_G(gc_active)) {
    4847           4 :                 return props;
    4848             :         }
    4849             : 
    4850           5 :         if (period_obj->start) {
    4851             :                 php_date_obj *date_obj;
    4852           5 :                 object_init_ex(&zv, date_ce_date);
    4853           5 :                 date_obj = Z_PHPDATE_P(&zv);
    4854           5 :                 date_obj->time = timelib_time_clone(period_obj->start);
    4855             :         } else {
    4856           0 :                 ZVAL_NULL(&zv);
    4857             :         }
    4858           5 :         zend_hash_str_update(props, "start", sizeof("start")-1, &zv);
    4859             : 
    4860           5 :         if (period_obj->current) {
    4861             :                 php_date_obj *date_obj;
    4862           3 :                 object_init_ex(&zv, date_ce_date);
    4863           3 :                 date_obj = Z_PHPDATE_P(&zv);
    4864           3 :                 date_obj->time = timelib_time_clone(period_obj->current);
    4865             :         } else {
    4866           2 :                 ZVAL_NULL(&zv);
    4867             :         }
    4868           5 :         zend_hash_str_update(props, "current", sizeof("current")-1, &zv);
    4869             : 
    4870           5 :         if (period_obj->end) {
    4871             :                 php_date_obj *date_obj;
    4872           0 :                 object_init_ex(&zv, date_ce_date);
    4873           0 :                 date_obj = Z_PHPDATE_P(&zv);
    4874           0 :                 date_obj->time = timelib_time_clone(period_obj->end);
    4875             :         } else {
    4876           5 :                 ZVAL_NULL(&zv);
    4877             :         }
    4878           5 :         zend_hash_str_update(props, "end", sizeof("end")-1, &zv);
    4879             : 
    4880           5 :         if (period_obj->interval) {
    4881             :                 php_interval_obj *interval_obj;
    4882           5 :                 object_init_ex(&zv, date_ce_interval);
    4883           5 :                 interval_obj = Z_PHPINTERVAL_P(&zv);
    4884           5 :                 interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
    4885           5 :                 interval_obj->initialized = 1;
    4886             :         } else {
    4887           0 :                 ZVAL_NULL(&zv);
    4888             :         }
    4889           5 :         zend_hash_str_update(props, "interval", sizeof("interval")-1, &zv);
    4890             : 
    4891             :         /* converted to larger type (int->long); must check when unserializing */
    4892           5 :         ZVAL_LONG(&zv, (zend_long) period_obj->recurrences);
    4893           5 :         zend_hash_str_update(props, "recurrences", sizeof("recurrences")-1, &zv);
    4894             : 
    4895           5 :         ZVAL_BOOL(&zv, period_obj->include_start_date);
    4896           5 :         zend_hash_str_update(props, "include_start_date", sizeof("include_start_date")-1, &zv);
    4897             : 
    4898           5 :         return props;
    4899             : } /* }}} */
    4900             : 
    4901           2 : static int php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht) /* {{{ */
    4902             : {
    4903             :         zval *ht_entry;
    4904             : 
    4905             :         /* this function does no rollback on error */
    4906             : 
    4907           2 :         ht_entry = zend_hash_str_find(myht, "start", sizeof("start")-1);
    4908           2 :         if (ht_entry) {
    4909           2 :                 if (Z_TYPE_P(ht_entry) == IS_OBJECT && Z_OBJCE_P(ht_entry) == date_ce_date) {
    4910             :                         php_date_obj *date_obj;
    4911           1 :                         date_obj = Z_PHPDATE_P(ht_entry);
    4912           1 :                         period_obj->start = timelib_time_clone(date_obj->time);
    4913           1 :                         period_obj->start_ce = Z_OBJCE_P(ht_entry);
    4914           0 :                 } else if (Z_TYPE_P(ht_entry) != IS_NULL) {
    4915           0 :                         return 0;
    4916             :                 }
    4917             :         } else {
    4918           1 :                 return 0;
    4919             :         }
    4920             : 
    4921           1 :         ht_entry = zend_hash_str_find(myht, "end", sizeof("end")-1);
    4922           1 :         if (ht_entry) {
    4923           1 :                 if (Z_TYPE_P(ht_entry) == IS_OBJECT && Z_OBJCE_P(ht_entry) == date_ce_date) {
    4924             :                         php_date_obj *date_obj;
    4925           0 :                         date_obj = Z_PHPDATE_P(ht_entry);
    4926           0 :                         period_obj->end = timelib_time_clone(date_obj->time);
    4927           1 :                 } else if (Z_TYPE_P(ht_entry) != IS_NULL) {
    4928           0 :                         return 0;
    4929             :                 }
    4930             :         } else {
    4931           0 :                 return 0;
    4932             :         }
    4933             : 
    4934           1 :         ht_entry = zend_hash_str_find(myht, "current", sizeof("current")-1);
    4935           1 :         if (ht_entry) {
    4936           2 :                 if (Z_TYPE_P(ht_entry) == IS_OBJECT && Z_OBJCE_P(ht_entry) == date_ce_date) {
    4937             :                         php_date_obj *date_obj;
    4938           1 :                         date_obj = Z_PHPDATE_P(ht_entry);
    4939           1 :                         period_obj->current = timelib_time_clone(date_obj->time);
    4940           0 :                 } else if (Z_TYPE_P(ht_entry) != IS_NULL)  {
    4941           0 :                         return 0;
    4942             :                 }
    4943             :         } else {
    4944           0 :                 return 0;
    4945             :         }
    4946             : 
    4947           1 :         ht_entry = zend_hash_str_find(myht, "interval", sizeof("interval")-1);
    4948           1 :         if (ht_entry) {
    4949           2 :                 if (Z_TYPE_P(ht_entry) == IS_OBJECT && Z_OBJCE_P(ht_entry) == date_ce_interval) {
    4950             :                         php_interval_obj *interval_obj;
    4951           1 :                         interval_obj = Z_PHPINTERVAL_P(ht_entry);
    4952           1 :                         period_obj->interval = timelib_rel_time_clone(interval_obj->diff);
    4953             :                 } else { /* interval is required */
    4954           0 :                         return 0;
    4955             :                 }
    4956             :         } else {
    4957           0 :                 return 0;
    4958             :         }
    4959             : 
    4960           1 :         ht_entry = zend_hash_str_find(myht, "recurrences", sizeof("recurrences")-1);
    4961           5 :         if (ht_entry &&
    4962           2 :                         Z_TYPE_P(ht_entry) == IS_LONG && Z_LVAL_P(ht_entry) >= 0 && Z_LVAL_P(ht_entry) <= INT_MAX) {
    4963           1 :                 period_obj->recurrences = Z_LVAL_P(ht_entry);
    4964             :         } else {
    4965           0 :                 return 0;
    4966             :         }
    4967             : 
    4968           1 :         ht_entry = zend_hash_str_find(myht, "include_start_date", sizeof("include_start_date")-1);
    4969           4 :         if (ht_entry &&
    4970             :                         (Z_TYPE_P(ht_entry) == IS_FALSE || Z_TYPE_P(ht_entry) == IS_TRUE)) {
    4971           1 :                 period_obj->include_start_date = (Z_TYPE_P(ht_entry) == IS_TRUE);
    4972             :         } else {
    4973           0 :                 return 0;
    4974             :         }
    4975             : 
    4976           1 :         period_obj->initialized = 1;
    4977             : 
    4978           1 :         return 1;
    4979             : } /* }}} */
    4980             : 
    4981             : /* {{{ proto DatePeriod::__set_state()
    4982             : */
    4983           0 : PHP_METHOD(DatePeriod, __set_state)
    4984             : {
    4985             :         php_period_obj   *period_obj;
    4986             :         zval             *array;
    4987             :         HashTable        *myht;
    4988             : 
    4989           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) {
    4990           0 :                 RETURN_FALSE;
    4991             :         }
    4992             : 
    4993           0 :         myht = Z_ARRVAL_P(array);
    4994             : 
    4995           0 :         object_init_ex(return_value, date_ce_period);
    4996           0 :         period_obj = Z_PHPPERIOD_P(return_value);
    4997           0 :         if (!php_date_period_initialize_from_hash(period_obj, myht)) {
    4998           0 :                 php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
    4999             :         }
    5000             : }
    5001             : /* }}} */
    5002             : 
    5003             : /* {{{ proto DatePeriod::__wakeup()
    5004             : */
    5005           2 : PHP_METHOD(DatePeriod, __wakeup)
    5006             : {
    5007           2 :         zval             *object = getThis();
    5008             :         php_period_obj   *period_obj;
    5009             :         HashTable        *myht;
    5010             : 
    5011           2 :         period_obj = Z_PHPPERIOD_P(object);
    5012             : 
    5013           2 :         myht = Z_OBJPROP_P(object);
    5014             : 
    5015           2 :         if (!php_date_period_initialize_from_hash(period_obj, myht)) {
    5016           1 :                 php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
    5017             :         }
    5018           1 : }
    5019             : /* }}} */
    5020             : 
    5021             : /* {{{ date_period_read_property */
    5022           0 : static zval *date_period_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv)
    5023             : {
    5024             :         zval *zv;
    5025           0 :         if (type != BP_VAR_IS && type != BP_VAR_R) {
    5026           0 :                 php_error_docref(NULL, E_ERROR, "Retrieval of DatePeriod properties for modification is unsupported");
    5027             :         }
    5028             : 
    5029           0 :         Z_OBJPROP_P(object); /* build properties hash table */
    5030             : 
    5031           0 :         zv = std_object_handlers.read_property(object, member, type, cache_slot, rv);
    5032           0 :         if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) {
    5033             :                 /* defensive copy */
    5034           0 :                 ZVAL_OBJ(zv, Z_OBJ_HANDLER_P(zv, clone_obj)(zv));
    5035             :         }
    5036             : 
    5037           0 :         return zv;
    5038             : }
    5039             : /* }}} */
    5040             : 
    5041             : /* {{{ date_period_write_property */
    5042           0 : static void date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot)
    5043             : {
    5044           0 :         php_error_docref(NULL, E_ERROR, "Writing to DatePeriod properties is unsupported");
    5045           0 : }
    5046             : /* }}} */
    5047             : 
    5048             : /*
    5049             :  * Local variables:
    5050             :  * tab-width: 4
    5051             :  * c-basic-offset: 4
    5052             :  * End:
    5053             :  * vim600: fdm=marker
    5054             :  * vim: noet sw=4 ts=4
    5055             :  */

Generated by: LCOV version 1.10

Generated at Sun, 29 May 2016 00:48:21 +0000 (3 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.