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: 1703 1905 89.4 %
Date: 2014-12-15 Functions: 120 132 90.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 15 Dec 2014 17:02:40 +0000 (3 days ago)

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