PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/protected/extensions/helpers/LunarDateHelper.php

https://bitbucket.org/hiscaler/firefly-ultimate
PHP | 287 lines | 168 code | 37 blank | 82 comment | 48 complexity | d97d89b395ad12c3e200455687aaa7a0 MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. /**
  3. * PHP 获取农历日期类
  4. * From http://www.codehorde.com/thread-21480-1-1.html
  5. */
  6. class LunarDateHelper {
  7. public $MIN_YEAR = 1891;
  8. public $MAX_YEAR = 2100;
  9. public $lunarInfo = array(array(0, 2, 9, 21936), array(6, 1, 30, 9656), array(0, 2, 17, 9584), array(0, 2, 6, 21168), array(5, 1, 26, 43344), array(0, 2, 13, 59728), array(0, 2, 2, 27296), array(3, 1, 22, 44368), array(0, 2, 10, 43856), array(8, 1, 30, 19304), array(0, 2, 19, 19168), array(0, 2, 8, 42352), array(5, 1, 29, 21096), array(0, 2, 16, 53856), array(0, 2, 4, 55632), array(4, 1, 25, 27304), array(0, 2, 13, 22176), array(0, 2, 2, 39632), array(2, 1, 22, 19176), array(0, 2, 10, 19168), array(6, 1, 30, 42200), array(0, 2, 18, 42192), array(0, 2, 6, 53840), array(5, 1, 26, 54568), array(0, 2, 14, 46400), array(0, 2, 3, 54944), array(2, 1, 23, 38608), array(0, 2, 11, 38320), array(7, 2, 1, 18872), array(0, 2, 20, 18800), array(0, 2, 8, 42160), array(5, 1, 28, 45656), array(0, 2, 16, 27216), array(0, 2, 5, 27968), array(4, 1, 24, 44456), array(0, 2, 13, 11104), array(0, 2, 2, 38256), array(2, 1, 23, 18808), array(0, 2, 10, 18800), array(6, 1, 30, 25776), array(0, 2, 17, 54432), array(0, 2, 6, 59984), array(5, 1, 26, 27976), array(0, 2, 14, 23248), array(0, 2, 4, 11104), array(3, 1, 24, 37744), array(0, 2, 11, 37600), array(7, 1, 31, 51560), array(0, 2, 19, 51536), array(0, 2, 8, 54432), array(6, 1, 27, 55888), array(0, 2, 15, 46416), array(0, 2, 5, 22176), array(4, 1, 25, 43736), array(0, 2, 13, 9680), array(0, 2, 2, 37584), array(2, 1, 22, 51544), array(0, 2, 10, 43344), array(7, 1, 29, 46248), array(0, 2, 17, 27808), array(0, 2, 6, 46416), array(5, 1, 27, 21928), array(0, 2, 14, 19872), array(0, 2, 3, 42416), array(3, 1, 24, 21176), array(0, 2, 12, 21168), array(8, 1, 31, 43344), array(0, 2, 18, 59728), array(0, 2, 8, 27296), array(6, 1, 28, 44368), array(0, 2, 15, 43856), array(0, 2, 5, 19296), array(4, 1, 25, 42352), array(0, 2, 13, 42352), array(0, 2, 2, 21088), array(3, 1, 21, 59696), array(0, 2, 9, 55632), array(7, 1, 30, 23208), array(0, 2, 17, 22176), array(0, 2, 6, 38608), array(5, 1, 27, 19176), array(0, 2, 15, 19152), array(0, 2, 3, 42192), array(4, 1, 23, 53864), array(0, 2, 11, 53840), array(8, 1, 31, 54568), array(0, 2, 18, 46400), array(0, 2, 7, 46752), array(6, 1, 28, 38608), array(0, 2, 16, 38320), array(0, 2, 5, 18864), array(4, 1, 25, 42168), array(0, 2, 13, 42160), array(10, 2, 2, 45656), array(0, 2, 20, 27216), array(0, 2, 9, 27968), array(6, 1, 29, 44448), array(0, 2, 17, 43872), array(0, 2, 6, 38256), array(5, 1, 27, 18808), array(0, 2, 15, 18800), array(0, 2, 4, 25776), array(3, 1, 23, 27216), array(0, 2, 10, 59984), array(8, 1, 31, 27432), array(0, 2, 19, 23232), array(0, 2, 7, 43872), array(5, 1, 28, 37736), array(0, 2, 16, 37600), array(0, 2, 5, 51552), array(4, 1, 24, 54440), array(0, 2, 12, 54432), array(0, 2, 1, 55888), array(2, 1, 22, 23208), array(0, 2, 9, 22176), array(7, 1, 29, 43736), array(0, 2, 18, 9680), array(0, 2, 7, 37584), array(5, 1, 26, 51544), array(0, 2, 14, 43344), array(0, 2, 3, 46240), array(4, 1, 23, 46416), array(0, 2, 10, 44368), array(9, 1, 31, 21928), array(0, 2, 19, 19360), array(0, 2, 8, 42416), array(6, 1, 28, 21176), array(0, 2, 16, 21168), array(0, 2, 5, 43312), array(4, 1, 25, 29864), array(0, 2, 12, 27296), array(0, 2, 1, 44368), array(2, 1, 22, 19880), array(0, 2, 10, 19296), array(6, 1, 29, 42352), array(0, 2, 17, 42208), array(0, 2, 6, 53856), array(5, 1, 26, 59696), array(0, 2, 13, 54576), array(0, 2, 3, 23200), array(3, 1, 23, 27472), array(0, 2, 11, 38608), array(11, 1, 31, 19176), array(0, 2, 19, 19152), array(0, 2, 8, 42192), array(6, 1, 28, 53848), array(0, 2, 15, 53840), array(0, 2, 4, 54560), array(5, 1, 24, 55968), array(0, 2, 12, 46496), array(0, 2, 1, 22224), array(2, 1, 22, 19160), array(0, 2, 10, 18864), array(7, 1, 30, 42168), array(0, 2, 17, 42160), array(0, 2, 6, 43600), array(5, 1, 26, 46376), array(0, 2, 14, 27936), array(0, 2, 2, 44448), array(3, 1, 23, 21936), array(0, 2, 11, 37744), array(8, 2, 1, 18808), array(0, 2, 19, 18800), array(0, 2, 8, 25776), array(6, 1, 28, 27216), array(0, 2, 15, 59984), array(0, 2, 4, 27424), array(4, 1, 24, 43872), array(0, 2, 12, 43744), array(0, 2, 2, 37600), array(3, 1, 21, 51568), array(0, 2, 9, 51552), array(7, 1, 29, 54440), array(0, 2, 17, 54432), array(0, 2, 5, 55888), array(5, 1, 26, 23208), array(0, 2, 14, 22176), array(0, 2, 3, 42704), array(4, 1, 23, 21224), array(0, 2, 11, 21200), array(8, 1, 31, 43352), array(0, 2, 19, 43344), array(0, 2, 7, 46240), array(6, 1, 27, 46416), array(0, 2, 15, 44368), array(0, 2, 5, 21920), array(4, 1, 24, 42448), array(0, 2, 12, 42416), array(0, 2, 2, 21168), array(3, 1, 22, 43320), array(0, 2, 9, 26928), array(7, 1, 29, 29336), array(0, 2, 17, 27296), array(0, 2, 6, 44368), array(5, 1, 26, 19880), array(0, 2, 14, 19296), array(0, 2, 3, 42352), array(4, 1, 24, 21104), array(0, 2, 10, 53856), array(8, 1, 30, 59696), array(0, 2, 18, 54560), array(0, 2, 7, 55968), array(6, 1, 27, 27472), array(0, 2, 15, 22224), array(0, 2, 5, 19168), array(4, 1, 25, 42216), array(0, 2, 12, 42192), array(0, 2, 1, 53584), array(2, 1, 21, 55592), array(0, 2, 9, 54560));
  10. /**
  11. * 将阳历转换为阴历
  12. * @param year 公历-年
  13. * @param month 公历-月
  14. * @param date 公历-日
  15. */
  16. function convertSolarToLunar($year, $month, $date) {
  17. //debugger;
  18. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  19. if ($year == $this->MIN_YEAR && $month <= 2 && $date <= 9) {
  20. return array(1891, '正月', '初一', '辛卯', 1, 1, '兔');
  21. }
  22. return $this->getLunarByBetween($year, $this->getDaysBetweenSolar($year, $month, $date, $yearData[1], $yearData[2]));
  23. }
  24. /**
  25. * 将阴历转换为阳历
  26. * @param year 阴历-年
  27. * @param month 阴历-月,闰月处理:例如如果当年闰五月,那么第二个五月就传六月,相当于阴历有13个月,只是有的时候第13个月的天数为0
  28. * @param date 阴历-日
  29. */
  30. function convertLunarToSolar($year, $month, $date) {
  31. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  32. $between = $this->getDaysBetweenLunar($year, $month, $date);
  33. $res = mktime(0, 0, 0, $yearData[1], $yearData[2], $year);
  34. $res = date('Y-m-d', $res + $between * 24 * 60 * 60);
  35. $day = split_date($res);
  36. $year = $day[0];
  37. $month = $day[1];
  38. $day = $day[2];
  39. return array($year, $month, $day);
  40. }
  41. /**
  42. * 判断是否是闰年
  43. * @param year
  44. */
  45. function isLeapYear($year) {
  46. return (($year % 4 == 0 && $year % 100 != 0) || ($year % 400 == 0));
  47. }
  48. /**
  49. * 获取干支纪年
  50. * @param year
  51. */
  52. function getLunarYearName($year) {
  53. $sky = array('庚', '辛', '壬', '癸', '甲', '乙', '丙', '丁', '戊', '己');
  54. $earth = array('申', '酉', '戌', '亥', '子', '丑', '寅', '卯', '辰', '巳', '午', '未');
  55. $year = $year . '';
  56. return $sky[$year{3}] . $earth[$year % 12];
  57. }
  58. /**
  59. * 根据阴历年获取生肖
  60. * @param year 阴历年
  61. */
  62. function getYearZodiac($year) {
  63. $zodiac = array('猴', '鸡', '狗', '猪', '鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊');
  64. return $zodiac[$year % 12];
  65. }
  66. /**
  67. * 获取阳历月份的天数
  68. * @param year 阳历-年
  69. * @param month 阳历-月
  70. */
  71. function getSolarMonthDays($year, $month) {
  72. $monthHash = array('1' => 31, '2' => $this->isLeapYear($year) ? 29 : 28, '3' => 31, '4' => 30, '5' => 31, '6' => 30, '7' => 31, '8' => 31, '9' => 30, '10' => 31, '11' => 30, '12' => 31);
  73. return $monthHash["$month"];
  74. }
  75. /**
  76. * 获取阴历月份的天数
  77. * @param year 阴历-年
  78. * @param month 阴历-月,从一月开始
  79. */
  80. function getLunarMonthDays($year, $month) {
  81. $monthData = $this->getLunarMonths($year);
  82. return $monthData[$month - 1];
  83. }
  84. /**
  85. * 获取阴历每月的天数的数组
  86. * @param year
  87. */
  88. function getLunarMonths($year) {
  89. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  90. $leapMonth = $yearData[0];
  91. $bit = decbin($yearData[3]);
  92. for ($i = 0; $i < strlen($bit); $i++) {
  93. $bitArray[$i] = substr($bit, $i, 1);
  94. }
  95. for ($k = 0, $klen = 16 - count($bitArray); $k < $klen; $k++) {
  96. array_unshift($bitArray, '0');
  97. }
  98. $bitArray = array_slice($bitArray, 0, ($leapMonth == 0 ? 12 : 13));
  99. for ($i = 0; $i < count($bitArray); $i++) {
  100. $bitArray[$i] = $bitArray[$i] + 29;
  101. }
  102. return $bitArray;
  103. }
  104. /**
  105. * 获取农历每年的天数
  106. * @param year 农历年份
  107. */
  108. function getLunarYearDays($year) {
  109. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  110. $monthArray = $this->getLunarYearMonths($year);
  111. $len = count($monthArray);
  112. return ($monthArray[$len - 1] == 0 ? $monthArray[$len - 2] : $monthArray[$len - 1]);
  113. }
  114. function getLunarYearMonths($year) {
  115. //debugger;
  116. $monthData = $this->getLunarMonths($year);
  117. $res = array();
  118. $temp = 0;
  119. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  120. $len = ($yearData[0] == 0 ? 12 : 13);
  121. for ($i = 0; $i < $len; $i++) {
  122. $temp = 0;
  123. for ($j = 0; $j <= $i; $j++) {
  124. $temp+=$monthData[$j];
  125. }
  126. array_push($res, $temp);
  127. }
  128. return $res;
  129. }
  130. /**
  131. * 获取闰月
  132. * @param year 阴历年份
  133. */
  134. function getLeapMonth($year) {
  135. $yearData = $this->lunarInfo[$year - $this->MIN_YEAR];
  136. return $yearData[0];
  137. }
  138. /**
  139. * 计算阴历日期与正月初一相隔的天数
  140. * @param year
  141. * @param month
  142. * @param date
  143. */
  144. function getDaysBetweenLunar($year, $month, $date) {
  145. $yearMonth = $this->getLunarMonths($year);
  146. $res = 0;
  147. for ($i = 1; $i < $month; $i++) {
  148. $res +=$yearMonth[$i - 1];
  149. }
  150. $res+=$date - 1;
  151. return $res;
  152. }
  153. /**
  154. * 计算2个阳历日期之间的天数
  155. * @param year 阳历年
  156. * @param cmonth
  157. * @param cdate
  158. * @param dmonth 阴历正月对应的阳历月份
  159. * @param ddate 阴历初一对应的阳历天数
  160. */
  161. function getDaysBetweenSolar($year, $cmonth, $cdate, $dmonth, $ddate) {
  162. $a = mktime(0, 0, 0, $cmonth, $cdate, $year);
  163. $b = mktime(0, 0, 0, $dmonth, $ddate, $year);
  164. return ceil(($a - $b) / 24 / 3600);
  165. }
  166. /**
  167. * 根据距离正月初一的天数计算阴历日期
  168. * @param year 阳历年
  169. * @param between 天数
  170. */
  171. function getLunarByBetween($year, $between) {
  172. //debugger;
  173. $lunarArray = array();
  174. $yearMonth = array();
  175. $t = 0;
  176. $e = 0;
  177. $leapMonth = 0;
  178. $m = '';
  179. if ($between == 0) {
  180. array_push($lunarArray, $year, '正月', '初一');
  181. $t = 1;
  182. $e = 1;
  183. } else {
  184. $year = $between > 0 ? $year : ($year - 1);
  185. $yearMonth = $this->getLunarYearMonths($year);
  186. $leapMonth = $this->getLeapMonth($year);
  187. $between = $between > 0 ? $between : ($this->getLunarYearDays($year) + $between);
  188. for ($i = 0; $i < 13; $i++) {
  189. if ($between == $yearMonth[$i]) {
  190. $t = $i + 2;
  191. $e = 1;
  192. break;
  193. } else if ($between < $yearMonth[$i]) {
  194. $t = $i + 1;
  195. $e = $between - (empty($yearMonth[$i - 1]) ? 0 : $yearMonth[$i - 1]) + 1;
  196. break;
  197. }
  198. }
  199. $m = ($leapMonth != 0 && $t == $leapMonth + 1) ? ('闰' . $this->getCapitalNum($t - 1, true)) : $this->getCapitalNum(($leapMonth != 0 && $leapMonth + 1 < $t ? ($t - 1) : $t), true);
  200. array_push($lunarArray, $year, $m, $this->getCapitalNum($e, false));
  201. }
  202. array_push($lunarArray, $this->getLunarYearName($year)); //天干地支
  203. array_push($lunarArray, $t, $e);
  204. array_push($lunarArray, $this->getYearZodiac($year)); //12生肖
  205. array_push($lunarArray, $leapMonth); //闰几月
  206. return $lunarArray;
  207. }
  208. /**
  209. * 获取数字的阴历叫法
  210. * @param num 数字
  211. * @param isMonth 是否是月份的数字
  212. */
  213. function getCapitalNum($num, $isMonth) {
  214. $isMonth = $isMonth || false;
  215. $dateHash = array('0' => '', '1' => '一', '2' => '二', '3' => '三', '4' => '四', '5' => '五', '6' => '六', '7' => '七', '8' => '八', '9' => '九', '10' => '十 ');
  216. $monthHash = array('0' => '', '1' => '正月', '2' => '二月', '3' => '三月', '4' => '四月', '5' => '五月', '6' => '六月', '7' => '七月', '8' => '八月', '9' => '九月', '10' => '十月', '11' => '冬月', '12' => '腊月');
  217. $res = '';
  218. if ($isMonth) {
  219. $res = $monthHash[$num];
  220. } else {
  221. if ($num <= 10) {
  222. $res = '初' . $dateHash[$num];
  223. } else if ($num > 10 && $num < 20) {
  224. $res = '十' . $dateHash[$num - 10];
  225. } else if ($num == 20) {
  226. $res = "二十";
  227. } else if ($num > 20 && $num < 30) {
  228. $res = "廿" . $dateHash[$num - 20];
  229. } else if ($num == 30) {
  230. $res = "三十";
  231. }
  232. }
  233. return $res;
  234. }
  235. /**
  236. * 将数字转换为中文
  237. * @param integer $number
  238. * @return string
  239. */
  240. function convertNumberToUppercaseDigits($number) {
  241. $digits = array('零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
  242. $res = '';
  243. $number = (string) $number;
  244. $max = strlen($number);
  245. for ($i = 0; $i < $max; $i++) {
  246. $res .= $digits[substr($number, $i, 1)];
  247. }
  248. return $res;
  249. }
  250. }