easter.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. +----------------------------------------------------------------------+
  19. */
  20. /* $Id: */
  21. #include "php.h"
  22. #include "php_calendar.h"
  23. #include "sdncal.h"
  24. #include <time.h>
  25. static void _cal_easter(INTERNAL_FUNCTION_PARAMETERS, int gm)
  26. {
  27. /* based on code by Simon Kershaw, <webmaster@ely.anglican.org> */
  28. struct tm te;
  29. long year, golden, solar, lunar, pfm, dom, tmp, easter;
  30. long method = CAL_EASTER_DEFAULT;
  31. /* Default to the current year if year parameter is not given */
  32. {
  33. time_t a;
  34. struct tm b, *res;
  35. time(&a);
  36. res = php_localtime_r(&a, &b);
  37. if (!res) {
  38. year = 1900;
  39. } else {
  40. year = 1900 + b.tm_year;
  41. }
  42. }
  43. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
  44. "|ll", &year, &method) == FAILURE) {
  45. return;
  46. }
  47. if (gm && (year<1970 || year>2037)) { /* out of range for timestamps */
  48. php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function is only valid for years between 1970 and 2037 inclusive");
  49. RETURN_FALSE;
  50. }
  51. golden = (year % 19) + 1; /* the Golden number */
  52. if ((year <= 1582 && method != CAL_EASTER_ALWAYS_GREGORIAN) ||
  53. (year >= 1583 && year <= 1752 && method != CAL_EASTER_ROMAN && method != CAL_EASTER_ALWAYS_GREGORIAN) ||
  54. method == CAL_EASTER_ALWAYS_JULIAN) { /* JULIAN CALENDAR */
  55. dom = (year + (year/4) + 5) % 7; /* the "Dominical number" - finding a Sunday */
  56. if (dom < 0) {
  57. dom += 7;
  58. }
  59. pfm = (3 - (11*golden) - 7) % 30; /* uncorrected date of the Paschal full moon */
  60. if (pfm < 0) {
  61. pfm += 30;
  62. }
  63. } else { /* GREGORIAN CALENDAR */
  64. dom = (year + (year/4) - (year/100) + (year/400)) % 7; /* the "Domincal number" */
  65. if (dom < 0) {
  66. dom += 7;
  67. }
  68. solar = (year-1600)/100 - (year-1600)/400; /* the solar and lunar corrections */
  69. lunar = (((year-1400) / 100) * 8) / 25;
  70. pfm = (3 - (11*golden) + solar - lunar) % 30; /* uncorrected date of the Paschal full moon */
  71. if (pfm < 0) {
  72. pfm += 30;
  73. }
  74. }
  75. if ((pfm == 29) || (pfm == 28 && golden > 11)) { /* corrected date of the Paschal full moon */
  76. pfm--; /* - days after 21st March */
  77. }
  78. tmp = (4-pfm-dom) % 7;
  79. if (tmp < 0) {
  80. tmp += 7;
  81. }
  82. easter = pfm + tmp + 1; /* Easter as the number of days after 21st March */
  83. if (gm) { /* return a timestamp */
  84. te.tm_isdst = -1;
  85. te.tm_year = year-1900;
  86. te.tm_sec = 0;
  87. te.tm_min = 0;
  88. te.tm_hour = 0;
  89. if (easter < 11) {
  90. te.tm_mon = 2; /* March */
  91. te.tm_mday = easter+21;
  92. } else {
  93. te.tm_mon = 3; /* April */
  94. te.tm_mday = easter-10;
  95. }
  96. Z_LVAL_P(return_value) = mktime(&te);
  97. } else { /* return the days after March 21 */
  98. Z_LVAL_P(return_value) = easter;
  99. }
  100. Z_TYPE_P(return_value) = IS_LONG;
  101. }
  102. /* {{{ proto int easter_date([int year])
  103. Return the timestamp of midnight on Easter of a given year (defaults to current year) */
  104. PHP_FUNCTION(easter_date)
  105. {
  106. _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  107. }
  108. /* }}} */
  109. /* {{{ proto int easter_days([int year, [int method]])
  110. Return the number of days after March 21 that Easter falls on for a given year (defaults to current year) */
  111. PHP_FUNCTION(easter_days)
  112. {
  113. _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  114. }
  115. /* }}} */
  116. /*
  117. * Local variables:
  118. * tab-width: 4
  119. * c-basic-offset: 4
  120. * End:
  121. */