line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Calendar::Any::Chinese; |
2
|
|
|
|
|
|
|
{ |
3
|
|
|
|
|
|
|
$Calendar::Any::Chinese::VERSION = '0.5'; |
4
|
|
|
|
|
|
|
} |
5
|
1
|
|
|
1
|
|
19778
|
use base 'Calendar::Any'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
555
|
|
6
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
62
|
|
7
|
1
|
|
|
1
|
|
527
|
use Calendar::Any::Gregorian; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
8
|
1
|
|
|
1
|
|
680
|
use Calendar::Any::Util::Lunar; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2956
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
sub new { |
11
|
1
|
|
|
1
|
1
|
12
|
my $_class = shift; |
12
|
1
|
|
33
|
|
|
7
|
my $class = ref $_class || $_class; |
13
|
1
|
|
|
|
|
2
|
my $self = {}; |
14
|
1
|
|
|
|
|
2
|
bless $self, $class; |
15
|
1
|
50
|
|
|
|
4
|
if ( @_ ) { |
16
|
1
|
|
|
|
|
2
|
my %arg; |
17
|
1
|
50
|
|
|
|
6
|
if ( $_[0] =~ /-\D/ ) { |
18
|
0
|
|
|
|
|
0
|
%arg = @_; |
19
|
|
|
|
|
|
|
} else { |
20
|
1
|
50
|
|
|
|
4
|
if ( $#_ > 0 ) { |
21
|
1
|
|
|
|
|
9
|
$arg{$_} = shift for qw(-cycle -year -month -day); |
22
|
|
|
|
|
|
|
} else { |
23
|
0
|
|
|
|
|
0
|
return $self->from_absolute(@_); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
} |
26
|
1
|
|
|
|
|
2
|
foreach ( qw(-cycle -year -month -day) ) { |
27
|
4
|
50
|
|
|
|
84
|
$self->{substr($_, 1)} = $arg{$_} if exists $arg{$_}; |
28
|
|
|
|
|
|
|
} |
29
|
1
|
|
|
|
|
4
|
$self->absolute_date(); |
30
|
|
|
|
|
|
|
} |
31
|
1
|
|
|
|
|
3
|
return $self; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub from_absolute { |
35
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
36
|
0
|
|
|
|
|
0
|
my $absdate = shift; |
37
|
0
|
|
|
|
|
0
|
$self->{absolute} = $absdate; |
38
|
0
|
|
|
|
|
0
|
my $date = Calendar::Any::Gregorian->new($absdate); |
39
|
0
|
|
|
|
|
0
|
$self->{gdate} = $date; |
40
|
0
|
|
|
|
|
0
|
my $cyear = $date->year+2695; |
41
|
0
|
|
|
|
|
0
|
my @list = (@{_year($date->year-1)}, |
|
0
|
|
|
|
|
0
|
|
42
|
0
|
|
|
|
|
0
|
@{_year($date->year)}, |
43
|
0
|
|
|
|
|
0
|
@{_year($date->year+1)}); |
44
|
0
|
|
|
|
|
0
|
foreach ( 0..$#list ) { |
45
|
0
|
0
|
|
|
|
0
|
if ( $list[$_]->[0] == 1 ) { |
46
|
0
|
|
|
|
|
0
|
$cyear++; |
47
|
|
|
|
|
|
|
} |
48
|
0
|
0
|
|
|
|
0
|
if ( $list[$_+1]->[1] > $absdate ) { |
49
|
0
|
|
|
|
|
0
|
$date = $list[$_]; |
50
|
0
|
|
|
|
|
0
|
last; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
} |
53
|
0
|
|
|
|
|
0
|
$self->{cycle} = int(($cyear-1)/60); |
54
|
0
|
|
|
|
|
0
|
$self->{year} = _mod($cyear, 60); |
55
|
0
|
|
|
|
|
0
|
$self->{month} = $date->[0]; |
56
|
0
|
|
|
|
|
0
|
$self->{day} = $absdate - $date->[1] + 1; |
57
|
0
|
|
|
|
|
0
|
return $self; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub absolute_date { |
61
|
5
|
|
|
5
|
0
|
6
|
my $self = shift; |
62
|
5
|
100
|
|
|
|
14
|
if (exists $self->{absolute} ) { |
63
|
4
|
|
|
|
|
36
|
return $self->{absolute}; |
64
|
|
|
|
|
|
|
} |
65
|
1
|
|
|
|
|
4
|
my ($cycle, $year, $month, $day) = ($self->{cycle}, $self->{year}, $self->{month}, $self->{day}); |
66
|
1
|
|
|
|
|
4
|
my $gyear = 60*($cycle-1)+$year-1-2636; |
67
|
1
|
|
|
|
|
4
|
my $monthday = _assoc_month($month, [_memq_month(1, _year($gyear)), @{_year($gyear+1)}]); |
|
1
|
|
|
|
|
3
|
|
68
|
1
|
|
|
|
|
6
|
$self->{absolute} = $day-1+$monthday->[1]; |
69
|
1
|
|
|
|
|
4
|
$self->assert_date(); |
70
|
1
|
|
|
|
|
4
|
return $self->{absolute}; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
0
|
|
|
0
|
1
|
0
|
sub cycle { shift->{cycle}; } |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub is_leap_year { |
76
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
77
|
0
|
|
|
|
|
0
|
my $list = _year_month_list($self->cycle, $self->year); |
78
|
0
|
|
|
|
|
0
|
return $#{$list} == 12; |
|
0
|
|
|
|
|
0
|
|
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
1
|
|
|
1
|
1
|
6
|
sub gyear { shift->gdate->year; } |
82
|
|
|
|
|
|
|
|
83
|
1
|
|
|
1
|
1
|
3
|
sub gmonth { shift->gdate->month; } |
84
|
|
|
|
|
|
|
|
85
|
1
|
|
|
1
|
1
|
4
|
sub gday { shift->gdate->day; } |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub gdate { |
88
|
3
|
|
|
3
|
1
|
4
|
my $self = shift; |
89
|
3
|
100
|
|
|
|
7
|
if ( !exists $self->{gdate} ) { |
90
|
1
|
|
|
|
|
3
|
$self->{gdate} = Calendar::Any::Gregorian->new($self->absolute_date); |
91
|
|
|
|
|
|
|
} |
92
|
3
|
|
|
|
|
17
|
return $self->{gdate}; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub last_day_of_month { |
96
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
97
|
1
|
50
|
|
|
|
4
|
my $date = Calendar::Any::Util::Lunar::new_moon_date |
98
|
|
|
|
|
|
|
( $self->day==1 ? $self->absolute_date+1 : $self, |
99
|
|
|
|
|
|
|
timezone(Calendar::Any::Gregorian->new($self->absolute_date)->year)); |
100
|
1
|
|
|
|
|
4
|
return int($date-1-$self->absolute_date + $self->day); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub year_month_list { |
104
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
105
|
0
|
|
|
|
|
0
|
return _year_month_list($self->cycle, $self->year); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub timezone { |
109
|
1
|
|
|
1
|
1
|
2
|
my $year = shift; |
110
|
1
|
50
|
33
|
|
|
11
|
return ((defined $year && $year >= 1928) ? 480 : 465 + 40.0/60.0 ); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub next_jieqi_date { |
114
|
0
|
|
|
0
|
1
|
0
|
Calendar::Any::Util::Solar::next_longitude_date($_[0], 15, $_[1]); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub assert_date { |
118
|
1
|
|
|
1
|
0
|
2
|
my $self = shift; |
119
|
1
|
50
|
33
|
|
|
11
|
if ( $self->year < 1 || $self->year > 60 ) { |
120
|
0
|
|
|
|
|
0
|
confess('Not a valid year: should not from 1 to 60 for ' . ref $self); |
121
|
|
|
|
|
|
|
} |
122
|
1
|
50
|
33
|
|
|
8
|
if ( $self->month < 1 || $self->month > 12 ) { |
123
|
0
|
|
|
|
|
0
|
confess(sprintf('Not a valid month %d: should from 1 to 12 for %s', $self->month, ref $self)); |
124
|
|
|
|
|
|
|
} |
125
|
1
|
50
|
33
|
|
|
7
|
if ( $self->day < 1 || $self->day > $self->last_day_of_month() ) { |
126
|
0
|
|
|
|
|
0
|
confess(sprintf('Not a valid day %d: should from 1 to %d in %d, %d for %s', |
127
|
|
|
|
|
|
|
$self->day, $self->last_day_of_month, $self->month, $self->year, ref $self)); |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
#========================================================== |
132
|
|
|
|
|
|
|
# Format calendar |
133
|
|
|
|
|
|
|
#========================================================== |
134
|
|
|
|
|
|
|
our @celestial_stem = qw(甲 乙 丙 丁 戊 已 庚 辛 壬 癸); |
135
|
|
|
|
|
|
|
our @terrestrial_branch = qw(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥); |
136
|
|
|
|
|
|
|
our @weekday_name = qw(日 一 二 三 四 五 六); |
137
|
|
|
|
|
|
|
our @month_name = |
138
|
|
|
|
|
|
|
qw(正月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 腊月); |
139
|
|
|
|
|
|
|
our @day_name = qw |
140
|
|
|
|
|
|
|
(初一 初二 初三 初四 初五 初六 初七 初八 初九 初十 |
141
|
|
|
|
|
|
|
十一 十二 十三 十四 十五 十六 十七 十八 十九 二十 |
142
|
|
|
|
|
|
|
廿一 廿二 廿三 廿四 廿五 廿六 廿七 廿八 廿九 三十 |
143
|
|
|
|
|
|
|
卅一); |
144
|
|
|
|
|
|
|
our @zodiac_name = qw(鼠 牛 虎 兔 龙 蛇 马 羊 猴 鸡 狗 猪); |
145
|
|
|
|
|
|
|
our @jieqi_name = qw |
146
|
|
|
|
|
|
|
(小寒 大寒 立春 雨水 惊蛰 春分 |
147
|
|
|
|
|
|
|
清明 谷雨 立夏 小满 芒种 夏至 |
148
|
|
|
|
|
|
|
小暑 大暑 立秋 处暑 白露 秋分 |
149
|
|
|
|
|
|
|
寒露 霜降 立冬 小雪 大雪 冬至); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub day_name { |
152
|
0
|
|
|
0
|
0
|
0
|
return $day_name[shift->day-1]; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub month_name { |
156
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
157
|
0
|
|
|
|
|
0
|
my $month = $self->month; |
158
|
0
|
0
|
|
|
|
0
|
if ( _is_int($month) ) { |
159
|
0
|
|
|
|
|
0
|
$month_name[$month-1]; |
160
|
|
|
|
|
|
|
} else { |
161
|
0
|
|
|
|
|
0
|
return "闰".$month_name[$month-1]; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub weekday_name { |
166
|
0
|
|
|
0
|
1
|
0
|
return "星期".$weekday_name[shift->weekday]; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub sexagesimal_name { |
170
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
171
|
0
|
|
|
|
|
0
|
my $year = $self->year-1; |
172
|
0
|
|
|
|
|
0
|
return $celestial_stem[$year%10] . $terrestrial_branch[$year%12]; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub zodiac_name { |
176
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
177
|
0
|
|
|
|
|
0
|
my $year = $self->year-1; |
178
|
0
|
|
|
|
|
0
|
return $zodiac_name[$year%12]; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
0
|
0
|
0
|
sub format_Y { shift->gyear } |
182
|
0
|
|
|
0
|
0
|
0
|
sub format_S { shift->sexagesimal_name } |
183
|
0
|
|
|
0
|
0
|
0
|
sub format_D { shift->day_name } |
184
|
0
|
|
|
0
|
0
|
0
|
sub format_Z { shift->zodiac_name } |
185
|
0
|
|
|
0
|
0
|
0
|
sub format_m { sprintf("%02d", shift->gmonth) } |
186
|
0
|
|
|
0
|
0
|
0
|
sub format_d { sprintf("%02d", shift->gday) } |
187
|
|
|
|
|
|
|
our $default_format = "%Y年%m月%d日 %W %S%Z年%M%D"; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
#========================================================== |
190
|
|
|
|
|
|
|
# Private functions |
191
|
|
|
|
|
|
|
#========================================================== |
192
|
|
|
|
|
|
|
#========================================================== |
193
|
|
|
|
|
|
|
# Input : chinese year cycle, year |
194
|
|
|
|
|
|
|
# Output : the array of month in the chinese year |
195
|
|
|
|
|
|
|
# Desc : |
196
|
|
|
|
|
|
|
#========================================================== |
197
|
|
|
|
|
|
|
sub _year_month_list { |
198
|
0
|
|
|
0
|
|
0
|
my ($cycle, $year) = @_; |
199
|
0
|
|
|
|
|
0
|
my $date = __PACKAGE__->new($cycle, $year, 1, 1); |
200
|
0
|
|
|
|
|
0
|
$year = $date->gyear; |
201
|
0
|
|
|
|
|
0
|
my $list1 = _year($year); |
202
|
0
|
|
|
|
|
0
|
my $list2 = _year($year+1); |
203
|
0
|
|
|
|
|
0
|
my @list = _memq_month(1, $list1); |
204
|
0
|
|
|
|
|
0
|
foreach ( @$list2 ) { |
205
|
0
|
0
|
|
|
|
0
|
last if $_->[0]==1; |
206
|
0
|
|
|
|
|
0
|
push @list, $_; |
207
|
|
|
|
|
|
|
} |
208
|
0
|
|
|
|
|
0
|
return \@list; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
#========================================================== |
212
|
|
|
|
|
|
|
# Input : x, y |
213
|
|
|
|
|
|
|
# Output : x modulo y, range from 1-y |
214
|
|
|
|
|
|
|
# Desc : like operator %, but instead of 0, return the exclusive y |
215
|
|
|
|
|
|
|
#========================================================== |
216
|
|
|
|
|
|
|
sub _mod { |
217
|
0
|
0
|
|
0
|
|
0
|
$_[0] % $_[1] || $_[1]; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub _is_int { |
221
|
0
|
|
|
0
|
|
0
|
$_[0]-int($_[0])==0; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
#========================================================== |
225
|
|
|
|
|
|
|
# Input : month, an array of month list |
226
|
|
|
|
|
|
|
# Output : the month list from month |
227
|
|
|
|
|
|
|
# Desc : eg, _memq_month(2, [[12, 726464], [1, 726494], [2, 726523], [3, 726553], ...]) |
228
|
|
|
|
|
|
|
# return [[2, 726523], [3, 726553], ...] |
229
|
|
|
|
|
|
|
#========================================================== |
230
|
|
|
|
|
|
|
sub _memq_month { |
231
|
1
|
|
|
1
|
|
2
|
my ($month, $list) = @_; |
232
|
1
|
|
|
|
|
2
|
my $i = 0; |
233
|
1
|
|
|
|
|
4
|
for ( ; $i<=$#$list; $i++ ) { |
234
|
2
|
100
|
|
|
|
8
|
last if ($list->[$i][0] == $month); |
235
|
|
|
|
|
|
|
} |
236
|
1
|
|
|
|
|
4
|
return @{$list}[$i..$#$list]; |
|
1
|
|
|
|
|
12
|
|
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
#========================================================== |
240
|
|
|
|
|
|
|
# Input : month, an array of month list |
241
|
|
|
|
|
|
|
# Output : the month in the list |
242
|
|
|
|
|
|
|
# Desc : eg, _assoc_month(2, [[12, 726464], [1, 726494], [2, 726523], [3, 726553], ...]) |
243
|
|
|
|
|
|
|
# return [2, 726523] |
244
|
|
|
|
|
|
|
#========================================================== |
245
|
|
|
|
|
|
|
sub _assoc_month { |
246
|
1
|
|
|
1
|
|
1
|
my ($month, $list) = @_; |
247
|
1
|
|
|
|
|
3
|
foreach ( @$list ) { |
248
|
12
|
100
|
|
|
|
22
|
return $_ if $_->[0] == $month; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
#========================================================== |
253
|
|
|
|
|
|
|
# Input : Gregorian year |
254
|
|
|
|
|
|
|
# Output : the chinese month list of the year |
255
|
|
|
|
|
|
|
# Desc : The month list always range from winter solstice day in year-1 |
256
|
|
|
|
|
|
|
# to winter in solstice day. Usually, the month list is start |
257
|
|
|
|
|
|
|
# chinese month 12 in last year, but possible start from 11.5. |
258
|
|
|
|
|
|
|
# The month with .5 indicate that is a leap month. |
259
|
|
|
|
|
|
|
#========================================================== |
260
|
|
|
|
|
|
|
my %year_cache = ( |
261
|
|
|
|
|
|
|
'2000' => [ |
262
|
|
|
|
|
|
|
[12, 730126],[1, 730155],[2, 730185],[3, 730215],[4, 730244],[5, 730273], |
263
|
|
|
|
|
|
|
[6, 730303],[7, 730332],[8, 730361],[9, 730391],[10, 730420],[11, 730450] |
264
|
|
|
|
|
|
|
], |
265
|
|
|
|
|
|
|
'2001' => [ |
266
|
|
|
|
|
|
|
[12, 730480],[1, 730509],[2, 730539],[3, 730569],[4, 730598],[4.5, 730628], |
267
|
|
|
|
|
|
|
[5, 730657],[6, 730687],[7, 730716],[8, 730745],[9, 730775],[10, 730804], |
268
|
|
|
|
|
|
|
[11, 730834] |
269
|
|
|
|
|
|
|
], |
270
|
|
|
|
|
|
|
'2002' => [ |
271
|
|
|
|
|
|
|
[12, 730863],[1, 730893],[2, 730923],[3, 730953],[4, 730982],[5, 731012], |
272
|
|
|
|
|
|
|
[6, 731041],[7, 731071],[8, 731100],[9, 731129],[10, 731159],[11, 731188] |
273
|
|
|
|
|
|
|
], |
274
|
|
|
|
|
|
|
'2003' => [ |
275
|
|
|
|
|
|
|
[12, 731218],[1, 731247],[2, 731277],[3, 731307],[4, 731336],[5, 731366], |
276
|
|
|
|
|
|
|
[6, 731396],[7, 731425],[8, 731455],[9, 731484],[10, 731513],[11, 731543] |
277
|
|
|
|
|
|
|
], |
278
|
|
|
|
|
|
|
'2004' => [ |
279
|
|
|
|
|
|
|
[12, 731572],[1, 731602],[2, 731631],[2.5, 731661],[3, 731690],[4, 731720], |
280
|
|
|
|
|
|
|
[5, 731750],[6, 731779],[7, 731809],[8, 731838],[9, 731868],[10, 731897], |
281
|
|
|
|
|
|
|
[11, 731927] |
282
|
|
|
|
|
|
|
], |
283
|
|
|
|
|
|
|
'2005' => [ |
284
|
|
|
|
|
|
|
[12, 731956],[1, 731986],[2, 732015],[3, 732045],[4, 732074],[5, 732104], |
285
|
|
|
|
|
|
|
[6, 732133],[7, 732163],[8, 732193],[9, 732222],[10, 732252],[11, 732281] |
286
|
|
|
|
|
|
|
], |
287
|
|
|
|
|
|
|
'2006' => [ |
288
|
|
|
|
|
|
|
[12, 732311],[1, 732340],[2, 732370],[3, 732399],[4, 732429],[5, 732458], |
289
|
|
|
|
|
|
|
[6, 732488],[7, 732517],[7.5, 732547],[8, 732576],[9, 732606],[10, 732636], |
290
|
|
|
|
|
|
|
[11, 732665] |
291
|
|
|
|
|
|
|
], |
292
|
|
|
|
|
|
|
'2007' => [ |
293
|
|
|
|
|
|
|
[12, 732695],[1, 732725],[2, 732754],[3, 732783],[4, 732813],[5, 732842], |
294
|
|
|
|
|
|
|
[6, 732871],[7, 732901],[8, 732930],[9, 732960],[10, 732990],[11, 733020] |
295
|
|
|
|
|
|
|
], |
296
|
|
|
|
|
|
|
'2008' => [ |
297
|
|
|
|
|
|
|
[12, 733049],[1, 733079],[2, 733109],[3, 733138],[4, 733167],[5, 733197], |
298
|
|
|
|
|
|
|
[6, 733226],[7, 733255],[8, 733285],[9, 733314],[10, 733344],[11, 733374] |
299
|
|
|
|
|
|
|
], |
300
|
|
|
|
|
|
|
'2009' => [ |
301
|
|
|
|
|
|
|
[12, 733403],[1, 733433],[2, 733463],[3, 733493],[4, 733522],[5, 733551], |
302
|
|
|
|
|
|
|
[5.5, 733581],[6, 733610],[7, 733639],[8, 733669],[9, 733698],[10, 733728], |
303
|
|
|
|
|
|
|
[11, 733757] |
304
|
|
|
|
|
|
|
], |
305
|
|
|
|
|
|
|
'2010' => [ |
306
|
|
|
|
|
|
|
[12, 733787],[1, 733817],[2, 733847],[3, 733876],[4, 733906],[5, 733935], |
307
|
|
|
|
|
|
|
[6, 733965],[7, 733994],[8, 734023],[9, 734053],[10, 734082],[11, 734112] |
308
|
|
|
|
|
|
|
], |
309
|
|
|
|
|
|
|
'2011' => [ |
310
|
|
|
|
|
|
|
[12, 734141],[1, 734171],[2, 734201],[3, 734230],[4, 734260],[5, 734290], |
311
|
|
|
|
|
|
|
[6, 734319],[7, 734349],[8, 734378],[9, 734407],[10, 734437],[11, 734466] |
312
|
|
|
|
|
|
|
], |
313
|
|
|
|
|
|
|
'2012' => [ |
314
|
|
|
|
|
|
|
[12, 734496],[1, 734525],[2, 734555],[3, 734584],[4, 734614],[4.5, 734644], |
315
|
|
|
|
|
|
|
[5, 734673],[6, 734703],[7, 734732],[8, 734762],[9, 734791],[10, 734821], |
316
|
|
|
|
|
|
|
[11, 734850] |
317
|
|
|
|
|
|
|
], |
318
|
|
|
|
|
|
|
'2013' => [ |
319
|
|
|
|
|
|
|
[12, 734880],[1, 734909],[2, 734939],[3, 734968],[4, 734998],[5, 735027], |
320
|
|
|
|
|
|
|
[6, 735057],[7, 735087],[8, 735116],[9, 735146],[10, 735175],[11, 735205] |
321
|
|
|
|
|
|
|
], |
322
|
|
|
|
|
|
|
'2014' => [ |
323
|
|
|
|
|
|
|
[12, 735234],[1, 735264],[2, 735293],[3, 735323],[4, 735352],[5, 735382], |
324
|
|
|
|
|
|
|
[6, 735411],[7, 735441],[8, 735470],[9, 735500],[9.5, 735530],[10, 735559], |
325
|
|
|
|
|
|
|
[11, 735589] |
326
|
|
|
|
|
|
|
], |
327
|
|
|
|
|
|
|
'2015' => [ |
328
|
|
|
|
|
|
|
[12, 735618],[1, 735648],[2, 735677],[3, 735707],[4, 735736],[5, 735765], |
329
|
|
|
|
|
|
|
[6, 735795],[7, 735824],[8, 735854],[9, 735884],[10, 735914],[11, 735943] |
330
|
|
|
|
|
|
|
], |
331
|
|
|
|
|
|
|
'2016' => [ |
332
|
|
|
|
|
|
|
[12, 735973],[1, 736002],[2, 736032],[3, 736061],[4, 736091],[5, 736120], |
333
|
|
|
|
|
|
|
[6, 736149],[7, 736179],[8, 736208],[9, 736238],[10, 736268],[11, 736297] |
334
|
|
|
|
|
|
|
], |
335
|
|
|
|
|
|
|
'2017' => [ |
336
|
|
|
|
|
|
|
[12, 736327],[1, 736357],[2, 736386],[3, 736416],[4, 736445],[5, 736475], |
337
|
|
|
|
|
|
|
[6, 736504],[6.5, 736533],[7, 736563],[8, 736592],[9, 736622],[10, 736651], |
338
|
|
|
|
|
|
|
[11, 736681] |
339
|
|
|
|
|
|
|
], |
340
|
|
|
|
|
|
|
'2018' => [ |
341
|
|
|
|
|
|
|
[12, 736711],[1, 736741],[2, 736770],[3, 736800],[4, 736829],[5, 736859], |
342
|
|
|
|
|
|
|
[6, 736888],[7, 736917],[8, 736947],[9, 736976],[10, 737006],[11, 737035] |
343
|
|
|
|
|
|
|
], |
344
|
|
|
|
|
|
|
'2019' => [ |
345
|
|
|
|
|
|
|
[12, 737065],[1, 737095],[2, 737125],[3, 737154],[4, 737184],[5, 737213], |
346
|
|
|
|
|
|
|
[6, 737243],[7, 737272],[8, 737301],[9, 737331],[10, 737360],[11, 737389] |
347
|
|
|
|
|
|
|
], |
348
|
|
|
|
|
|
|
'2020' => [ |
349
|
|
|
|
|
|
|
[12, 737419],[1, 737449],[2, 737478],[3, 737508],[4, 737538],[4.5, 737568], |
350
|
|
|
|
|
|
|
[5, 737597],[6, 737627],[7, 737656],[8, 737685],[9, 737715],[10, 737744], |
351
|
|
|
|
|
|
|
[11, 737774] |
352
|
|
|
|
|
|
|
], |
353
|
|
|
|
|
|
|
); |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
sub _year { |
356
|
2
|
|
|
2
|
|
4
|
my $y = shift; |
357
|
2
|
50
|
|
|
|
7
|
if ( !exists $year_cache{$y} ) { |
358
|
0
|
|
|
|
|
0
|
$year_cache{$y} = _compute_chinese_year($y); |
359
|
|
|
|
|
|
|
} |
360
|
2
|
|
|
|
|
12
|
return $year_cache{$y}; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub _compute_chinese_year { |
364
|
0
|
|
|
0
|
|
|
my $y = shift; |
365
|
0
|
|
|
|
|
|
my $oldtz = $Calendar::Any::Util::Solar::timezone; |
366
|
0
|
|
|
|
|
|
$Calendar::Any::Util::Solar::timezone = timezone($y); |
367
|
0
|
|
|
|
|
|
my $next_solstice = _zodiac_sign(Calendar::Any::Gregorian->new(12, 15, $y)); |
368
|
0
|
|
|
|
|
|
my $months = _month_list(_zodiac_sign(Calendar::Any::Gregorian->new(12, 15, $y-1))+1, |
369
|
|
|
|
|
|
|
$next_solstice); |
370
|
0
|
|
|
|
|
|
my $list; |
371
|
0
|
0
|
|
|
|
|
if ( scalar(@$months) == 12 ) { |
372
|
0
|
|
|
|
|
|
$list = [[12, $months->[0]], map { [ $_, $months->[$_] ]} 1..11]; |
|
0
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
} else { |
374
|
0
|
|
|
|
|
|
my $next_sign = _zodiac_sign($months->[0]); |
375
|
0
|
0
|
0
|
|
|
|
if ( $months->[0]>$next_sign || $next_sign >= $months->[1] ) { |
376
|
0
|
|
|
|
|
|
$list = [[11.5, $months->[0]], [12, $months->[1]], |
377
|
0
|
|
|
|
|
|
map { [ $_, $months->[$_+1] ] } 1..11]; |
378
|
|
|
|
|
|
|
} else { |
379
|
0
|
|
|
|
|
|
my @list = ([12, $months->[0]]); |
380
|
0
|
0
|
|
|
|
|
if ( _zodiac_sign($months->[1]) >= _zodiac_sign($months->[2]) ) { |
381
|
0
|
|
|
|
|
|
push @list, [12.5, $months->[1]], |
382
|
0
|
|
|
|
|
|
map { [ $_, $months->[$_+1] ] } 1..11; |
383
|
|
|
|
|
|
|
} else { |
384
|
0
|
|
|
|
|
|
push @list, [1, $months->[1]]; |
385
|
0
|
|
|
|
|
|
my $i = 2; |
386
|
0
|
|
|
|
|
|
while ( $months->[$i+1] > _zodiac_sign($months->[$i]) ) { |
387
|
0
|
|
|
|
|
|
push @list, [$i, $months->[$i]]; |
388
|
0
|
|
|
|
|
|
$i++; |
389
|
|
|
|
|
|
|
} |
390
|
0
|
|
|
|
|
|
push @list, [$i-0.5, $months->[$i]]; |
391
|
0
|
|
|
|
|
|
foreach ( $i..11 ) { |
392
|
0
|
|
|
|
|
|
push @list, [$_, $months->[$_+1]]; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
} |
395
|
0
|
|
|
|
|
|
$list = \@list; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} |
398
|
0
|
|
|
|
|
|
$Calendar::Any::Util::Solar::timezone = $oldtz; |
399
|
0
|
|
|
|
|
|
return $list; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub _zodiac_sign { |
403
|
0
|
|
|
0
|
|
|
int(Calendar::Any::Util::Solar::next_longitude_date(shift, 30)); |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
#========================================================== |
407
|
|
|
|
|
|
|
# Input : start, end, timezone |
408
|
|
|
|
|
|
|
# Output : the array of new moon date between start and end |
409
|
|
|
|
|
|
|
# Desc : start and end should be Calendar object or absolute date |
410
|
|
|
|
|
|
|
#========================================================== |
411
|
|
|
|
|
|
|
sub _month_list { |
412
|
0
|
|
|
0
|
|
|
my ($start, $end) = @_; |
413
|
0
|
|
|
|
|
|
my @list; |
414
|
0
|
|
|
|
|
|
while ( $start <= $end ) { |
415
|
0
|
|
|
|
|
|
$start = int(Calendar::Any::Util::Lunar::new_moon_date($start)); |
416
|
0
|
|
|
|
|
|
push @list, $start; |
417
|
0
|
|
|
|
|
|
$start++; |
418
|
|
|
|
|
|
|
} |
419
|
0
|
0
|
|
|
|
|
pop @list if $list[-1]>$end; |
420
|
0
|
|
|
|
|
|
return \@list; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
1; |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
__END__ |