php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
calendar.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Shane Caraveo <shane@caraveo.com> |
14 | Colin Viebrock <colin@easydns.com> |
15 | Hartmut Holzgraefe <hholzgra@php.net> |
16 | Wez Furlong <wez@thebrainroom.com> |
17 +----------------------------------------------------------------------+
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include "php.h"
25#include "ext/standard/info.h"
26#include "php_calendar.h"
27#include "sdncal.h"
28
29#include <stdio.h>
30
31#ifdef PHP_WIN32
32/* This conflicts with a define in winnls.h, but that header is needed
33 to have GetACP(). */
34#undef CAL_GREGORIAN
35#endif
36
37/* this order must match the conversion table below */
45
46typedef zend_long (*cal_to_jd_func_t) (int month, int day, int year);
47typedef void (*cal_from_jd_func_t) (zend_long jd, int *year, int *month, int *day);
48typedef char *(*cal_as_string_func_t) (int year, int month, int day);
49
51 const char *name;
52 const char *symbol;
57 const char * const * month_name_short;
58 const char * const * month_name_long;
59};
60
61static const struct cal_entry_t cal_conversion_table[CAL_NUM_CALS] = {
62 {"Gregorian", "CAL_GREGORIAN", GregorianToSdn, SdnToGregorian, 12, 31,
64 {"Julian", "CAL_JULIAN", JulianToSdn, SdnToJulian, 12, 31,
66 {"Jewish", "CAL_JEWISH", JewishToSdn, SdnToJewish, 13, 30,
68 {"French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30,
70};
71
72#define JEWISH_MONTH_NAME(year) ((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthNameLeap:JewishMonthName)
73#define JEWISH_HEB_MONTH_NAME(year) ((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthHebNameLeap:JewishMonthHebName)
74
75/* For jddayofweek */
77
78/* For jdmonthname */
82};
83
84/* For heb_number_to_chars escape sequences of אבגדהוזחטיכלמנסעפצקרשת
85 ISO-8859-8 Hebrew alphabet */
86static const char alef_bet[25] = "0\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEB\xEC\xEE\xF0\xF1\xF2\xF4\xF6\xF7\xF8\xF9\xFA";
87
88#define CAL_JEWISH_ADD_ALAFIM_GERESH 0x2
89#define CAL_JEWISH_ADD_ALAFIM 0x4
90#define CAL_JEWISH_ADD_GERESHAYIM 0x8
91
92#include "calendar_arginfo.h"
93
96 "calendar",
97 ext_functions,
98 PHP_MINIT(calendar),
99 NULL,
100 NULL,
101 NULL,
102 PHP_MINFO(calendar),
105};
106
107#ifdef COMPILE_DL_CALENDAR
108ZEND_GET_MODULE(calendar)
109#endif
110
112{
113 register_calendar_symbols(module_number);
114
115 return SUCCESS;
116}
117
119{
121 php_info_print_table_row(2, "Calendar support", "enabled");
123}
124
125static void _php_cal_info(int cal, zval *ret)
126{
127 zval months, smonths;
128 int i;
129 const struct cal_entry_t *calendar;
130
131 calendar = &cal_conversion_table[cal];
133
134 array_init(&months);
135 array_init(&smonths);
136
137 for (i = 1; i <= calendar->num_months; i++) {
138 add_index_string(&months, i, calendar->month_name_long[i]);
139 add_index_string(&smonths, i, calendar->month_name_short[i]);
140 }
141
142 add_assoc_zval(ret, "months", &months);
143 add_assoc_zval(ret, "abbrevmonths", &smonths);
144 add_assoc_long(ret, "maxdaysinmonth", calendar->max_days_in_month);
145 add_assoc_string(ret, "calname", calendar->name);
146 add_assoc_string(ret, "calsymbol", calendar->symbol);
147
148}
149
150/* {{{ Returns information about a particular calendar */
152{
153 zend_long cal = -1;
154
155 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &cal) == FAILURE) {
157 }
158
159 if (cal == -1) {
160 int i;
161 zval val;
162
164
165 for (i = 0; i < CAL_NUM_CALS; i++) {
166 _php_cal_info(i, &val);
167 add_index_zval(return_value, i, &val);
168 }
169 return;
170 }
171
172 if (cal < 0 || cal >= CAL_NUM_CALS) {
173 zend_argument_value_error(1, "must be a valid calendar ID");
175 }
176
177 _php_cal_info(cal, return_value);
178}
179/* }}} */
180
181/* {{{ Returns the number of days in a month for a given year and calendar */
183{
184 zend_long cal, month, year;
185 const struct cal_entry_t *calendar;
186 zend_long sdn_start, sdn_next;
187
188 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &cal, &month, &year) == FAILURE) {
190 }
191
192 if (cal < 0 || cal >= CAL_NUM_CALS) {
193 zend_argument_value_error(1, "must be a valid calendar ID");
195 }
196
197 calendar = &cal_conversion_table[cal];
198
199 sdn_start = calendar->to_jd(year, month, 1);
200
201 if (sdn_start == 0) {
202 zend_value_error("Invalid date");
204 }
205
206 sdn_next = calendar->to_jd(year, 1 + month, 1);
207
208 if (sdn_next == 0) {
209 /* If the next month is invalid, then we need to try the first month of
210 * the next year, bearing in mind that the next year after 1 BCE is
211 * actually 1 AD and not 0. */
212 if (year == -1) {
213 sdn_next = calendar->to_jd(1, 1, 1);
214 }
215 else {
216 sdn_next = calendar->to_jd(year + 1, 1, 1);
217 if (cal == CAL_FRENCH && sdn_next == 0) {
218 /* The French calendar ends on 0014-13-05. */
219 sdn_next = 2380953;
220 }
221 }
222 }
223
224 RETURN_LONG(sdn_next - sdn_start);
225}
226/* }}} */
227
228/* {{{ Converts from a supported calendar to Julian Day Count */
230{
231 zend_long cal, month, day, year;
232
233 if (zend_parse_parameters(ZEND_NUM_ARGS(), "llll", &cal, &month, &day, &year) != SUCCESS) {
235 }
236
237 if (cal < 0 || cal >= CAL_NUM_CALS) {
238 zend_argument_value_error(1, "must be a valid calendar ID");
240 }
241
242 RETURN_LONG(cal_conversion_table[cal].to_jd(year, month, day));
243}
244/* }}} */
245
246/* {{{ Converts from Julian Day Count to a supported calendar and return extended information */
248{
249 zend_long jd, cal;
250 int month, day, year, dow;
251 const struct cal_entry_t *calendar;
252
253 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &jd, &cal) == FAILURE) {
255 }
256
257 if (cal < 0 || cal >= CAL_NUM_CALS) {
258 zend_argument_value_error(2, "must be a valid calendar ID");
260 }
261 calendar = &cal_conversion_table[cal];
262
264
265 calendar->from_jd(jd, &year, &month, &day);
266
267 add_assoc_str(return_value, "date",
268 zend_strpprintf(0, "%i/%i/%i", month, day, year));
269
270 add_assoc_long(return_value, "month", month);
271 add_assoc_long(return_value, "day", day);
272 add_assoc_long(return_value, "year", year);
273
274/* day of week */
275 if (cal != CAL_JEWISH || year > 0) {
276 dow = DayOfWeek(jd);
277 add_assoc_long(return_value, "dow", dow);
278 add_assoc_string(return_value, "abbrevdayname", DayNameShort[dow]);
279 add_assoc_string(return_value, "dayname", DayNameLong[dow]);
280 } else {
281 add_assoc_null(return_value, "dow");
282 add_assoc_string(return_value, "abbrevdayname", "");
283 add_assoc_string(return_value, "dayname", "");
284 }
285/* month name */
286 if(cal == CAL_JEWISH) {
287 /* special case for Jewish calendar */
288 add_assoc_string(return_value, "abbrevmonth", (year > 0 ? JEWISH_MONTH_NAME(year)[month] : ""));
289 add_assoc_string(return_value, "monthname", (year > 0 ? JEWISH_MONTH_NAME(year)[month] : ""));
290 } else {
291 add_assoc_string(return_value, "abbrevmonth", calendar->month_name_short[month]);
292 add_assoc_string(return_value, "monthname", calendar->month_name_long[month]);
293 }
294}
295/* }}} */
296
297/* {{{ Converts a julian day count to a gregorian calendar date */
299{
300 zend_long julday;
301 int year, month, day;
302
303 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &julday) == FAILURE) {
305 }
306
307 SdnToGregorian(julday, &year, &month, &day);
308
309 RETURN_NEW_STR(zend_strpprintf(0, "%i/%i/%i", month, day, year));
310}
311/* }}} */
312
313/* {{{ Converts a gregorian calendar date to julian day count */
315{
316 zend_long year, month, day;
317
318 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &month, &day, &year) == FAILURE) {
320 }
321
322 RETURN_LONG(GregorianToSdn(year, month, day));
323}
324/* }}} */
325
326/* {{{ Convert a julian day count to a julian calendar date */
328{
329 zend_long julday;
330 int year, month, day;
331
332 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &julday) == FAILURE) {
334 }
335
336 SdnToJulian(julday, &year, &month, &day);
337
338 RETURN_NEW_STR(zend_strpprintf(0, "%i/%i/%i", month, day, year));
339}
340/* }}} */
341
342/* {{{ Converts a julian calendar date to julian day count */
344{
345 zend_long year, month, day;
346
347 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &month, &day, &year) == FAILURE) {
349 }
350
351 RETURN_LONG(JulianToSdn(year, month, day));
352}
353/* }}} */
354
355/* {{{ heb_number_to_chars*/
356/*
357caution: the Hebrew format produces non-unique result.
358for example both: year '5' and year '5000' produce 'ה'.
359use the numeric one for calculations.
360 */
361static char *heb_number_to_chars(int n, int fl, char **ret)
362{
363 char *p, old[18], *endofalafim;
364
365 p = endofalafim = old;
366/*
367 prevents the option breaking the jewish beliefs, and some other
368 critical resources ;)
369 */
370 if (n > 9999 || n < 1) {
371 *ret = NULL;
372 return NULL;
373 }
374
375/* alafim (thousands) case */
376 if (n / 1000) {
377 *p = alef_bet[n / 1000];
378 p++;
379
381 *p = '\'';
382 p++;
383 }
384 if (CAL_JEWISH_ADD_ALAFIM & fl) {
385 /* Escape sequences of Hebrew characters in ISO-8859-8: אלפים */
386 strcpy(p, " \xE0\xEC\xF4\xE9\xED ");
387 p += 7;
388 }
389
390 endofalafim = p;
391 n = n % 1000;
392 }
393
394/* tav-tav (tav=400) case */
395 while (n >= 400) {
396 *p = alef_bet[22];
397 p++;
398 n -= 400;
399 }
400
401/* meot (hundreads) case */
402 if (n >= 100) {
403 *p = alef_bet[18 + n / 100];
404 p++;
405 n = n % 100;
406 }
407
408/* tet-vav & tet-zain case (special case for 15 and 16) */
409 if (n == 15 || n == 16) {
410 *p = alef_bet[9];
411 p++;
412 *p = alef_bet[n - 9];
413 p++;
414 } else {
415/* asarot (tens) case */
416 if (n >= 10) {
417 *p = alef_bet[9 + n / 10];
418 p++;
419 n = n % 10;
420 }
421
422/* yehidot (ones) case */
423 if (n > 0) {
424 *p = alef_bet[n];
425 p++;
426 }
427 }
428
429 if (CAL_JEWISH_ADD_GERESHAYIM & fl) {
430 switch (p - endofalafim) {
431 case 0:
432 break;
433 case 1:
434 *p = '\'';
435 p++;
436 break;
437 default:
438 *(p) = *(p - 1);
439 *(p - 1) = '"';
440 p++;
441 }
442 }
443
444 *p = '\0';
445 *ret = estrndup(old, (p - old) + 1);
446 p = *ret;
447 return p;
448}
449/* }}} */
450
451/* {{{ Converts a julian day count to a jewish calendar date */
453{
454 zend_long julday, fl = 0;
455 bool heb = 0;
456 int year, month, day;
457 char *dayp, *yearp;
458
459 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|bl", &julday, &heb, &fl) == FAILURE) {
461 }
462
463 SdnToJewish(julday, &year, &month, &day);
464 if (!heb) {
465 RETURN_NEW_STR(zend_strpprintf(0, "%i/%i/%i", month, day, year));
466 } else {
467 if (year <= 0 || year > 9999) {
468 zend_value_error("Year out of range (0-9999)");
470 }
471
472 RETVAL_NEW_STR(zend_strpprintf(0, "%s %s %s", heb_number_to_chars(day, fl, &dayp), JEWISH_HEB_MONTH_NAME(year)[month], heb_number_to_chars(year, fl, &yearp)));
473
474 if (dayp) {
475 efree(dayp);
476 }
477 if (yearp) {
478 efree(yearp);
479 }
480 }
481}
482/* }}} */
483
484/* {{{ Converts a jewish calendar date to a julian day count */
486{
487 zend_long year, month, day;
488
489 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &month, &day, &year) == FAILURE) {
491 }
492
493 RETURN_LONG(JewishToSdn(year, month, day));
494}
495/* }}} */
496
497/* {{{ Converts a julian day count to a french republic calendar date */
499{
500 zend_long julday;
501 int year, month, day;
502
503 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &julday) == FAILURE) {
505 }
506
507 SdnToFrench(julday, &year, &month, &day);
508
509 RETURN_NEW_STR(zend_strpprintf(0, "%i/%i/%i", month, day, year));
510}
511/* }}} */
512
513/* {{{ Converts a french republic calendar date to julian day count */
515{
516 zend_long year, month, day;
517
518 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &month, &day, &year) == FAILURE) {
520 }
521
522 RETURN_LONG(FrenchToSdn(year, month, day));
523}
524/* }}} */
525
526/* {{{ Returns name or number of day of week from julian day count */
528{
529 zend_long julday, mode = CAL_DOW_DAYNO;
530 int day;
531 const char *daynamel, *daynames;
532
533 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &julday, &mode) == FAILURE) {
535 }
536
537 day = DayOfWeek(julday);
538 daynamel = DayNameLong[day];
539 daynames = DayNameShort[day];
540
541 switch (mode) {
542 case CAL_DOW_LONG:
543 RETURN_STRING(daynamel);
544 break;
545 case CAL_DOW_SHORT:
546 RETURN_STRING(daynames);
547 break;
548 case CAL_DOW_DAYNO:
549 default:
550 RETURN_LONG(day);
551 break;
552 }
553}
554/* }}} */
555
556/* {{{ Returns name of month for julian day count */
558{
559 zend_long julday, mode;
560 const char *monthname = NULL;
561 int month, day, year;
562
563 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &julday, &mode) == FAILURE) {
565 }
566
567 switch (mode) {
568 case CAL_MONTH_GREGORIAN_LONG: /* gregorian or julian month */
569 SdnToGregorian(julday, &year, &month, &day);
570 monthname = MonthNameLong[month];
571 break;
572 case CAL_MONTH_JULIAN_SHORT: /* gregorian or julian month */
573 SdnToJulian(julday, &year, &month, &day);
574 monthname = MonthNameShort[month];
575 break;
576 case CAL_MONTH_JULIAN_LONG: /* gregorian or julian month */
577 SdnToJulian(julday, &year, &month, &day);
578 monthname = MonthNameLong[month];
579 break;
580 case CAL_MONTH_JEWISH: /* jewish month */
581 SdnToJewish(julday, &year, &month, &day);
582 monthname = (year > 0 ? JEWISH_MONTH_NAME(year)[month] : "");
583 break;
584 case CAL_MONTH_FRENCH: /* french month */
585 SdnToFrench(julday, &year, &month, &day);
586 monthname = FrenchMonthName[month];
587 break;
588 default: /* default gregorian */
589 case CAL_MONTH_GREGORIAN_SHORT: /* gregorian or julian month */
590 SdnToGregorian(julday, &year, &month, &day);
591 monthname = MonthNameShort[month];
592 break;
593 }
594
595 RETURN_STRING(monthname);
596}
597/* }}} */
jdtofrench(int $julian_day)
jdmonthname(int $julian_day, int $mode)
frenchtojd(int $month, int $day, int $year)
cal_info(int $calendar=-1)
jddayofweek(int $julian_day, int $mode=CAL_DOW_DAYNO)
cal_to_jd(int $calendar, int $month, int $day, int $year)
gregoriantojd(int $month, int $day, int $year)
jdtojulian(int $julian_day)
cal_days_in_month(int $calendar, int $month, int $year)
jdtojewish(int $julian_day, bool $hebrew=false, int $flags=0)
cal_from_jd(int $julian_day, int $calendar)
jewishtojd(int $month, int $day, int $year)
juliantojd(int $month, int $day, int $year)
jdtogregorian(int $julian_day)
const char *const DayNameLong[7]
Definition dow.c:50
const char *const DayNameShort[7]
Definition dow.c:39
int DayOfWeek(zend_long sdn)
Definition dow.c:33
@ CAL_DOW_SHORT
Definition calendar.c:76
@ CAL_DOW_LONG
Definition calendar.c:76
@ CAL_DOW_DAYNO
Definition calendar.c:76
zend_long(* cal_to_jd_func_t)(int month, int day, int year)
Definition calendar.c:46
#define CAL_JEWISH_ADD_ALAFIM
Definition calendar.c:89
#define CAL_JEWISH_ADD_ALAFIM_GERESH
Definition calendar.c:88
#define JEWISH_HEB_MONTH_NAME(year)
Definition calendar.c:73
@ CAL_MONTH_FRENCH
Definition calendar.c:81
@ CAL_MONTH_JEWISH
Definition calendar.c:80
@ CAL_MONTH_JULIAN_SHORT
Definition calendar.c:80
@ CAL_MONTH_JULIAN_LONG
Definition calendar.c:80
@ CAL_MONTH_GREGORIAN_LONG
Definition calendar.c:79
@ CAL_MONTH_GREGORIAN_SHORT
Definition calendar.c:79
void(* cal_from_jd_func_t)(zend_long jd, int *year, int *month, int *day)
Definition calendar.c:47
#define CAL_JEWISH_ADD_GERESHAYIM
Definition calendar.c:90
cal_name_type_t
Definition calendar.c:38
@ CAL_GREGORIAN
Definition calendar.c:39
@ CAL_NUM_CALS
Definition calendar.c:43
@ CAL_JULIAN
Definition calendar.c:40
@ CAL_JEWISH
Definition calendar.c:41
@ CAL_FRENCH
Definition calendar.c:42
#define JEWISH_MONTH_NAME(year)
Definition calendar.c:72
zend_module_entry calendar_module_entry
Definition calendar.c:94
zend_long n
Definition ffi.c:4979
zval * val
Definition ffi.c:4262
zend_long FrenchToSdn(int year, int month, int day)
Definition french.c:117
const char *const FrenchMonthName[14]
Definition french.c:134
void SdnToFrench(zend_long sdn, int *pYear, int *pMonth, int *pDay)
Definition french.c:95
char * mode
#define NULL
Definition gdcache.h:45
const char *const MonthNameShort[13]
Definition gregor.c:247
zend_long GregorianToSdn(int inputYear, int inputMonth, int inputDay)
Definition gregor.c:202
void SdnToGregorian(zend_long sdn, int *pYear, int *pMonth, int *pDay)
Definition gregor.c:137
const char *const MonthNameLong[13]
Definition gregor.c:264
#define SUCCESS
Definition hash_sha3.c:261
const char *const JewishMonthNameLeap[14]
Definition jewish.c:298
zend_long JewishToSdn(int year, int month, int day)
Definition jewish.c:698
void SdnToJewish(zend_long sdn, int *pYear, int *pMonth, int *pDay)
Definition jewish.c:559
void SdnToJulian(zend_long sdn, int *pYear, int *pMonth, int *pDay)
Definition julian.c:155
zend_long JulianToSdn(int inputYear, int inputMonth, int inputDay)
Definition julian.c:215
php_info_print_table_start()
Definition info.c:1064
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
Definition info.c:1074
#define PHP_FUNCTION
Definition php.h:364
#define PHP_MINFO
Definition php.h:396
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_MINFO_FUNCTION
Definition php.h:404
#define PHP_MINIT
Definition php.h:392
#define PHP_CALENDAR_VERSION
Definition php_calendar.h:8
p
Definition session.c:1105
Definition calendar.c:50
int max_days_in_month
Definition calendar.c:56
int num_months
Definition calendar.c:55
cal_from_jd_func_t from_jd
Definition calendar.c:54
cal_to_jd_func_t to_jd
Definition calendar.c:53
const char * symbol
Definition calendar.c:52
const char *const * month_name_long
Definition calendar.c:58
const char *const * month_name_short
Definition calendar.c:57
const char * name
Definition calendar.c:51
ZEND_API zend_string * zend_strpprintf(size_t max_len, const char *format,...)
Definition zend.c:353
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
ZEND_API void add_index_string(zval *arg, zend_ulong index, const char *str)
Definition zend_API.c:2087
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define RETVAL_NEW_STR(s)
Definition zend_API.h:1015
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_NEW_STR(s)
Definition zend_API.h:1041
#define RETURN_THROWS()
Definition zend_API.h:1060
#define array_init(arg)
Definition zend_API.h:537
#define estrndup(s, length)
Definition zend_alloc.h:165
#define efree(ptr)
Definition zend_alloc.h:155
struct _zval_struct zval
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
int32_t zend_long
Definition zend_long.h:42
#define STANDARD_MODULE_HEADER
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES
@ FAILURE
Definition zend_types.h:61
zval * return_value
zval * ret