calendar.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Shane Caraveo <shane@caraveo.com> |
  16. | Colin Viebrock <colin@easydns.com> |
  17. | Hartmut Holzgraefe <hholzgra@php.net> |
  18. | Wez Furlong <wez@thebrainroom.com> |
  19. +----------------------------------------------------------------------+
  20. */
  21. /* $Id$ */
  22. #ifdef HAVE_CONFIG_H
  23. #include "config.h"
  24. #endif
  25. #ifdef PHP_WIN32
  26. #define _WINNLS_
  27. #endif
  28. #include "php.h"
  29. #include "ext/standard/info.h"
  30. #include "php_calendar.h"
  31. #include "sdncal.h"
  32. #include <stdio.h>
  33. /* {{{ arginfo */
  34. ZEND_BEGIN_ARG_INFO_EX(arginfo_unixtojd, 0, 0, 0)
  35. ZEND_ARG_INFO(0, timestamp)
  36. ZEND_END_ARG_INFO()
  37. ZEND_BEGIN_ARG_INFO(arginfo_jdtounix, 0)
  38. ZEND_ARG_INFO(0, jday)
  39. ZEND_END_ARG_INFO()
  40. ZEND_BEGIN_ARG_INFO_EX(arginfo_cal_info, 0, 0, 0)
  41. ZEND_ARG_INFO(0, calendar)
  42. ZEND_END_ARG_INFO()
  43. ZEND_BEGIN_ARG_INFO(arginfo_cal_days_in_month, 0)
  44. ZEND_ARG_INFO(0, calendar)
  45. ZEND_ARG_INFO(0, month)
  46. ZEND_ARG_INFO(0, year)
  47. ZEND_END_ARG_INFO()
  48. ZEND_BEGIN_ARG_INFO(arginfo_cal_to_jd, 0)
  49. ZEND_ARG_INFO(0, calendar)
  50. ZEND_ARG_INFO(0, month)
  51. ZEND_ARG_INFO(0, day)
  52. ZEND_ARG_INFO(0, year)
  53. ZEND_END_ARG_INFO()
  54. ZEND_BEGIN_ARG_INFO(arginfo_cal_from_jd, 0)
  55. ZEND_ARG_INFO(0, jd)
  56. ZEND_ARG_INFO(0, calendar)
  57. ZEND_END_ARG_INFO()
  58. ZEND_BEGIN_ARG_INFO(arginfo_jdtogregorian, 0)
  59. ZEND_ARG_INFO(0, juliandaycount)
  60. ZEND_END_ARG_INFO()
  61. ZEND_BEGIN_ARG_INFO(arginfo_gregoriantojd, 0)
  62. ZEND_ARG_INFO(0, month)
  63. ZEND_ARG_INFO(0, day)
  64. ZEND_ARG_INFO(0, year)
  65. ZEND_END_ARG_INFO()
  66. ZEND_BEGIN_ARG_INFO(arginfo_jdtojulian, 0)
  67. ZEND_ARG_INFO(0, juliandaycount)
  68. ZEND_END_ARG_INFO()
  69. ZEND_BEGIN_ARG_INFO(arginfo_juliantojd, 0)
  70. ZEND_ARG_INFO(0, month)
  71. ZEND_ARG_INFO(0, day)
  72. ZEND_ARG_INFO(0, year)
  73. ZEND_END_ARG_INFO()
  74. ZEND_BEGIN_ARG_INFO_EX(arginfo_jdtojewish, 0, 0, 1)
  75. ZEND_ARG_INFO(0, juliandaycount)
  76. ZEND_ARG_INFO(0, hebrew)
  77. ZEND_ARG_INFO(0, fl)
  78. ZEND_END_ARG_INFO()
  79. ZEND_BEGIN_ARG_INFO(arginfo_jewishtojd, 0)
  80. ZEND_ARG_INFO(0, month)
  81. ZEND_ARG_INFO(0, day)
  82. ZEND_ARG_INFO(0, year)
  83. ZEND_END_ARG_INFO()
  84. ZEND_BEGIN_ARG_INFO(arginfo_jdtofrench, 0)
  85. ZEND_ARG_INFO(0, juliandaycount)
  86. ZEND_END_ARG_INFO()
  87. ZEND_BEGIN_ARG_INFO(arginfo_frenchtojd, 0)
  88. ZEND_ARG_INFO(0, month)
  89. ZEND_ARG_INFO(0, day)
  90. ZEND_ARG_INFO(0, year)
  91. ZEND_END_ARG_INFO()
  92. ZEND_BEGIN_ARG_INFO_EX(arginfo_jddayofweek, 0, 0, 1)
  93. ZEND_ARG_INFO(0, juliandaycount)
  94. ZEND_ARG_INFO(0, mode)
  95. ZEND_END_ARG_INFO()
  96. ZEND_BEGIN_ARG_INFO(arginfo_jdmonthname, 0)
  97. ZEND_ARG_INFO(0, juliandaycount)
  98. ZEND_ARG_INFO(0, mode)
  99. ZEND_END_ARG_INFO()
  100. ZEND_BEGIN_ARG_INFO_EX(arginfo_easter_date, 0, 0, 0)
  101. ZEND_ARG_INFO(0, year)
  102. ZEND_END_ARG_INFO()
  103. ZEND_BEGIN_ARG_INFO_EX(arginfo_easter_days, 0, 0, 0)
  104. ZEND_ARG_INFO(0, year)
  105. ZEND_ARG_INFO(0, method)
  106. ZEND_END_ARG_INFO()
  107. /* }}} */
  108. const zend_function_entry calendar_functions[] = {
  109. PHP_FE(jdtogregorian, arginfo_jdtogregorian)
  110. PHP_FE(gregoriantojd, arginfo_gregoriantojd)
  111. PHP_FE(jdtojulian, arginfo_jdtojulian)
  112. PHP_FE(juliantojd, arginfo_juliantojd)
  113. PHP_FE(jdtojewish, arginfo_jdtojewish)
  114. PHP_FE(jewishtojd, arginfo_jewishtojd)
  115. PHP_FE(jdtofrench, arginfo_jdtofrench)
  116. PHP_FE(frenchtojd, arginfo_frenchtojd)
  117. PHP_FE(jddayofweek, arginfo_jddayofweek)
  118. PHP_FE(jdmonthname, arginfo_jdmonthname)
  119. PHP_FE(easter_date, arginfo_easter_date)
  120. PHP_FE(easter_days, arginfo_easter_days)
  121. PHP_FE(unixtojd, arginfo_unixtojd)
  122. PHP_FE(jdtounix, arginfo_jdtounix)
  123. PHP_FE(cal_to_jd, arginfo_cal_to_jd)
  124. PHP_FE(cal_from_jd, arginfo_cal_from_jd)
  125. PHP_FE(cal_days_in_month, arginfo_cal_days_in_month)
  126. PHP_FE(cal_info, arginfo_cal_info)
  127. PHP_FE_END
  128. };
  129. zend_module_entry calendar_module_entry = {
  130. STANDARD_MODULE_HEADER,
  131. "calendar",
  132. calendar_functions,
  133. PHP_MINIT(calendar),
  134. NULL,
  135. NULL,
  136. NULL,
  137. PHP_MINFO(calendar),
  138. NO_VERSION_YET,
  139. STANDARD_MODULE_PROPERTIES,
  140. };
  141. #ifdef COMPILE_DL_CALENDAR
  142. ZEND_GET_MODULE(calendar)
  143. #endif
  144. /* this order must match the conversion table below */
  145. enum cal_name_type_t {
  146. CAL_GREGORIAN = 0,
  147. CAL_JULIAN,
  148. CAL_JEWISH,
  149. CAL_FRENCH,
  150. CAL_NUM_CALS
  151. };
  152. typedef long int (*cal_to_jd_func_t) (int month, int day, int year);
  153. typedef void (*cal_from_jd_func_t) (long int jd, int *year, int *month, int *day);
  154. typedef char *(*cal_as_string_func_t) (int year, int month, int day);
  155. struct cal_entry_t {
  156. char *name;
  157. char *symbol;
  158. cal_to_jd_func_t to_jd;
  159. cal_from_jd_func_t from_jd;
  160. int num_months;
  161. int max_days_in_month;
  162. char **month_name_short;
  163. char **month_name_long;
  164. };
  165. static struct cal_entry_t cal_conversion_table[CAL_NUM_CALS] = {
  166. {"Gregorian", "CAL_GREGORIAN", GregorianToSdn, SdnToGregorian, 12, 31,
  167. MonthNameShort, MonthNameLong},
  168. {"Julian", "CAL_JULIAN", JulianToSdn, SdnToJulian, 12, 31,
  169. MonthNameShort, MonthNameLong},
  170. {"Jewish", "CAL_JEWISH", JewishToSdn, SdnToJewish, 13, 30,
  171. JewishMonthNameLeap, JewishMonthNameLeap},
  172. {"French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30,
  173. FrenchMonthName, FrenchMonthName}
  174. };
  175. #define JEWISH_MONTH_NAME(year) ((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthNameLeap:JewishMonthName)
  176. #define JEWISH_HEB_MONTH_NAME(year) ((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthHebNameLeap:JewishMonthHebName)
  177. /* For jddayofweek */
  178. enum { CAL_DOW_DAYNO, CAL_DOW_LONG, CAL_DOW_SHORT };
  179. /* For jdmonthname */
  180. enum { CAL_MONTH_GREGORIAN_SHORT, CAL_MONTH_GREGORIAN_LONG,
  181. CAL_MONTH_JULIAN_SHORT, CAL_MONTH_JULIAN_LONG, CAL_MONTH_JEWISH,
  182. CAL_MONTH_FRENCH
  183. };
  184. /* for heb_number_to_chars */
  185. static char alef_bet[25] = "0àáâãäåæçèéëìîðñòôö÷øùú";
  186. #define CAL_JEWISH_ADD_ALAFIM_GERESH 0x2
  187. #define CAL_JEWISH_ADD_ALAFIM 0x4
  188. #define CAL_JEWISH_ADD_GERESHAYIM 0x8
  189. PHP_MINIT_FUNCTION(calendar)
  190. {
  191. REGISTER_LONG_CONSTANT("CAL_GREGORIAN", CAL_GREGORIAN, CONST_CS | CONST_PERSISTENT);
  192. REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS | CONST_PERSISTENT);
  193. REGISTER_LONG_CONSTANT("CAL_JEWISH", CAL_JEWISH, CONST_CS | CONST_PERSISTENT);
  194. REGISTER_LONG_CONSTANT("CAL_FRENCH", CAL_FRENCH, CONST_CS | CONST_PERSISTENT);
  195. REGISTER_LONG_CONSTANT("CAL_NUM_CALS", CAL_NUM_CALS, CONST_CS | CONST_PERSISTENT);
  196. /* constants for jddayofweek */
  197. REGISTER_LONG_CONSTANT("CAL_DOW_DAYNO", CAL_DOW_DAYNO, CONST_CS | CONST_PERSISTENT);
  198. REGISTER_LONG_CONSTANT("CAL_DOW_SHORT", CAL_DOW_SHORT, CONST_CS | CONST_PERSISTENT);
  199. REGISTER_LONG_CONSTANT("CAL_DOW_LONG", CAL_DOW_LONG, CONST_CS | CONST_PERSISTENT);
  200. /* constants for jdmonthname */
  201. REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_SHORT", CAL_MONTH_GREGORIAN_SHORT, CONST_CS | CONST_PERSISTENT);
  202. REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_LONG", CAL_MONTH_GREGORIAN_LONG, CONST_CS | CONST_PERSISTENT);
  203. REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_SHORT", CAL_MONTH_JULIAN_SHORT, CONST_CS | CONST_PERSISTENT);
  204. REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_LONG", CAL_MONTH_JULIAN_LONG, CONST_CS | CONST_PERSISTENT);
  205. REGISTER_LONG_CONSTANT("CAL_MONTH_JEWISH", CAL_MONTH_JEWISH, CONST_CS | CONST_PERSISTENT);
  206. REGISTER_LONG_CONSTANT("CAL_MONTH_FRENCH", CAL_MONTH_FRENCH, CONST_CS | CONST_PERSISTENT);
  207. /* constants for easter calculation */
  208. REGISTER_LONG_CONSTANT("CAL_EASTER_DEFAULT", CAL_EASTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
  209. REGISTER_LONG_CONSTANT("CAL_EASTER_ROMAN", CAL_EASTER_ROMAN, CONST_CS | CONST_PERSISTENT);
  210. REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_GREGORIAN", CAL_EASTER_ALWAYS_GREGORIAN, CONST_CS | CONST_PERSISTENT);
  211. REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_JULIAN", CAL_EASTER_ALWAYS_JULIAN, CONST_CS | CONST_PERSISTENT);
  212. /* constants for Jewish date formatting */
  213. REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_ALAFIM_GERESH", CAL_JEWISH_ADD_ALAFIM_GERESH, CONST_CS | CONST_PERSISTENT);
  214. REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_ALAFIM", CAL_JEWISH_ADD_ALAFIM, CONST_CS | CONST_PERSISTENT);
  215. REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_GERESHAYIM", CAL_JEWISH_ADD_GERESHAYIM, CONST_CS | CONST_PERSISTENT);
  216. return SUCCESS;
  217. }
  218. PHP_MINFO_FUNCTION(calendar)
  219. {
  220. php_info_print_table_start();
  221. php_info_print_table_row(2, "Calendar support", "enabled");
  222. php_info_print_table_end();
  223. }
  224. static void _php_cal_info(int cal, zval **ret)
  225. {
  226. zval *months, *smonths;
  227. int i;
  228. struct cal_entry_t *calendar;
  229. calendar = &cal_conversion_table[cal];
  230. array_init(*ret);
  231. MAKE_STD_ZVAL(months);
  232. MAKE_STD_ZVAL(smonths);
  233. array_init(months);
  234. array_init(smonths);
  235. for (i = 1; i <= calendar->num_months; i++) {
  236. add_index_string(months, i, calendar->month_name_long[i], 1);
  237. add_index_string(smonths, i, calendar->month_name_short[i], 1);
  238. }
  239. add_assoc_zval(*ret, "months", months);
  240. add_assoc_zval(*ret, "abbrevmonths", smonths);
  241. add_assoc_long(*ret, "maxdaysinmonth", calendar->max_days_in_month);
  242. add_assoc_string(*ret, "calname", calendar->name, 1);
  243. add_assoc_string(*ret, "calsymbol", calendar->symbol, 1);
  244. }
  245. /* {{{ proto array cal_info([int calendar])
  246. Returns information about a particular calendar */
  247. PHP_FUNCTION(cal_info)
  248. {
  249. long cal = -1;
  250. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &cal) == FAILURE) {
  251. RETURN_FALSE;
  252. }
  253. if (cal == -1) {
  254. int i;
  255. zval *val;
  256. array_init(return_value);
  257. for (i = 0; i < CAL_NUM_CALS; i++) {
  258. MAKE_STD_ZVAL(val);
  259. _php_cal_info(i, &val);
  260. add_index_zval(return_value, i, val);
  261. }
  262. return;
  263. }
  264. if (cal != -1 && (cal < 0 || cal >= CAL_NUM_CALS)) {
  265. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
  266. RETURN_FALSE;
  267. }
  268. _php_cal_info(cal, &return_value);
  269. }
  270. /* }}} */
  271. /* {{{ proto int cal_days_in_month(int calendar, int month, int year)
  272. Returns the number of days in a month for a given year and calendar */
  273. PHP_FUNCTION(cal_days_in_month)
  274. {
  275. long cal, month, year;
  276. struct cal_entry_t *calendar;
  277. long sdn_start, sdn_next;
  278. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &cal, &month, &year) == FAILURE) {
  279. RETURN_FALSE;
  280. }
  281. if (cal < 0 || cal >= CAL_NUM_CALS) {
  282. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
  283. RETURN_FALSE;
  284. }
  285. calendar = &cal_conversion_table[cal];
  286. sdn_start = calendar->to_jd(year, month, 1);
  287. if (sdn_start == 0) {
  288. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid date.");
  289. RETURN_FALSE;
  290. }
  291. sdn_next = calendar->to_jd(year, 1 + month, 1);
  292. if (sdn_next == 0) {
  293. /* If the next month is invalid, then we need to try the first month of
  294. * the next year, bearing in mind that the next year after 1 BCE is
  295. * actually 1 AD and not 0. */
  296. if (year == -1) {
  297. sdn_next = calendar->to_jd(1, 1, 1);
  298. }
  299. else {
  300. sdn_next = calendar->to_jd(year + 1, 1, 1);
  301. if (cal == CAL_FRENCH && sdn_next == 0) {
  302. /* The French calendar ends on 0014-13-05. */
  303. sdn_next = 2380953;
  304. }
  305. }
  306. }
  307. RETURN_LONG(sdn_next - sdn_start);
  308. }
  309. /* }}} */
  310. /* {{{ proto int cal_to_jd(int calendar, int month, int day, int year)
  311. Converts from a supported calendar to Julian Day Count */
  312. PHP_FUNCTION(cal_to_jd)
  313. {
  314. long cal, month, day, year;
  315. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llll", &cal, &month, &day, &year) != SUCCESS) {
  316. RETURN_FALSE;
  317. }
  318. if (cal < 0 || cal >= CAL_NUM_CALS) {
  319. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
  320. RETURN_FALSE;
  321. }
  322. RETURN_LONG(cal_conversion_table[cal].to_jd(year, month, day));
  323. }
  324. /* }}} */
  325. /* {{{ proto array cal_from_jd(int jd, int calendar)
  326. Converts from Julian Day Count to a supported calendar and return extended information */
  327. PHP_FUNCTION(cal_from_jd)
  328. {
  329. long jd, cal;
  330. int month, day, year, dow;
  331. char date[16];
  332. struct cal_entry_t *calendar;
  333. if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "ll", &jd, &cal) == FAILURE) {
  334. RETURN_FALSE;
  335. }
  336. if (cal < 0 || cal >= CAL_NUM_CALS) {
  337. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld", cal);
  338. RETURN_FALSE;
  339. }
  340. calendar = &cal_conversion_table[cal];
  341. array_init(return_value);
  342. calendar->from_jd(jd, &year, &month, &day);
  343. snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
  344. add_assoc_string(return_value, "date", date, 1);
  345. add_assoc_long(return_value, "month", month);
  346. add_assoc_long(return_value, "day", day);
  347. add_assoc_long(return_value, "year", year);
  348. /* day of week */
  349. if (cal != CAL_JEWISH || year > 0) {
  350. dow = DayOfWeek(jd);
  351. add_assoc_long(return_value, "dow", dow);
  352. add_assoc_string(return_value, "abbrevdayname", DayNameShort[dow], 1);
  353. add_assoc_string(return_value, "dayname", DayNameLong[dow], 1);
  354. } else {
  355. add_assoc_null(return_value, "dow");
  356. add_assoc_string(return_value, "abbrevdayname", "", 1);
  357. add_assoc_string(return_value, "dayname", "", 1);
  358. }
  359. /* month name */
  360. if(cal == CAL_JEWISH) {
  361. /* special case for Jewish calendar */
  362. add_assoc_string(return_value, "abbrevmonth", (year > 0 ? JEWISH_MONTH_NAME(year)[month] : ""), 1);
  363. add_assoc_string(return_value, "monthname", (year > 0 ? JEWISH_MONTH_NAME(year)[month] : ""), 1);
  364. } else {
  365. add_assoc_string(return_value, "abbrevmonth", calendar->month_name_short[month], 1);
  366. add_assoc_string(return_value, "monthname", calendar->month_name_long[month], 1);
  367. }
  368. }
  369. /* }}} */
  370. /* {{{ proto string jdtogregorian(int juliandaycount)
  371. Converts a julian day count to a gregorian calendar date */
  372. PHP_FUNCTION(jdtogregorian)
  373. {
  374. long julday;
  375. int year, month, day;
  376. char date[16];
  377. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
  378. RETURN_FALSE;
  379. }
  380. SdnToGregorian(julday, &year, &month, &day);
  381. snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
  382. RETURN_STRING(date, 1);
  383. }
  384. /* }}} */
  385. /* {{{ proto int gregoriantojd(int month, int day, int year)
  386. Converts a gregorian calendar date to julian day count */
  387. PHP_FUNCTION(gregoriantojd)
  388. {
  389. long year, month, day;
  390. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
  391. RETURN_FALSE;
  392. }
  393. RETURN_LONG(GregorianToSdn(year, month, day));
  394. }
  395. /* }}} */
  396. /* {{{ proto string jdtojulian(int juliandaycount)
  397. Convert a julian day count to a julian calendar date */
  398. PHP_FUNCTION(jdtojulian)
  399. {
  400. long julday;
  401. int year, month, day;
  402. char date[16];
  403. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
  404. RETURN_FALSE;
  405. }
  406. SdnToJulian(julday, &year, &month, &day);
  407. snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
  408. RETURN_STRING(date, 1);
  409. }
  410. /* }}} */
  411. /* {{{ proto int juliantojd(int month, int day, int year)
  412. Converts a julian calendar date to julian day count */
  413. PHP_FUNCTION(juliantojd)
  414. {
  415. long year, month, day;
  416. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
  417. RETURN_FALSE;
  418. }
  419. RETURN_LONG(JulianToSdn(year, month, day));
  420. }
  421. /* }}} */
  422. /* {{{ heb_number_to_chars*/
  423. /*
  424. caution: the Hebrew format produces non unique result.
  425. for example both: year '5' and year '5000' produce 'ä'.
  426. use the numeric one for calculations.
  427. */
  428. static char *heb_number_to_chars(int n, int fl, char **ret)
  429. {
  430. char *p, old[18], *endofalafim;
  431. p = endofalafim = old;
  432. /*
  433. prevents the option breaking the jewish beliefs, and some other
  434. critical resources ;)
  435. */
  436. if (n > 9999 || n < 1) {
  437. *ret = NULL;
  438. return NULL;
  439. }
  440. /* alafim (thousands) case */
  441. if (n / 1000) {
  442. *p = alef_bet[n / 1000];
  443. p++;
  444. if (CAL_JEWISH_ADD_ALAFIM_GERESH & fl) {
  445. *p = '\'';
  446. p++;
  447. }
  448. if (CAL_JEWISH_ADD_ALAFIM & fl) {
  449. strcpy(p, " àìôéí ");
  450. p += 7;
  451. }
  452. endofalafim = p;
  453. n = n % 1000;
  454. }
  455. /* tav-tav (tav=400) case */
  456. while (n >= 400) {
  457. *p = alef_bet[22];
  458. p++;
  459. n -= 400;
  460. }
  461. /* meot (hundreads) case */
  462. if (n >= 100) {
  463. *p = alef_bet[18 + n / 100];
  464. p++;
  465. n = n % 100;
  466. }
  467. /* tet-vav & tet-zain case (special case for 15 and 16) */
  468. if (n == 15 || n == 16) {
  469. *p = alef_bet[9];
  470. p++;
  471. *p = alef_bet[n - 9];
  472. p++;
  473. } else {
  474. /* asarot (tens) case */
  475. if (n >= 10) {
  476. *p = alef_bet[9 + n / 10];
  477. p++;
  478. n = n % 10;
  479. }
  480. /* yehidot (ones) case */
  481. if (n > 0) {
  482. *p = alef_bet[n];
  483. p++;
  484. }
  485. }
  486. if (CAL_JEWISH_ADD_GERESHAYIM & fl) {
  487. switch (p - endofalafim) {
  488. case 0:
  489. break;
  490. case 1:
  491. *p = '\'';
  492. p++;
  493. break;
  494. default:
  495. *(p) = *(p - 1);
  496. *(p - 1) = '"';
  497. p++;
  498. }
  499. }
  500. *p = '\0';
  501. *ret = estrndup(old, (p - old) + 1);
  502. p = *ret;
  503. return p;
  504. }
  505. /* }}} */
  506. /* {{{ proto string jdtojewish(int juliandaycount [, bool hebrew [, int fl]])
  507. Converts a julian day count to a jewish calendar date */
  508. PHP_FUNCTION(jdtojewish)
  509. {
  510. long julday, fl = 0;
  511. zend_bool heb = 0;
  512. int year, month, day;
  513. char date[16], hebdate[32];
  514. char *dayp, *yearp;
  515. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|bl", &julday, &heb, &fl) == FAILURE) {
  516. RETURN_FALSE;
  517. }
  518. SdnToJewish(julday, &year, &month, &day);
  519. if (!heb) {
  520. snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
  521. RETURN_STRING(date, 1);
  522. } else {
  523. if (year <= 0 || year > 9999) {
  524. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Year out of range (0-9999).");
  525. RETURN_FALSE;
  526. }
  527. snprintf(hebdate, sizeof(hebdate), "%s %s %s", heb_number_to_chars(day, fl, &dayp), JEWISH_HEB_MONTH_NAME(year)[month], heb_number_to_chars(year, fl, &yearp));
  528. if (dayp) {
  529. efree(dayp);
  530. }
  531. if (yearp) {
  532. efree(yearp);
  533. }
  534. RETURN_STRING(hebdate, 1);
  535. }
  536. }
  537. /* }}} */
  538. /* {{{ proto int jewishtojd(int month, int day, int year)
  539. Converts a jewish calendar date to a julian day count */
  540. PHP_FUNCTION(jewishtojd)
  541. {
  542. long year, month, day;
  543. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
  544. RETURN_FALSE;
  545. }
  546. RETURN_LONG(JewishToSdn(year, month, day));
  547. }
  548. /* }}} */
  549. /* {{{ proto string jdtofrench(int juliandaycount)
  550. Converts a julian day count to a french republic calendar date */
  551. PHP_FUNCTION(jdtofrench)
  552. {
  553. long julday;
  554. int year, month, day;
  555. char date[16];
  556. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
  557. RETURN_FALSE;
  558. }
  559. SdnToFrench(julday, &year, &month, &day);
  560. snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
  561. RETURN_STRING(date, 1);
  562. }
  563. /* }}} */
  564. /* {{{ proto int frenchtojd(int month, int day, int year)
  565. Converts a french republic calendar date to julian day count */
  566. PHP_FUNCTION(frenchtojd)
  567. {
  568. long year, month, day;
  569. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
  570. RETURN_FALSE;
  571. }
  572. RETURN_LONG(FrenchToSdn(year, month, day));
  573. }
  574. /* }}} */
  575. /* {{{ proto mixed jddayofweek(int juliandaycount [, int mode])
  576. Returns name or number of day of week from julian day count */
  577. PHP_FUNCTION(jddayofweek)
  578. {
  579. long julday, mode = CAL_DOW_DAYNO;
  580. int day;
  581. char *daynamel, *daynames;
  582. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &julday, &mode) == FAILURE) {
  583. RETURN_FALSE;
  584. }
  585. day = DayOfWeek(julday);
  586. daynamel = DayNameLong[day];
  587. daynames = DayNameShort[day];
  588. switch (mode) {
  589. case CAL_DOW_LONG:
  590. RETURN_STRING(daynamel, 1);
  591. break;
  592. case CAL_DOW_SHORT:
  593. RETURN_STRING(daynames, 1);
  594. break;
  595. case CAL_DOW_DAYNO:
  596. default:
  597. RETURN_LONG(day);
  598. break;
  599. }
  600. }
  601. /* }}} */
  602. /* {{{ proto string jdmonthname(int juliandaycount, int mode)
  603. Returns name of month for julian day count */
  604. PHP_FUNCTION(jdmonthname)
  605. {
  606. long julday, mode;
  607. char *monthname = NULL;
  608. int month, day, year;
  609. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &julday, &mode) == FAILURE) {
  610. RETURN_FALSE;
  611. }
  612. switch (mode) {
  613. case CAL_MONTH_GREGORIAN_LONG: /* gregorian or julian month */
  614. SdnToGregorian(julday, &year, &month, &day);
  615. monthname = MonthNameLong[month];
  616. break;
  617. case CAL_MONTH_JULIAN_SHORT: /* gregorian or julian month */
  618. SdnToJulian(julday, &year, &month, &day);
  619. monthname = MonthNameShort[month];
  620. break;
  621. case CAL_MONTH_JULIAN_LONG: /* gregorian or julian month */
  622. SdnToJulian(julday, &year, &month, &day);
  623. monthname = MonthNameLong[month];
  624. break;
  625. case CAL_MONTH_JEWISH: /* jewish month */
  626. SdnToJewish(julday, &year, &month, &day);
  627. monthname = (year > 0 ? JEWISH_MONTH_NAME(year)[month] : "");
  628. break;
  629. case CAL_MONTH_FRENCH: /* french month */
  630. SdnToFrench(julday, &year, &month, &day);
  631. monthname = FrenchMonthName[month];
  632. break;
  633. default: /* default gregorian */
  634. case CAL_MONTH_GREGORIAN_SHORT: /* gregorian or julian month */
  635. SdnToGregorian(julday, &year, &month, &day);
  636. monthname = MonthNameShort[month];
  637. break;
  638. }
  639. RETURN_STRING(monthname, 1);
  640. }
  641. /* }}} */
  642. /*
  643. * Local variables:
  644. * tab-width: 4
  645. * c-basic-offset: 4
  646. * End:
  647. * vim600: sw=4 ts=4 fdm=marker
  648. * vim<600: sw=4 ts=4
  649. */