majiameng /
tools
| 1 | <?php |
||||||
| 2 | /* |
||||||
| 3 | * This file is part of the tinymeng/tools. |
||||||
| 4 | * (c) overtrue <[email protected]> |
||||||
| 5 | * This source file is subject to the MIT license that is bundled |
||||||
| 6 | * with this source code in the file LICENSE. |
||||||
| 7 | */ |
||||||
| 8 | namespace tinymeng\tools; |
||||||
| 9 | |||||||
| 10 | use DateTime; |
||||||
| 11 | use DateTimeZone; |
||||||
| 12 | use InvalidArgumentException; |
||||||
| 13 | |||||||
| 14 | /** |
||||||
| 15 | * Class Calendar. |
||||||
| 16 | * |
||||||
| 17 | * @author overtrue <[email protected]> |
||||||
| 18 | */ |
||||||
| 19 | class Calendar |
||||||
| 20 | { |
||||||
| 21 | /** |
||||||
| 22 | * 农历 1900-2100 的润大小信息. |
||||||
| 23 | * |
||||||
| 24 | * @var array |
||||||
| 25 | */ |
||||||
| 26 | protected $lunars = [ |
||||||
| 27 | 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909 |
||||||
| 28 | 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919 |
||||||
| 29 | 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929 |
||||||
| 30 | 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939 |
||||||
| 31 | 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949 |
||||||
| 32 | 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959 |
||||||
| 33 | 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969 |
||||||
| 34 | 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979 |
||||||
| 35 | 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989 |
||||||
| 36 | 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999 |
||||||
| 37 | 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009 |
||||||
| 38 | 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019 |
||||||
| 39 | 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 |
||||||
| 40 | 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039 |
||||||
| 41 | 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049 |
||||||
| 42 | 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059 |
||||||
| 43 | 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069 |
||||||
| 44 | 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079 |
||||||
| 45 | 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089 |
||||||
| 46 | 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099 |
||||||
| 47 | 0x0d520, // 2100 |
||||||
| 48 | ]; |
||||||
| 49 | |||||||
| 50 | /** |
||||||
| 51 | * 公历每个月份的天数表. |
||||||
| 52 | * |
||||||
| 53 | * @var array |
||||||
| 54 | */ |
||||||
| 55 | protected $solarMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
||||||
| 56 | |||||||
| 57 | /** |
||||||
| 58 | * 天干地支之天干速查表. |
||||||
| 59 | * |
||||||
| 60 | * @var array |
||||||
| 61 | */ |
||||||
| 62 | protected $gan = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; |
||||||
| 63 | |||||||
| 64 | /** |
||||||
| 65 | * 天干地支之天干速查表 <=> 色彩. |
||||||
| 66 | * |
||||||
| 67 | * @var array |
||||||
| 68 | */ |
||||||
| 69 | protected $colors = ['青', '青', '红', '红', '黄', '黄', '白', '白', '黑', '黑']; |
||||||
| 70 | |||||||
| 71 | /** |
||||||
| 72 | * 天干地支之天干速查表 <=> 五行. |
||||||
| 73 | * |
||||||
| 74 | * @var array |
||||||
| 75 | */ |
||||||
| 76 | protected $wuXing = ['木', '木', '火', '火', '土', '土', '金', '金', '水', '水']; |
||||||
| 77 | |||||||
| 78 | /** |
||||||
| 79 | * 地支 <=> 五行. |
||||||
| 80 | * |
||||||
| 81 | * @var array |
||||||
| 82 | */ |
||||||
| 83 | protected $zhiWuxing = ['水', '土', '木', '木', '土', '火', '火', '土', '金', '金', '土', '水']; |
||||||
| 84 | |||||||
| 85 | /** |
||||||
| 86 | * 天干地支之地支速查表. |
||||||
| 87 | * |
||||||
| 88 | * @var array |
||||||
| 89 | */ |
||||||
| 90 | protected $zhi = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; |
||||||
| 91 | |||||||
| 92 | /** |
||||||
| 93 | * 天干地支之地支速查表 <=> 生肖. |
||||||
| 94 | * |
||||||
| 95 | * @var array |
||||||
| 96 | */ |
||||||
| 97 | protected $animals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']; |
||||||
| 98 | |||||||
| 99 | /** |
||||||
| 100 | * 24节气速查表. |
||||||
| 101 | * |
||||||
| 102 | * @var array |
||||||
| 103 | */ |
||||||
| 104 | protected $solarTerm = [ |
||||||
| 105 | '小寒', '大寒', '立春', '雨水', '惊蛰', '春分', |
||||||
| 106 | '清明', '谷雨', '立夏', '小满', '芒种', '夏至', |
||||||
| 107 | '小暑', '大暑', '立秋', '处暑', '白露', '秋分', |
||||||
| 108 | '寒露', '霜降', '立冬', '小雪', '大雪', '冬至', |
||||||
| 109 | ]; |
||||||
| 110 | |||||||
| 111 | /** |
||||||
| 112 | * 1900-2100 各年的 24 节气日期速查表. |
||||||
| 113 | * |
||||||
| 114 | * @var array |
||||||
| 115 | */ |
||||||
| 116 | protected $solarTerms = [ |
||||||
| 117 | '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', |
||||||
| 118 | '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', |
||||||
| 119 | '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', |
||||||
| 120 | '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', |
||||||
| 121 | 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', |
||||||
| 122 | '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', |
||||||
| 123 | '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', |
||||||
| 124 | '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', |
||||||
| 125 | '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', |
||||||
| 126 | '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 127 | '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', |
||||||
| 128 | '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', |
||||||
| 129 | '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', |
||||||
| 130 | '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 131 | '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', |
||||||
| 132 | '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', |
||||||
| 133 | '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', |
||||||
| 134 | '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', |
||||||
| 135 | '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', |
||||||
| 136 | '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', |
||||||
| 137 | '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 138 | '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', |
||||||
| 139 | '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', |
||||||
| 140 | '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', |
||||||
| 141 | '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 142 | '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', |
||||||
| 143 | '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', |
||||||
| 144 | '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', |
||||||
| 145 | '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', |
||||||
| 146 | '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', |
||||||
| 147 | '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', |
||||||
| 148 | '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 149 | '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', |
||||||
| 150 | '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', |
||||||
| 151 | '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', |
||||||
| 152 | '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', |
||||||
| 153 | '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', |
||||||
| 154 | '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', |
||||||
| 155 | '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', |
||||||
| 156 | '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', |
||||||
| 157 | '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', |
||||||
| 158 | '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', |
||||||
| 159 | '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', |
||||||
| 160 | '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', |
||||||
| 161 | '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', |
||||||
| 162 | '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', |
||||||
| 163 | '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', |
||||||
| 164 | '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', |
||||||
| 165 | '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', |
||||||
| 166 | '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', |
||||||
| 167 | '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', |
||||||
| 168 | '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', |
||||||
| 169 | '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', |
||||||
| 170 | '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', |
||||||
| 171 | '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', |
||||||
| 172 | '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', |
||||||
| 173 | '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', |
||||||
| 174 | '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', |
||||||
| 175 | '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', |
||||||
| 176 | '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', |
||||||
| 177 | '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', |
||||||
| 178 | '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', |
||||||
| 179 | '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', |
||||||
| 180 | '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', |
||||||
| 181 | '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', |
||||||
| 182 | '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', |
||||||
| 183 | '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', |
||||||
| 184 | ]; |
||||||
| 185 | |||||||
| 186 | /** |
||||||
| 187 | * 数字转中文速查表. |
||||||
| 188 | * |
||||||
| 189 | * @var array |
||||||
| 190 | */ |
||||||
| 191 | protected $weekdayAlias = ['日', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']; |
||||||
| 192 | |||||||
| 193 | /** |
||||||
| 194 | * 日期转农历称呼速查表. |
||||||
| 195 | * |
||||||
| 196 | * @var array |
||||||
| 197 | */ |
||||||
| 198 | protected $dateAlias = ['初', '十', '廿', '卅']; |
||||||
| 199 | |||||||
| 200 | /** |
||||||
| 201 | * 月份转农历称呼速查表. |
||||||
| 202 | * |
||||||
| 203 | * @var array |
||||||
| 204 | */ |
||||||
| 205 | protected $monthAlias = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']; |
||||||
| 206 | |||||||
| 207 | /** |
||||||
| 208 | * 传入阳历年月日获得详细的公历、农历信息. |
||||||
| 209 | * |
||||||
| 210 | * @param int $year |
||||||
| 211 | * @param int $month |
||||||
| 212 | * @param int $day |
||||||
| 213 | * @param int $hour |
||||||
| 214 | * |
||||||
| 215 | * @return array |
||||||
| 216 | */ |
||||||
| 217 | public function solar($year, $month, $day, $hour = null) |
||||||
| 218 | { |
||||||
| 219 | $date = $this->makeDate("{$year}-{$month}-{$day}"); |
||||||
| 220 | $lunar = $this->solar2lunar($year, $month, $day, $hour); |
||||||
| 221 | $week = abs((int)$date->format('w')); // 0 ~ 6 修正 星期七 为 星期日 |
||||||
| 222 | |||||||
| 223 | return array_merge( |
||||||
| 224 | $lunar, |
||||||
| 225 | [ |
||||||
| 226 | 'gregorian_year' => (string) $year, |
||||||
| 227 | 'gregorian_month' => sprintf('%02d', $month), |
||||||
| 228 | 'gregorian_day' => sprintf('%02d', $day), |
||||||
| 229 | 'gregorian_hour' => !is_numeric($hour) || $hour < 0 || $hour > 23 ? null : sprintf('%02d', $hour), |
||||||
| 230 | 'week_no' => $week, // 在周日时将会传回 0 |
||||||
| 231 | 'week_name' => '星期'.$this->weekdayAlias[$week], |
||||||
| 232 | 'is_today' => 0 === $this->makeDate('now')->diff($date)->days, |
||||||
| 233 | 'constellation' => $this->toConstellation($month, $day), |
||||||
| 234 | 'is_same_year' => $lunar['lunar_year'] == $year ?: false, |
||||||
| 235 | ] |
||||||
| 236 | ); |
||||||
| 237 | } |
||||||
| 238 | |||||||
| 239 | /** |
||||||
| 240 | * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历信息. |
||||||
| 241 | * |
||||||
| 242 | * @param int $year lunar year |
||||||
| 243 | * @param int $month lunar month |
||||||
| 244 | * @param int $day lunar day |
||||||
| 245 | * @param bool $isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] |
||||||
| 246 | * @param int $hour birth hour.[0~23] |
||||||
| 247 | * |
||||||
| 248 | * @return array |
||||||
| 249 | */ |
||||||
| 250 | public function lunar($year, $month, $day, $isLeapMonth = false, $hour = null) |
||||||
| 251 | { |
||||||
| 252 | $solar = $this->lunar2solar($year, $month, $day, $isLeapMonth); |
||||||
| 253 | |||||||
| 254 | return $this->solar($solar['solar_year'], $solar['solar_month'], $solar['solar_day'], $hour); |
||||||
| 255 | } |
||||||
| 256 | |||||||
| 257 | /** |
||||||
| 258 | * 返回农历指定年的总天数. |
||||||
| 259 | * |
||||||
| 260 | * @param int $year |
||||||
| 261 | * |
||||||
| 262 | * @return int |
||||||
| 263 | */ |
||||||
| 264 | public function daysOfYear($year) |
||||||
| 265 | { |
||||||
| 266 | $sum = 348; |
||||||
| 267 | |||||||
| 268 | for ($i = 0x8000; $i > 0x8; $i >>= 1) { |
||||||
| 269 | $sum += ($this->lunars[$year - 1900] & $i) ? 1 : 0; |
||||||
| 270 | } |
||||||
| 271 | |||||||
| 272 | return $sum + $this->leapDays($year); |
||||||
| 273 | } |
||||||
| 274 | |||||||
| 275 | /** |
||||||
| 276 | * 返回农历指定年的总月数. |
||||||
| 277 | * |
||||||
| 278 | * @param int $year |
||||||
| 279 | * |
||||||
| 280 | * @return int |
||||||
| 281 | */ |
||||||
| 282 | public function monthsOfYear($year) |
||||||
| 283 | { |
||||||
| 284 | return 0 < $this->leapMonth($year) ? 13 : 12; |
||||||
| 285 | } |
||||||
| 286 | |||||||
| 287 | /** |
||||||
| 288 | * 返回农历 y 年闰月是哪个月;若 y 年没有闰月 则返回0. |
||||||
| 289 | * |
||||||
| 290 | * @param int $year |
||||||
| 291 | * |
||||||
| 292 | * @return int |
||||||
| 293 | */ |
||||||
| 294 | public function leapMonth($year) |
||||||
| 295 | { |
||||||
| 296 | // 闰字编码 \u95f0 |
||||||
| 297 | return $this->lunars[$year - 1900] & 0xf; |
||||||
| 298 | } |
||||||
| 299 | |||||||
| 300 | /** |
||||||
| 301 | * 返回农历y年闰月的天数 若该年没有闰月则返回 0. |
||||||
| 302 | * |
||||||
| 303 | * @param int $year |
||||||
| 304 | * |
||||||
| 305 | * @return int |
||||||
| 306 | */ |
||||||
| 307 | public function leapDays($year) |
||||||
| 308 | { |
||||||
| 309 | if ($this->leapMonth($year)) { |
||||||
| 310 | return ($this->lunars[$year - 1900] & 0x10000) ? 30 : 29; |
||||||
| 311 | } |
||||||
| 312 | |||||||
| 313 | return 0; |
||||||
| 314 | } |
||||||
| 315 | |||||||
| 316 | /** |
||||||
| 317 | * 返回农历 y 年 m 月(非闰月)的总天数,计算 m 为闰月时的天数请使用 leapDays 方法. |
||||||
| 318 | * |
||||||
| 319 | * @param int $year |
||||||
| 320 | * @param int $month |
||||||
| 321 | * |
||||||
| 322 | * @return int |
||||||
| 323 | */ |
||||||
| 324 | public function lunarDays($year, $month) |
||||||
| 325 | { |
||||||
| 326 | // 月份参数从 1 至 12,参数错误返回 -1 |
||||||
| 327 | if ($month > 12 || $month < 1) { |
||||||
| 328 | return -1; |
||||||
| 329 | } |
||||||
| 330 | |||||||
| 331 | return ($this->lunars[$year - 1900] & (0x10000 >> $month)) ? 30 : 29; |
||||||
| 332 | } |
||||||
| 333 | |||||||
| 334 | /** |
||||||
| 335 | * 返回公历 y 年 m 月的天数. |
||||||
| 336 | * |
||||||
| 337 | * @param int $year |
||||||
| 338 | * @param int $month |
||||||
| 339 | * |
||||||
| 340 | * @return int |
||||||
| 341 | */ |
||||||
| 342 | public function solarDays($year, $month) |
||||||
| 343 | { |
||||||
| 344 | // 若参数错误 返回-1 |
||||||
| 345 | if ($month > 12 || $month < 1) { |
||||||
| 346 | return -1; |
||||||
| 347 | } |
||||||
| 348 | |||||||
| 349 | $ms = $month - 1; |
||||||
| 350 | |||||||
| 351 | if (1 == $ms) { // 2 月份的闰平规律测算后确认返回 28 或 29 |
||||||
| 352 | return ((0 === $year % 4) && (0 !== $year % 100) || (0 === $year % 400)) ? 29 : 28; |
||||||
| 353 | } |
||||||
| 354 | |||||||
| 355 | return $this->solarMonth[$ms]; |
||||||
| 356 | } |
||||||
| 357 | |||||||
| 358 | /** |
||||||
| 359 | * 农历年份转换为干支纪年. |
||||||
| 360 | * |
||||||
| 361 | * @param int $lunarYear |
||||||
| 362 | * @param null|int $termIndex |
||||||
| 363 | * |
||||||
| 364 | * @return string |
||||||
| 365 | */ |
||||||
| 366 | public function ganZhiYear($lunarYear, $termIndex = null) |
||||||
| 367 | { |
||||||
| 368 | /** |
||||||
| 369 | * 据维基百科干支词条:『在西历新年后,华夏新年或干支历新年之前,则续用上一年之干支』 |
||||||
| 370 | * 所以干支年份应该不需要根据节气校正,为免影响现有系统,此处暂时保留原有逻辑 |
||||||
| 371 | * https://zh.wikipedia.org/wiki/%E5%B9%B2%E6%94%AF. |
||||||
| 372 | * |
||||||
| 373 | * 即使考虑节气,有的年份没有立春,有的年份有两个立春,此处逻辑仍不能处理该特殊情况 |
||||||
| 374 | */ |
||||||
| 375 | $adjust = null !== $termIndex && 3 > $termIndex ? 1 : 0; |
||||||
| 376 | |||||||
| 377 | $ganKey = ($lunarYear + $adjust - 4) % 10; |
||||||
| 378 | $zhiKey = ($lunarYear + $adjust - 4) % 12; |
||||||
| 379 | |||||||
| 380 | return $this->gan[$ganKey].$this->zhi[$zhiKey]; |
||||||
| 381 | } |
||||||
| 382 | |||||||
| 383 | /** |
||||||
| 384 | * 公历月、日判断所属星座. |
||||||
| 385 | * |
||||||
| 386 | * @param int $gregorianMonth |
||||||
| 387 | * @param int $gregorianDay |
||||||
| 388 | * |
||||||
| 389 | * @return string |
||||||
| 390 | */ |
||||||
| 391 | public function toConstellation($gregorianMonth, $gregorianDay) |
||||||
| 392 | { |
||||||
| 393 | $constellations = '魔羯水瓶双鱼白羊金牛双子巨蟹狮子处女天秤天蝎射手魔羯'; |
||||||
| 394 | $arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]; |
||||||
| 395 | |||||||
| 396 | return mb_substr( |
||||||
| 397 | $constellations, |
||||||
| 398 | $gregorianMonth * 2 - ($gregorianDay < $arr[$gregorianMonth - 1] ? 2 : 0), |
||||||
| 399 | 2, |
||||||
| 400 | 'UTF-8' |
||||||
| 401 | ); |
||||||
| 402 | } |
||||||
| 403 | |||||||
| 404 | /** |
||||||
| 405 | * 传入offset偏移量返回干支. |
||||||
| 406 | * |
||||||
| 407 | * @param int $offset 相对甲子的偏移量 |
||||||
| 408 | * |
||||||
| 409 | * @return string |
||||||
| 410 | */ |
||||||
| 411 | public function toGanZhi($offset) |
||||||
| 412 | { |
||||||
| 413 | return $this->gan[$offset % 10].$this->zhi[$offset % 12]; |
||||||
| 414 | } |
||||||
| 415 | |||||||
| 416 | /** |
||||||
| 417 | * 传入公历年获得该年第n个节气的公历日期 |
||||||
| 418 | * |
||||||
| 419 | * @param int $year 公历年(1900-2100); |
||||||
| 420 | * @param int $no 二十四节气中的第几个节气(1~24);从n=1(小寒)算起 |
||||||
| 421 | * |
||||||
| 422 | * @return int |
||||||
| 423 | * |
||||||
| 424 | * @example |
||||||
| 425 | * <pre> |
||||||
| 426 | * $_24 = $this->getTerm(1987,3) ;// _24 = 4; 意即 1987 年 2 月 4 日立春 |
||||||
| 427 | * </pre> |
||||||
| 428 | */ |
||||||
| 429 | public function getTerm($year, $no) |
||||||
| 430 | { |
||||||
| 431 | if ($year < 1900 || $year > 2100) { |
||||||
| 432 | return -1; |
||||||
| 433 | } |
||||||
| 434 | if ($no < 1 || $no > 24) { |
||||||
| 435 | return -1; |
||||||
| 436 | } |
||||||
| 437 | $solarTermsOfYear = array_map('hexdec', (array)str_split($this->solarTerms[$year - 1900], 5)); |
||||||
| 438 | $positions = [ |
||||||
| 439 | 0 => [0, 1], |
||||||
| 440 | 1 => [1, 2], |
||||||
| 441 | 2 => [3, 1], |
||||||
| 442 | 3 => [4, 2], |
||||||
| 443 | ]; |
||||||
| 444 | $group = intval(($no - 1) / 4); |
||||||
| 445 | list($offset, $length) = $positions[($no - 1) % 4]; |
||||||
| 446 | |||||||
| 447 | return substr($solarTermsOfYear[$group], $offset, $length); |
||||||
| 448 | } |
||||||
| 449 | |||||||
| 450 | public function toChinaYear($year) |
||||||
| 451 | { |
||||||
| 452 | if (!is_numeric($year)) { |
||||||
| 453 | throw new InvalidArgumentException("错误的年份:{$year}"); |
||||||
| 454 | } |
||||||
| 455 | $lunarYear = ''; |
||||||
| 456 | $year = (string) $year; |
||||||
| 457 | for ($i = 0, $l = strlen($year); $i < $l; ++$i) { |
||||||
| 458 | $lunarYear .= '0' !== $year[$i] ? $this->weekdayAlias[$year[$i]] : '零'; |
||||||
| 459 | } |
||||||
| 460 | |||||||
| 461 | return $lunarYear; |
||||||
| 462 | } |
||||||
| 463 | |||||||
| 464 | /** |
||||||
| 465 | * 传入农历数字月份返回汉语通俗表示法. |
||||||
| 466 | * |
||||||
| 467 | * @param int $month |
||||||
| 468 | * |
||||||
| 469 | * @return string |
||||||
| 470 | */ |
||||||
| 471 | public function toChinaMonth($month) |
||||||
| 472 | { |
||||||
| 473 | // 若参数错误 返回 -1 |
||||||
| 474 | if ($month > 12 || $month < 1) { |
||||||
| 475 | throw new InvalidArgumentException("错误的月份:{$month}"); |
||||||
| 476 | } |
||||||
| 477 | |||||||
| 478 | return $this->monthAlias[abs($month) - 1].'月'; |
||||||
| 479 | } |
||||||
| 480 | |||||||
| 481 | /** |
||||||
| 482 | * 传入农历日期数字返回汉字表示法. |
||||||
| 483 | * |
||||||
| 484 | * @param int $day |
||||||
| 485 | * |
||||||
| 486 | * @return string |
||||||
| 487 | */ |
||||||
| 488 | public function toChinaDay($day) |
||||||
| 489 | { |
||||||
| 490 | switch ($day) { |
||||||
| 491 | case 10: |
||||||
| 492 | return '初十'; |
||||||
| 493 | case 20: |
||||||
| 494 | return '二十'; |
||||||
| 495 | case 30: |
||||||
| 496 | return '三十'; |
||||||
| 497 | default: |
||||||
| 498 | return $this->dateAlias[intval($day / 10)].$this->weekdayAlias[$day % 10]; |
||||||
| 499 | } |
||||||
| 500 | } |
||||||
| 501 | |||||||
| 502 | /** |
||||||
| 503 | * 年份转生肖. |
||||||
| 504 | * |
||||||
| 505 | * 仅能大致转换, 精确划分生肖分界线是 “立春”. |
||||||
| 506 | * |
||||||
| 507 | * @param int $year |
||||||
| 508 | * @param null|int $termIndex |
||||||
| 509 | * |
||||||
| 510 | * @return string |
||||||
| 511 | */ |
||||||
| 512 | public function getAnimal($year, $termIndex = null) |
||||||
| 513 | { |
||||||
| 514 | // 认为此逻辑不需要,详情参见 ganZhiYear 相关注释 |
||||||
| 515 | $adjust = null !== $termIndex && 3 > $termIndex ? 1 : 0; |
||||||
| 516 | |||||||
| 517 | $animalIndex = ($year + $adjust - 4) % 12; |
||||||
| 518 | |||||||
| 519 | return $this->animals[$animalIndex]; |
||||||
| 520 | } |
||||||
| 521 | |||||||
| 522 | /** |
||||||
| 523 | * 干支转色彩. |
||||||
| 524 | * |
||||||
| 525 | * @param $ganZhi |
||||||
| 526 | * |
||||||
| 527 | * @return string |
||||||
| 528 | */ |
||||||
| 529 | protected function getColor($ganZhi) |
||||||
| 530 | { |
||||||
| 531 | if (!$ganZhi) { |
||||||
| 532 | return null; |
||||||
| 533 | } |
||||||
| 534 | |||||||
| 535 | $gan = substr($ganZhi, 0, 3); |
||||||
| 536 | |||||||
| 537 | if (!$gan) { |
||||||
| 538 | return null; |
||||||
| 539 | } |
||||||
| 540 | |||||||
| 541 | return $this->colors[array_search($gan, $this->gan)]; |
||||||
| 542 | } |
||||||
| 543 | |||||||
| 544 | /** |
||||||
| 545 | * 干支转五行. |
||||||
| 546 | * |
||||||
| 547 | * @param $ganZhi |
||||||
| 548 | * |
||||||
| 549 | * @return string |
||||||
| 550 | */ |
||||||
| 551 | protected function getWuXing($ganZhi) |
||||||
| 552 | { |
||||||
| 553 | if (!$ganZhi) { |
||||||
| 554 | return null; |
||||||
| 555 | } |
||||||
| 556 | |||||||
| 557 | $gan = substr($ganZhi, 0, 3); |
||||||
| 558 | $zhi = substr($ganZhi, 3); |
||||||
| 559 | |||||||
| 560 | if (!$gan || !$zhi) { |
||||||
| 561 | return null; |
||||||
| 562 | } |
||||||
| 563 | |||||||
| 564 | $wGan = $this->wuXing[array_search($gan, $this->gan)]; |
||||||
| 565 | $wZhi = $this->zhiWuxing[array_search($zhi, $this->zhi)]; |
||||||
| 566 | |||||||
| 567 | return $wGan.$wZhi; |
||||||
| 568 | } |
||||||
| 569 | |||||||
| 570 | /** |
||||||
| 571 | * 阳历转阴历. |
||||||
| 572 | * |
||||||
| 573 | * @param int $year |
||||||
| 574 | * @param int $month |
||||||
| 575 | * @param int $day |
||||||
| 576 | * @param int $hour |
||||||
| 577 | * |
||||||
| 578 | * @return array |
||||||
| 579 | */ |
||||||
| 580 | public function solar2lunar($year, $month, $day, $hour = null) |
||||||
| 581 | { |
||||||
| 582 | if (23 == $hour) { |
||||||
| 583 | // 23点过后算子时,农历以子时为一天的起始 |
||||||
| 584 | $date = $this->makeDate("{$year}-{$month}-{$day} +1day"); |
||||||
| 585 | } else { |
||||||
| 586 | $date = $this->makeDate("{$year}-{$month}-{$day}"); |
||||||
| 587 | } |
||||||
| 588 | |||||||
| 589 | list($year, $month, $day) = explode('-', $date->format('Y-n-j')); |
||||||
| 590 | |||||||
| 591 | // 参数区间1900.1.31~2100.12.31 |
||||||
| 592 | if ($year < 1900 || $year > 2100) { |
||||||
| 593 | throw new InvalidArgumentException("不支持的年份:{$year}"); |
||||||
| 594 | } |
||||||
| 595 | |||||||
| 596 | // 年份限定、上限 |
||||||
| 597 | if (1900 == $year && 1 == $month && $day < 31) { |
||||||
| 598 | throw new InvalidArgumentException("不支持的日期:{$year}-{$month}-{$day}"); |
||||||
| 599 | } |
||||||
| 600 | |||||||
| 601 | $offset = (int)$this->dateDiff($date, '1900-01-31')->days; |
||||||
| 602 | |||||||
| 603 | for ($i = 1900; $i < 2101 && $offset > 0; ++$i) { |
||||||
| 604 | $daysOfYear = $this->daysOfYear($i); |
||||||
| 605 | $offset -= $daysOfYear; |
||||||
| 606 | } |
||||||
| 607 | |||||||
| 608 | if ($offset < 0) { |
||||||
| 609 | $offset += $daysOfYear; |
||||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||||||
| 610 | --$i; |
||||||
| 611 | } |
||||||
| 612 | |||||||
| 613 | // 农历年 |
||||||
| 614 | $lunarYear = $i; |
||||||
| 615 | |||||||
| 616 | $leap = $this->leapMonth($i); // 闰哪个月 |
||||||
| 617 | $isLeap = false; |
||||||
| 618 | |||||||
| 619 | // 用当年的天数 offset,逐个减去每月(农历)的天数,求出当天是本月的第几天 |
||||||
| 620 | for ($i = 1; $i < 13 && $offset > 0; ++$i) { |
||||||
| 621 | // 闰月 |
||||||
| 622 | if ($leap > 0 && $i == ($leap + 1) && !$isLeap) { |
||||||
| 623 | --$i; |
||||||
| 624 | $isLeap = true; |
||||||
| 625 | $daysOfMonth = $this->leapDays($lunarYear); // 计算农历月天数 |
||||||
| 626 | } else { |
||||||
| 627 | $daysOfMonth = $this->lunarDays($lunarYear, $i); // 计算农历普通月天数 |
||||||
| 628 | } |
||||||
| 629 | |||||||
| 630 | // 解除闰月 |
||||||
| 631 | if (true === $isLeap && $i == ($leap + 1)) { |
||||||
| 632 | $isLeap = false; |
||||||
| 633 | } |
||||||
| 634 | |||||||
| 635 | $offset -= $daysOfMonth; |
||||||
| 636 | } |
||||||
| 637 | // offset为0时,并且刚才计算的月份是闰月,要校正 |
||||||
| 638 | if (0 === $offset && $leap > 0 && $i == $leap + 1) { |
||||||
| 639 | if ($isLeap) { |
||||||
| 640 | $isLeap = false; |
||||||
| 641 | } else { |
||||||
| 642 | $isLeap = true; |
||||||
| 643 | --$i; |
||||||
| 644 | } |
||||||
| 645 | } |
||||||
| 646 | |||||||
| 647 | if ($offset < 0) { |
||||||
| 648 | $offset += $daysOfMonth; |
||||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
| 649 | --$i; |
||||||
| 650 | } |
||||||
| 651 | |||||||
| 652 | // 农历月 |
||||||
| 653 | $lunarMonth = $i; |
||||||
| 654 | |||||||
| 655 | // 农历日 |
||||||
| 656 | $lunarDay = $offset + 1; |
||||||
| 657 | |||||||
| 658 | // 月柱 1900 年 1 月小寒以前为 丙子月(60进制12) |
||||||
| 659 | $firstNode = $this->getTerm($year, ($month * 2 - 1)); // 返回当月「节气」为几日开始 |
||||||
|
0 ignored issues
–
show
$year of type string is incompatible with the type integer expected by parameter $year of tinymeng\tools\Calendar::getTerm().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 660 | $secondNode = $this->getTerm($year, ($month * 2)); // 返回当月「节气」为几日开始 |
||||||
| 661 | |||||||
| 662 | // 依据 12 节气修正干支月 |
||||||
| 663 | $ganZhiMonth = $this->toGanZhi(($year - 1900) * 12 + $month + 11); |
||||||
| 664 | |||||||
| 665 | if ($day >= $firstNode) { |
||||||
| 666 | $ganZhiMonth = $this->toGanZhi(($year - 1900) * 12 + $month + 12); |
||||||
| 667 | } |
||||||
| 668 | |||||||
| 669 | // 获取该天的节气 |
||||||
| 670 | $termIndex = null; |
||||||
| 671 | if ($firstNode == $day) { |
||||||
| 672 | $termIndex = $month * 2 - 2; |
||||||
| 673 | } |
||||||
| 674 | |||||||
| 675 | if ($secondNode == $day) { |
||||||
| 676 | $termIndex = $month * 2 - 1; |
||||||
| 677 | } |
||||||
| 678 | |||||||
| 679 | $term = null !== $termIndex ? $this->solarTerm[$termIndex] : null; |
||||||
| 680 | |||||||
| 681 | // 日柱 当月一日与 1900/1/1 相差天数 |
||||||
| 682 | $dayCyclical = $this->dateDiff("{$year}-{$month}-01", '1900-01-01')->days + 10; |
||||||
| 683 | $dayCyclical += $day - 1; |
||||||
| 684 | $ganZhiDay = $this->toGanZhi($dayCyclical); |
||||||
| 685 | |||||||
| 686 | // 时柱和时辰 |
||||||
| 687 | list($ganZhiHour, $lunarHour, $hour) = $this->ganZhiHour($hour, $dayCyclical); |
||||||
| 688 | |||||||
| 689 | $ganZhiYear = $this->ganZhiYear($lunarYear, $termIndex); |
||||||
| 690 | |||||||
| 691 | return [ |
||||||
| 692 | 'lunar_year' => (string) $lunarYear, |
||||||
| 693 | 'lunar_month' => sprintf('%02d', $lunarMonth), |
||||||
| 694 | 'lunar_day' => sprintf('%02d', $lunarDay), |
||||||
| 695 | 'lunar_hour' => $hour, |
||||||
| 696 | 'lunar_year_chinese' => $this->toChinaYear($lunarYear), |
||||||
| 697 | 'lunar_month_chinese' => ($isLeap ? '闰' : '').$this->toChinaMonth($lunarMonth), |
||||||
| 698 | 'lunar_day_chinese' => $this->toChinaDay($lunarDay), |
||||||
| 699 | 'lunar_hour_chinese' => $lunarHour, |
||||||
| 700 | 'ganzhi_year' => $ganZhiYear, |
||||||
| 701 | 'ganzhi_month' => $ganZhiMonth, |
||||||
| 702 | 'ganzhi_day' => $ganZhiDay, |
||||||
| 703 | 'ganzhi_hour' => $ganZhiHour, |
||||||
| 704 | 'wuxing_year' => $this->getWuXing($ganZhiYear), |
||||||
| 705 | 'wuxing_month' => $this->getWuXing($ganZhiMonth), |
||||||
| 706 | 'wuxing_day' => $this->getWuXing($ganZhiDay), |
||||||
| 707 | 'wuxing_hour' => $this->getWuXing($ganZhiHour), |
||||||
| 708 | 'color_year' => $this->getColor($ganZhiYear), |
||||||
| 709 | 'color_month' => $this->getColor($ganZhiMonth), |
||||||
| 710 | 'color_day' => $this->getColor($ganZhiDay), |
||||||
| 711 | 'color_hour' => $this->getColor($ganZhiHour), |
||||||
| 712 | 'animal' => $this->getAnimal($lunarYear, $termIndex), |
||||||
| 713 | 'term' => $term, |
||||||
| 714 | 'is_leap' => $isLeap, |
||||||
| 715 | ]; |
||||||
| 716 | } |
||||||
| 717 | |||||||
| 718 | /** |
||||||
| 719 | * 阴历转阳历. |
||||||
| 720 | * |
||||||
| 721 | * @param int $year |
||||||
| 722 | * @param int $month |
||||||
| 723 | * @param int $day |
||||||
| 724 | * @param bool $isLeapMonth |
||||||
| 725 | * |
||||||
| 726 | * @return array|int |
||||||
| 727 | */ |
||||||
| 728 | public function lunar2solar($year, $month, $day, $isLeapMonth = false) |
||||||
| 729 | { |
||||||
| 730 | // 参数区间 1900.1.3 1 ~2100.12.1 |
||||||
| 731 | $leapMonth = $this->leapMonth($year); |
||||||
| 732 | |||||||
| 733 | // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 |
||||||
| 734 | if ($isLeapMonth && ($leapMonth != $month)) { |
||||||
| 735 | $isLeapMonth = false; |
||||||
| 736 | } |
||||||
| 737 | |||||||
| 738 | // 超出了最大极限值 |
||||||
| 739 | if (2100 == $year && 12 == $month && $day > 1 || 1900 == $year && 1 == $month && $day < 31) { |
||||||
|
0 ignored issues
–
show
|
|||||||
| 740 | return -1; |
||||||
| 741 | } |
||||||
| 742 | |||||||
| 743 | $maxDays = $days = $this->lunarDays($year, $month); |
||||||
| 744 | |||||||
| 745 | // if month is leap, _day use leapDays method |
||||||
| 746 | if ($isLeapMonth) { |
||||||
| 747 | $maxDays = $this->leapDays($year, $month); |
||||||
|
0 ignored issues
–
show
The call to
tinymeng\tools\Calendar::leapDays() has too many arguments starting with $month.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. Loading history...
|
|||||||
| 748 | } |
||||||
| 749 | |||||||
| 750 | // 参数合法性效验 |
||||||
| 751 | if ($year < 1900 || $year > 2100 || $day > $maxDays) { |
||||||
| 752 | throw new InvalidArgumentException('传入的参数不合法'); |
||||||
| 753 | } |
||||||
| 754 | |||||||
| 755 | // 计算农历的时间差 |
||||||
| 756 | $offset = 0; |
||||||
| 757 | |||||||
| 758 | for ($i = 1900; $i < $year; ++$i) { |
||||||
| 759 | $offset += $this->daysOfYear($i); |
||||||
| 760 | } |
||||||
| 761 | |||||||
| 762 | $isAdd = false; |
||||||
| 763 | for ($i = 1; $i < $month; ++$i) { |
||||||
| 764 | $leap = $this->leapMonth($year); |
||||||
| 765 | if (!$isAdd) {// 处理闰月 |
||||||
| 766 | if ($leap <= $i && $leap > 0) { |
||||||
| 767 | $offset += $this->leapDays($year); |
||||||
| 768 | $isAdd = true; |
||||||
| 769 | } |
||||||
| 770 | } |
||||||
| 771 | $offset += $this->lunarDays($year, $i); |
||||||
| 772 | } |
||||||
| 773 | |||||||
| 774 | // 转换闰月农历 需补充该年闰月的前一个月的时差 |
||||||
| 775 | if ($isLeapMonth) { |
||||||
| 776 | $offset += $days; |
||||||
| 777 | } |
||||||
| 778 | |||||||
| 779 | // 1900 年农历正月一日的公历时间为 1900 年 1 月 30 日 0 时 0 分 0 秒 (该时间也是本农历的最开始起始点) |
||||||
| 780 | // XXX: 部分 windows 机器不支持负时间戳,所以这里就写死了,哈哈哈哈... |
||||||
| 781 | $startTimestamp = -2206483200; |
||||||
| 782 | $date = date('Y-m-d', ($offset + $day) * 86400 + $startTimestamp); |
||||||
| 783 | |||||||
| 784 | list($solarYear, $solarMonth, $solarDay) = explode('-', $date); |
||||||
| 785 | |||||||
| 786 | return [ |
||||||
| 787 | 'solar_year' => $solarYear, |
||||||
| 788 | 'solar_month' => sprintf('%02d', $solarMonth), |
||||||
| 789 | 'solar_day' => sprintf('%02d', $solarDay), |
||||||
| 790 | ]; |
||||||
| 791 | } |
||||||
| 792 | |||||||
| 793 | /** |
||||||
| 794 | * 获取两个日期之间的距离. |
||||||
| 795 | * |
||||||
| 796 | * @param string|\DateTime $date1 |
||||||
| 797 | * @param string|\DateTime $date2 |
||||||
| 798 | * |
||||||
| 799 | * @return bool|\DateInterval |
||||||
| 800 | */ |
||||||
| 801 | public function dateDiff($date1, $date2) |
||||||
| 802 | { |
||||||
| 803 | if (!($date1 instanceof DateTime)) { |
||||||
| 804 | $date1 = $this->makeDate($date1); |
||||||
| 805 | } |
||||||
| 806 | |||||||
| 807 | if (!($date2 instanceof DateTime)) { |
||||||
| 808 | $date2 = $this->makeDate($date2); |
||||||
| 809 | } |
||||||
| 810 | |||||||
| 811 | return $date1->diff($date2); |
||||||
| 812 | } |
||||||
| 813 | |||||||
| 814 | /** |
||||||
| 815 | * 获取两个日期之间以年为单位的距离. |
||||||
| 816 | * |
||||||
| 817 | * @param array $lunar1 |
||||||
| 818 | * @param array $lunar2 |
||||||
| 819 | * @param bool $absolute |
||||||
| 820 | * |
||||||
| 821 | * @return int |
||||||
| 822 | */ |
||||||
| 823 | public function diffInYears($lunar1, $lunar2, $absolute = true) |
||||||
| 824 | { |
||||||
| 825 | $solar1 = |
||||||
| 826 | $this->lunar2solar($lunar1['lunar_year'], $lunar1['lunar_month'], $lunar1['lunar_day'], $lunar1['is_leap']); |
||||||
| 827 | $date1 = $this->makeDate("{$solar1['solar_year']}-{$solar1['solar_month']}-{$solar1['solar_day']}"); |
||||||
| 828 | |||||||
| 829 | $solar2 = |
||||||
| 830 | $this->lunar2solar($lunar2['lunar_year'], $lunar2['lunar_month'], $lunar2['lunar_day'], $lunar2['is_leap']); |
||||||
| 831 | $date2 = $this->makeDate("{$solar2['solar_year']}-{$solar2['solar_month']}-{$solar2['solar_day']}"); |
||||||
| 832 | |||||||
| 833 | if ($date1 < $date2) { |
||||||
| 834 | $lessLunar = $lunar1; |
||||||
| 835 | $greaterLunar = $lunar2; |
||||||
| 836 | $changed = false; |
||||||
| 837 | } else { |
||||||
| 838 | $lessLunar = $lunar2; |
||||||
| 839 | $greaterLunar = $lunar1; |
||||||
| 840 | $changed = true; |
||||||
| 841 | } |
||||||
| 842 | |||||||
| 843 | $monthAdjustFactor = $greaterLunar['lunar_day'] >= $lessLunar['lunar_day'] ? 0 : 1; |
||||||
| 844 | if ($greaterLunar['lunar_month'] == $lessLunar['lunar_month']) { |
||||||
| 845 | if ($greaterLunar['is_leap'] && !$lessLunar['is_leap']) { |
||||||
| 846 | $monthAdjustFactor = 0; |
||||||
| 847 | } elseif (!$greaterLunar['is_leap'] && $lessLunar['is_leap']) { |
||||||
| 848 | $monthAdjustFactor = 1; |
||||||
| 849 | } |
||||||
| 850 | } |
||||||
| 851 | $yearAdjustFactor = $greaterLunar['lunar_month'] - $monthAdjustFactor >= $lessLunar['lunar_month'] ? 0 : 1; |
||||||
| 852 | $diff = $greaterLunar['lunar_year'] - $yearAdjustFactor - $lessLunar['lunar_year']; |
||||||
| 853 | |||||||
| 854 | return $absolute ? $diff : ($changed ? -1 * $diff : $diff); |
||||||
| 855 | } |
||||||
| 856 | |||||||
| 857 | /** |
||||||
| 858 | * 获取两个日期之间以月为单位的距离. |
||||||
| 859 | * @param array $lunar1 |
||||||
| 860 | * @param array $lunar2 |
||||||
| 861 | * @param bool $absolute |
||||||
| 862 | * @return float|int|mixed |
||||||
| 863 | */ |
||||||
| 864 | public function diffInMonths($lunar1, $lunar2, $absolute = true) |
||||||
| 865 | { |
||||||
| 866 | $solar1 = |
||||||
| 867 | $this->lunar2solar($lunar1['lunar_year'], $lunar1['lunar_month'], $lunar1['lunar_day'], $lunar1['is_leap']); |
||||||
| 868 | $date1 = $this->makeDate("{$solar1['solar_year']}-{$solar1['solar_month']}-{$solar1['solar_day']}"); |
||||||
| 869 | |||||||
| 870 | $solar2 = |
||||||
| 871 | $this->lunar2solar($lunar2['lunar_year'], $lunar2['lunar_month'], $lunar2['lunar_day'], $lunar2['is_leap']); |
||||||
| 872 | $date2 = $this->makeDate("{$solar2['solar_year']}-{$solar2['solar_month']}-{$solar2['solar_day']}"); |
||||||
| 873 | |||||||
| 874 | if ($date1 < $date2) { |
||||||
| 875 | $lessLunar = $lunar1; |
||||||
| 876 | $greaterLunar = $lunar2; |
||||||
| 877 | $changed = false; |
||||||
| 878 | } else { |
||||||
| 879 | $lessLunar = $lunar2; |
||||||
| 880 | $greaterLunar = $lunar1; |
||||||
| 881 | $changed = true; |
||||||
| 882 | } |
||||||
| 883 | |||||||
| 884 | $diff = 0; |
||||||
| 885 | |||||||
| 886 | if ($lessLunar['lunar_year'] == $greaterLunar['lunar_year']) { |
||||||
| 887 | $leapMonth = $this->leapMonth($lessLunar['lunar_year']); |
||||||
| 888 | $lessLunarAdjustFactor = |
||||||
| 889 | $lessLunar['is_leap'] || (0 < $leapMonth && $leapMonth < $lessLunar['lunar_month']) ? 1 : 0; |
||||||
| 890 | $greaterLunarAdjustFactor = |
||||||
| 891 | $greaterLunar['is_leap'] || (0 < $leapMonth && $leapMonth < $greaterLunar['lunar_month']) ? 1 : 0; |
||||||
| 892 | $diff = |
||||||
| 893 | $greaterLunar['lunar_month'] + $greaterLunarAdjustFactor - $lessLunar['lunar_month'] - $lessLunarAdjustFactor; |
||||||
| 894 | } else { |
||||||
| 895 | $lessLunarLeapMonth = $this->leapMonth($lessLunar['lunar_year']); |
||||||
| 896 | $greaterLunarLeapMonth = $this->leapMonth($greaterLunar['lunar_year']); |
||||||
| 897 | |||||||
| 898 | $lessLunarAdjustFactor = |
||||||
| 899 | (!$lessLunar['is_leap'] && $lessLunarLeapMonth == $lessLunar['lunar_month']) || $lessLunarLeapMonth > $lessLunar['lunar_month'] ? 1 : 0; |
||||||
| 900 | $diff += 12 + $lessLunarAdjustFactor - $lessLunar['lunar_month']; |
||||||
| 901 | for ($i = $lessLunar['lunar_year'] + 1; $i < $greaterLunar['lunar_year']; ++$i) { |
||||||
| 902 | $diff += $this->monthsOfYear($i); |
||||||
| 903 | } |
||||||
| 904 | $greaterLunarAdjustFactor = |
||||||
| 905 | $greaterLunar['is_leap'] || (0 < $greaterLunarLeapMonth && $greaterLunarLeapMonth < $greaterLunar['lunar_month']) ? 1 : 0; |
||||||
| 906 | $diff += $greaterLunarAdjustFactor + $greaterLunar['lunar_month']; |
||||||
| 907 | } |
||||||
| 908 | |||||||
| 909 | $diff -= $greaterLunar['lunar_day'] >= $lessLunar['lunar_day'] ? 0 : 1; |
||||||
| 910 | |||||||
| 911 | return $absolute ? $diff : ($changed ? -1 * $diff : $diff); |
||||||
| 912 | } |
||||||
| 913 | |||||||
| 914 | /** |
||||||
| 915 | * 获取两个日期之间以日为单位的距离. |
||||||
| 916 | * |
||||||
| 917 | * @param array $lunar1 |
||||||
| 918 | * @param array $lunar2 |
||||||
| 919 | * @param bool $absolute |
||||||
| 920 | * |
||||||
| 921 | * @return int |
||||||
| 922 | */ |
||||||
| 923 | public function diffInDays($lunar1, $lunar2, $absolute = true) |
||||||
| 924 | { |
||||||
| 925 | $solar1 = |
||||||
| 926 | $this->lunar2solar($lunar1['lunar_year'], $lunar1['lunar_month'], $lunar1['lunar_day'], $lunar1['is_leap']); |
||||||
| 927 | $date1 = $this->makeDate("{$solar1['solar_year']}-{$solar1['solar_month']}-{$solar1['solar_day']}"); |
||||||
| 928 | |||||||
| 929 | $solar2 = |
||||||
| 930 | $this->lunar2solar($lunar2['lunar_year'], $lunar2['lunar_month'], $lunar2['lunar_day'], $lunar2['is_leap']); |
||||||
| 931 | $date2 = $this->makeDate("{$solar2['solar_year']}-{$solar2['solar_month']}-{$solar2['solar_day']}"); |
||||||
| 932 | |||||||
| 933 | return $date1->diff($date2, $absolute)->format('%r%a'); |
||||||
| 934 | } |
||||||
| 935 | |||||||
| 936 | /** |
||||||
| 937 | * 增加年数. |
||||||
| 938 | * |
||||||
| 939 | * @param array $lunar |
||||||
| 940 | * @param int $value |
||||||
| 941 | * @param bool $overFlow |
||||||
| 942 | * |
||||||
| 943 | * @return array |
||||||
| 944 | */ |
||||||
| 945 | public function addYears($lunar, $value = 1, $overFlow = true) |
||||||
| 946 | { |
||||||
| 947 | $newYear = $lunar['lunar_year'] + $value; |
||||||
| 948 | $newMonth = $lunar['lunar_month']; |
||||||
| 949 | $newDay = $lunar['lunar_day']; |
||||||
| 950 | $isLeap = $lunar['is_leap']; |
||||||
| 951 | $needOverFlow = false; |
||||||
| 952 | |||||||
| 953 | $leapMonth = $this->leapMonth($newYear); |
||||||
| 954 | $isLeap = $isLeap && $newMonth == $leapMonth; |
||||||
| 955 | $maxDays = $isLeap ? $this->leapDays($newYear) : $this->lunarDays($newYear, $newMonth); |
||||||
| 956 | |||||||
| 957 | if ($newDay > $maxDays) { |
||||||
| 958 | if ($overFlow) { |
||||||
| 959 | $newDay = 1; |
||||||
| 960 | $needOverFlow = true; |
||||||
| 961 | } else { |
||||||
| 962 | $newDay = $maxDays; |
||||||
| 963 | } |
||||||
| 964 | } |
||||||
| 965 | $ret = $this->lunar($newYear, $newMonth, $newDay, $isLeap); |
||||||
| 966 | if ($needOverFlow) { |
||||||
| 967 | $ret = $this->addMonths($ret, 1, $overFlow); |
||||||
| 968 | } |
||||||
| 969 | |||||||
| 970 | return $ret; |
||||||
| 971 | } |
||||||
| 972 | |||||||
| 973 | /** |
||||||
| 974 | * 减少年数. |
||||||
| 975 | * |
||||||
| 976 | * @param array $lunar |
||||||
| 977 | * @param int $value |
||||||
| 978 | * @param bool $overFlow |
||||||
| 979 | * |
||||||
| 980 | * @return array |
||||||
| 981 | */ |
||||||
| 982 | public function subYears($lunar, $value = 1, $overFlow = true) |
||||||
| 983 | { |
||||||
| 984 | return $this->addYears($lunar, -1 * $value, $overFlow); |
||||||
| 985 | } |
||||||
| 986 | |||||||
| 987 | /** |
||||||
| 988 | * 增加月数. |
||||||
| 989 | * |
||||||
| 990 | * @param array $lunar |
||||||
| 991 | * @param int $value |
||||||
| 992 | * @param bool $overFlow |
||||||
| 993 | * |
||||||
| 994 | * @return array |
||||||
| 995 | */ |
||||||
| 996 | public function addMonths($lunar, $value = 1, $overFlow = true) |
||||||
| 997 | { |
||||||
| 998 | if (0 > $value) { |
||||||
| 999 | return $this->subMonths($lunar, -1 * $value, $overFlow); |
||||||
| 1000 | } else { |
||||||
| 1001 | $newYear = $lunar['lunar_year']; |
||||||
| 1002 | $newMonth = $lunar['lunar_month']; |
||||||
| 1003 | $newDay = $lunar['lunar_day']; |
||||||
| 1004 | $isLeap = $lunar['is_leap']; |
||||||
| 1005 | |||||||
| 1006 | while (0 < $value) { |
||||||
| 1007 | $leapMonth = $this->leapMonth($newYear); |
||||||
| 1008 | if (0 < $leapMonth) { |
||||||
| 1009 | $currentIsLeap = $isLeap; |
||||||
| 1010 | $isLeap = $newMonth + $value == $leapMonth + ($isLeap ? 0 : 1); |
||||||
| 1011 | |||||||
| 1012 | if ((!$currentIsLeap && $leapMonth == $newMonth) || ($newMonth < $leapMonth && $newMonth + $value > $leapMonth)) { |
||||||
| 1013 | --$value; |
||||||
| 1014 | } |
||||||
| 1015 | } else { |
||||||
| 1016 | $isLeap = false; |
||||||
| 1017 | } |
||||||
| 1018 | |||||||
| 1019 | if (13 > $newMonth + $value) { |
||||||
| 1020 | $newMonth += $value; |
||||||
| 1021 | $value = 0; |
||||||
| 1022 | } else { |
||||||
| 1023 | $value = $value + $newMonth - 13; |
||||||
| 1024 | ++$newYear; |
||||||
| 1025 | $newMonth = 1; |
||||||
| 1026 | } |
||||||
| 1027 | |||||||
| 1028 | if (0 == $value) { |
||||||
| 1029 | $maxDays = $isLeap ? $this->leapDays($newYear) : $this->lunarDays($newYear, $newMonth); |
||||||
| 1030 | if ($newDay > $maxDays) { |
||||||
| 1031 | if ($overFlow) { |
||||||
| 1032 | $newDay = 1; |
||||||
| 1033 | ++$value; |
||||||
| 1034 | } else { |
||||||
| 1035 | $newDay = $maxDays; |
||||||
| 1036 | } |
||||||
| 1037 | } |
||||||
| 1038 | } |
||||||
| 1039 | } |
||||||
| 1040 | |||||||
| 1041 | return $this->lunar($newYear, $newMonth, $newDay, $isLeap); |
||||||
| 1042 | } |
||||||
| 1043 | } |
||||||
| 1044 | |||||||
| 1045 | /** |
||||||
| 1046 | * 减少月数. |
||||||
| 1047 | * |
||||||
| 1048 | * @param array $lunar |
||||||
| 1049 | * @param int $value |
||||||
| 1050 | * @param bool $overFlow |
||||||
| 1051 | * |
||||||
| 1052 | * @return array |
||||||
| 1053 | */ |
||||||
| 1054 | public function subMonths($lunar, $value = 1, $overFlow = true) |
||||||
| 1055 | { |
||||||
| 1056 | if (0 > $value) { |
||||||
| 1057 | return $this->addMonths($lunar, -1 * $value, $overFlow); |
||||||
| 1058 | } else { |
||||||
| 1059 | $newYear = $lunar['lunar_year']; |
||||||
| 1060 | $newMonth = $lunar['lunar_month']; |
||||||
| 1061 | $newDay = $lunar['lunar_day']; |
||||||
| 1062 | $isLeap = $lunar['is_leap']; |
||||||
| 1063 | $needOverFlow = false; |
||||||
| 1064 | |||||||
| 1065 | while (0 < $value) { |
||||||
| 1066 | $leapMonth = $this->leapMonth($newYear); |
||||||
| 1067 | |||||||
| 1068 | if (0 < $leapMonth) { |
||||||
| 1069 | $isLeap = $newMonth - $value == $leapMonth; |
||||||
| 1070 | |||||||
| 1071 | if ($newMonth >= $leapMonth && $newMonth - $value < $leapMonth) { |
||||||
| 1072 | --$value; |
||||||
| 1073 | } |
||||||
| 1074 | } else { |
||||||
| 1075 | $isLeap = false; |
||||||
| 1076 | } |
||||||
| 1077 | |||||||
| 1078 | if ($newMonth > $value) { |
||||||
| 1079 | $newMonth -= $value; |
||||||
| 1080 | $value = 0; |
||||||
| 1081 | } else { |
||||||
| 1082 | $value = $value - $newMonth; |
||||||
| 1083 | --$newYear; |
||||||
| 1084 | $newMonth = 12; |
||||||
| 1085 | } |
||||||
| 1086 | |||||||
| 1087 | if (0 == $value) { |
||||||
| 1088 | $maxDays = $isLeap ? $this->leapDays($newYear) : $this->lunarDays($newYear, $newMonth); |
||||||
| 1089 | if ($newDay > $maxDays) { |
||||||
| 1090 | $newDay = $maxDays; |
||||||
| 1091 | $needOverFlow = $overFlow; |
||||||
| 1092 | } |
||||||
| 1093 | } |
||||||
| 1094 | } |
||||||
| 1095 | |||||||
| 1096 | $ret = $this->lunar($newYear, $newMonth, $newDay, $isLeap); |
||||||
| 1097 | if ($needOverFlow) { |
||||||
| 1098 | $ret = $this->addDays($ret, 1); |
||||||
| 1099 | } |
||||||
| 1100 | |||||||
| 1101 | return $ret; |
||||||
| 1102 | } |
||||||
| 1103 | } |
||||||
| 1104 | |||||||
| 1105 | /** |
||||||
| 1106 | * 增加天数. |
||||||
| 1107 | * |
||||||
| 1108 | * @param array $lunar |
||||||
| 1109 | * @param int $value |
||||||
| 1110 | * |
||||||
| 1111 | * @return array |
||||||
| 1112 | */ |
||||||
| 1113 | public function addDays($lunar, $value = 1) |
||||||
| 1114 | { |
||||||
| 1115 | $solar = |
||||||
| 1116 | $this->lunar2solar($lunar['lunar_year'], $lunar['lunar_month'], $lunar['lunar_day'], $lunar['is_leap']); |
||||||
| 1117 | $date = $this->makeDate("{$solar['solar_year']}-{$solar['solar_month']}-{$solar['solar_day']}"); |
||||||
| 1118 | $date->modify($value.' day'); |
||||||
| 1119 | |||||||
| 1120 | return $this->solar2lunar((int)$date->format('Y'), (int)$date->format('m'), (int)$date->format('d')); |
||||||
| 1121 | } |
||||||
| 1122 | |||||||
| 1123 | /** |
||||||
| 1124 | * 减少天数. |
||||||
| 1125 | * |
||||||
| 1126 | * @param array $lunar |
||||||
| 1127 | * @param int $value |
||||||
| 1128 | * |
||||||
| 1129 | * @return array |
||||||
| 1130 | */ |
||||||
| 1131 | public function subDays($lunar, $value = 1) |
||||||
| 1132 | { |
||||||
| 1133 | return $this->addDays($lunar, -1 * $value); |
||||||
| 1134 | } |
||||||
| 1135 | |||||||
| 1136 | /** |
||||||
| 1137 | * 创建日期对象 |
||||||
| 1138 | * |
||||||
| 1139 | * @param string $string |
||||||
| 1140 | * @param string $timezone |
||||||
| 1141 | * |
||||||
| 1142 | * @return \DateTime |
||||||
| 1143 | */ |
||||||
| 1144 | protected function makeDate($string = 'now', $timezone = 'PRC') |
||||||
| 1145 | { |
||||||
| 1146 | return new DateTime($string, new DateTimeZone($timezone)); |
||||||
| 1147 | } |
||||||
| 1148 | |||||||
| 1149 | /** |
||||||
| 1150 | * 获取时柱. |
||||||
| 1151 | * |
||||||
| 1152 | * @param int $hour 0~23 小时格式 |
||||||
| 1153 | * @param int $ganZhiDay 干支日期 |
||||||
| 1154 | * |
||||||
| 1155 | * @return array |
||||||
| 1156 | * |
||||||
| 1157 | * @see https://baike.baidu.com/item/%E6%97%B6%E6%9F%B1/6274024 |
||||||
| 1158 | */ |
||||||
| 1159 | protected function ganZhiHour($hour, $ganZhiDay) |
||||||
| 1160 | { |
||||||
| 1161 | if (!is_numeric($hour) || $hour < 0 || $hour > 23) { |
||||||
|
0 ignored issues
–
show
|
|||||||
| 1162 | return [null, null, null]; |
||||||
| 1163 | } |
||||||
| 1164 | |||||||
| 1165 | $zhiHour = intval(($hour + 1) / 2); |
||||||
| 1166 | $zhiHour = 12 === $zhiHour ? 0 : $zhiHour; |
||||||
| 1167 | |||||||
| 1168 | return [ |
||||||
| 1169 | $this->gan[($ganZhiDay % 10 % 5 * 2 + $zhiHour) % 10].$this->zhi[$zhiHour], |
||||||
| 1170 | $this->zhi[$zhiHour].'时', |
||||||
| 1171 | sprintf('%02d', $hour), |
||||||
| 1172 | ]; |
||||||
| 1173 | } |
||||||
| 1174 | } |
||||||
| 1175 |