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: 1838 2059 89.3 %
Date: 2014-09-27 Functions: 147 162 90.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 27 Sep 2014 16:43:07 +0000 (4 days ago)

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