File Coverage

lib/Date/Cutoff/JP.pm
Criterion Covered Total %
statement 56 56 100.0
branch 8 10 80.0
condition 5 5 100.0
subroutine 11 11 100.0
pod 1 1 100.0
total 81 83 97.5


line stmt bran cond sub pod time code
1             package Date::Cutoff::JP;
2 7     7   419412 use 5.008001;
  7         73  
3 7     7   46 use strict;
  7         13  
  7         176  
4 7     7   56 use warnings;
  7         28  
  7         361  
5              
6             our $VERSION = "0.06";
7              
8 7     7   41 use Carp;
  7         9  
  7         481  
9 7     7   3144 use Time::Seconds;
  7         22398  
  7         440  
10 7     7   3473 use Time::Piece;
  7         57601  
  7         27  
11             my $tp = Time::Piece->new();
12 7     7   3964 use Calendar::Japanese::Holiday;
  7         22523  
  7         451  
13 7     7   3076 use Date::DayOfWeek;
  7         11444  
  7         365  
14              
15 7     7   3869 use Moose;
  7         3278765  
  7         49  
16              
17             has cutoff => ( is => 'rw', isa => 'Int', default => 0 );
18             has payday => ( is => 'rw', isa => 'Int', default => 0 );
19             has late => ( is => 'rw', isa => 'Int', default => 1 );
20              
21             before 'cutoff' => sub {
22             my $self = shift;
23             my $value = shift;
24             return super() unless defined $value;
25             croak "unvalid cutoff was set: $value" if $value < 0 or 28 < $value;
26             my $day = $value? $value: 31;
27             croak "cuttoff must be before payday" if $day >= $self->payday and $self->late == 0;
28             return super();
29             };
30              
31             before 'payday' => sub {
32             my $self = shift;
33             my $value = shift;
34             return super() unless defined $value;
35             croak "unvalid payday was set: $value" if $value < 0 or 28 < $value;
36             my $day = $value? $value: 31;
37             croak "payday must be after cuttoff" if $day <= $self->cutoff and $self->late == 0;
38             return super();
39             };
40              
41             before 'late' => sub {
42             my $self = shift;
43             my $value = shift;
44             return super() unless defined $value;
45             croak "unvalid lateness was set: $value" if $value < 0 or 2 < $value;
46             my( $cutoff, $payday ) = ($self->cutoff, $self->payday);
47             croak "payday is before cuttoff in same month" if $value == 0 and $payday <= $cutoff;
48             return super();
49             };
50              
51             __PACKAGE__->meta->make_immutable;
52              
53             sub _isWeekend {
54 278     278   2342 my $self = shift;
55 278         886 my ($y, $m, $d ) = split "-", shift;
56 278         765 my $dow = dayofweek( $d, $m, $y );
57 278   100     10034 return isHoliday( $y, 0+$m, 0+$d, 1 ) || $dow == 6 || $dow == 0;
58             }
59              
60             sub calc_date {
61 72     72 1 77805 my $self = shift;
62 72 50       216 my $until = shift if @_;
63 72 50       242 my $t = $until? $tp->strptime( $until, '%Y-%m-%d' ) : localtime();
64            
65 72 100       7455 my $cutoff = $self->cutoff? $self->cutoff: $t->month_last_day();
66 72         627 my $str = $t->strftime('%Y-%m-') . sprintf( "%02d", $cutoff );
67 72         2750 my $ref_day = $t->strptime( $str, '%Y-%m-%d');
68 72         5988 my $over = 0;
69 72 100       176 if ( $ref_day->epoch() < $t->epoch() ) {
70 12         124 $over = 1;
71 12         25 $ref_day += ONE_DAY() * $ref_day->month_last_day();
72             }
73            
74 72         1499 $cutoff = $ref_day->ymd();
75 72         1126 while( $self->_isWeekend($cutoff) ){
76 60         19360 my $ref_day = $t->strptime( $cutoff, '%Y-%m-%d');
77 60         4903 $ref_day += ONE_DAY();
78 60         3203 $cutoff = $ref_day->ymd();
79             }
80            
81 72   100     16511 $ref_day += ONE_DAY() * 28 * ( $self->late || 0 );
82 72         4507 $str = $ref_day->strftime('%Y-%m-%d');
83 72         2007 $ref_day = $t->strptime( $str, '%Y-%m-%d');
84              
85 72 100       5921 my $payday = $self->payday? $self->payday: $ref_day->month_last_day();
86 72         950 $str = $ref_day->strftime('%Y-%m-') . sprintf( "%02d", $payday );
87            
88 72         2570 my $date = $t->strptime( $str, '%Y-%m-%d' )->ymd();
89 72         6869 while( $self->_isWeekend($date) ){
90 74         22643 my $ref_day = $t->strptime( $date, '%Y-%m-%d');
91 74         6029 $ref_day += ONE_DAY();
92 74         3955 $date = $ref_day->ymd();
93             }
94 72         19166 return ( cutoff => $cutoff, payday => $date, is_over => $over );
95             }
96              
97             1;
98             __END__
99              
100             =encoding utf-8
101              
102             =head1 NAME
103              
104             Date::CutOff::JP - Get the day cutoff and payday for in Japanese timezone
105              
106             =head1 SYNOPSIS
107              
108             use Date::CutOff::JP;
109             my $dco = Date::CutOff::JP->new({ cutoff => 0, late => 1, payday => 0 });
110             my %calculated = $dco->calc_date('2019-01-01');
111             print $calculated{'cutoff'}; # '2019-01-31'
112             print $calculated{'payday'}; # '2019-02-28'
113              
114             =head1 DESCRIPTION
115              
116             Date::CutOff::JP provides how to calculate the day cutoff and the payday from Japanese calendar.
117              
118             You can calculate the weekday for cutoff and paying without holidays in Japan.
119            
120             =head1 Constructor
121              
122             =head3 new({ [cutoff => $day], [payday => $day], [late => 0||1||2] })
123            
124             You may omit parameters. defaults are { cutoff => 0, payday => 0, late => 1 }
125            
126             =head2 Accessor Methods
127            
128             =head3 cutoff()
129            
130             get/set the day cutoff in every months. 0 means the end of the month.
131            
132             B<caution> Int over 28 is denied
133              
134             =head3 payday()
135            
136             get/set the payday in every months. 0 means the end of the month.
137            
138             B<caution> Int over 28 is denied
139              
140             =head3 late()
141            
142             get/set the lateness. 0 means the cutoff and payday is at same month.
143              
144             The all you can set is Int of [ 0 .. 2 ] 3 or more returns error.
145            
146             =head2 Method
147              
148             =head3 calc_date([$date])
149              
150             You may omit the parameter. default is TODAY.
151            
152             returns hash value with keys below:
153              
154             =over
155            
156             =item cutoff
157              
158             The latest cutoff after $date.
159            
160             =item payday
161            
162             The latest payday after $date.
163              
164             =item is_over ( maybe bad key name )
165            
166             Is or not that the cutoff is pending until next month.
167              
168             =back
169            
170             =head1 BUGS
171              
172             =head1 SEE ALSO
173            
174             L<Calendar::Japanese::Holiday>,L<Date::DayOfWeek>
175            
176             L<日本の祝日YAML|https://github.com/holiday-jp/holiday_jp/blob/master/holidays.yml>
177            
178             =head1 LICENSE
179              
180             Copyright (C) worthmine.
181              
182             This library is free software; you can redistribute it and/or modify
183             it under the same terms as Perl itself.
184              
185             =head1 AUTHOR
186              
187             worthmine E<lt>worthmine@cpan.orgE<gt>
188            
189             =cut