good chemistry is complicated,and a little bit messy -LW PerlMonks

### Calculating Number Of Pay Periods

 on Oct 08, 2017 at 21:10 UTC Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I am working on a perl script to determine the number of pay periods remaining until retirement. I can calculate the number of days between now and the retirement date, but I have not been able to determine how to determine how many calendar months there are between now and the date in the future. Since payday is on the 1st and the 15th, determining the number of pay periods remaining should be pretty easy once I know the number of calendar months in the interval specified.

I have scoured this web site and Stack Overflow. DateTime::Duration and Date::Calc had a lot of good guidance, and I used some of those packages to determine other useful data, but otherwise, I cannot find a solution to my problem.

Any guidance in determining the number of pay periods in an interval is greatly appreciated.

Replies are listed 'Best First'.
Re: Calculating Number Of Pay Periods
by Anonymous Monk on Oct 08, 2017 at 21:30 UTC
```use strict;
use warnings;
use DateTime;

my \$now = DateTime->now(time_zone=>'local');
\$now->truncate(to=>'day');

my \$then = DateTime->new(time_zone=>'local',
year=>2019, month=>11, day=>23 );

print \$now->ymd," to ",\$then->ymd,"\n";

my \$diff = \$now->delta_md(\$then);
my (\$months,\$days) = \$diff->in_units('months','days');
print "\$months months and \$days days\n";

my \$weeks = \$now->delta_days(\$then)->in_units('weeks');
print "\$weeks weeks\n";

__END__

2017-10-08 to 2019-11-23
25 months and 15 days
110 weeks
Worked like a champ! Thank you.
Re: Calculating Number Of Pay Periods
by haukex (Abbot) on Oct 09, 2017 at 11:04 UTC

Here's yet another way to do it, using DateTime::Set for recurring events. It's also possible to modify the "recurrence" callback to shift the exact day if, for example, paydays can't be on a weekend, and there are even modules that calculate holidays for different regions.

```use warnings;
use strict;
use DateTime;
use DateTime::Set;

my \$paydays = DateTime::Set->from_recurrence(
start  => DateTime->now,
before => DateTime->new( year=>2019, month=>7, day=>1 ),
recurrence => sub {
my \$dt = shift;
return \$dt->day < 15
},
);

print "paydays: ",\$paydays->count,"\n";
# - or -
my \$iter = \$paydays->iterator;
while ( my \$dt = \$iter->next ) {
print \$dt->ymd, "\n";
}

__END__

paydays: 41
2017-10-15
2017-11-01
2017-11-15
...
2019-05-15
2019-06-01
2019-06-15
Re: Calculating Number Of Pay Periods
by choroba (Bishop) on Oct 09, 2017 at 11:30 UTC
Crossposted to reddit. It's considered polite to inform about crossposting to avoid unnecessary work of people who don't attend both the sites.

Moreover, it's OK to post just a link to reddit.

```(\$q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+\$1,++print+eval\$q,q,a,
Re: Calculating Number Of Pay Periods
by ww (Archbishop) on Oct 08, 2017 at 22:57 UTC

Ummmm...."Caution, Will Robinson!"

Perhaps your employer's procedure makes pay periods equivalent to the intervals between paydays... in which case, some paydays are for a longer pay period than others.

BUT
that just bends your mind and leads to complications beyond what you're trying to calculate.

All you really need to do -- based on the assertions in your OP -- is count months till you retire and multiply by two...and should you wish to use perl to do the arithmetic, you already have pointers to how to do it.

\$anecdote ne \$data ... and, rememember, check Ln42!

Re: Calculating Number Of Pay Periods (UPDATED)
by thanos1983 (Vicar) on Oct 09, 2017 at 10:27 UTC

Hello Anonymous Monk,

But also to point out that there is a beautiful module Date::Manip that contains a function called Date::Manip::Recur. There also some examples provided Date::Manip::Examples/RECURRING EVENTS which can retrieve the frequency from until specified date.

The beauty of this module is that you can change days, months, years, timezone(s) more or less what ever comes to your mind and you will get what you want.

Update For better and more accurate calculation use it like this:

```my \$start = ParseDate('now');
my \$end = "2017123123:59:59";

my (\$start, \$end) = qw(2017-01-01 2017-12-31);

Sample of code:

```#!/usr/bin/perl
use strict;
use warnings;
use Date::Manip;
use feature 'say';

my (\$start, \$end) = qw(2017-01-01 2017-12-31);

# y:m:w:d:h:m:s
my @days = ParseRecur('0:0:0:1:0:0:0', \$start, \$start, \$end);
my @weeks = ParseRecur('0:0:1::0:0:0', \$start, \$start, \$end);
my @months = ParseRecur('0:1:0::0:0:0', \$start, \$start, \$end);
my @years = ParseRecur('1:0:0::0:0:0', \$start, \$start, \$end);
my @datesEvery15th = ParseRecur('0:0:0:15:0:0:0', \$start, \$start, \$end
+);

say "Number of days: " . scalar @days;
say "Number of weeks: " . scalar @weeks;
say "Number of months: " . scalar @months;
say "Number of years: " . scalar @years;
say "Number of payments: " . scalar @datesEvery15th;

=print payment dates
for my \$date (@dates15th) {
say UnixDate(\$date, "%Y-%m-%d");
}
=cut

__END__

\$ perl test.pl
Number of days: 365
Number of weeks: 53
Number of months: 12
Number of years: 1
Number of payments: 25

Update2: To find out if the payment day is a working day or it will be shifted to the next working day. Read the POD for more information Date::Manip::DM5:

```for my \$date (@datesEvery15th) {
if (Date_IsWorkDay(\$date)) {
say UnixDate(\$date, "%Y-%m-%d");
}
else {
my \$nearestWorkingData = Date_NearestWorkDay(\$date);
say UnixDate(\$nearestWorkingData, "%Y-%m-%d");
}
}

__END__

2017-10-09
2017-10-24
2017-11-08
2017-11-23
2017-12-08
2017-12-22

Update3: An alternative way to know the exact time from today to what ever day you want that can easily be updated based on timezone. Sample of code below:

```#!/usr/bin/perl
use strict;
use warnings;
use Date::Manip;
use feature 'say';
use Data::Dumper;

my \$dateLocal = ParseDate('now');
# say \$dateLocal;

my \$end = "2017123123:59:59";

my \$dateStartLocal = ParseDate(\$dateLocal);
my \$dateEnd = ParseDate(\$end);

my \$deltaLocal = DateCalc( \$dateStartLocal,
\$dateEnd,
1 );
say \$deltaLocal;

my @dataLocal = split(/:/, \$deltaLocal);

my @values = qw(year(s) month(s) week(s) day(s) hour(s) minute(s));

my %hashLocal;
@hashLocal{@values} = @dataLocal;

print Dumper \%hashLocal;

###### Different Timezone(s) ######

# From timeZone To timeZone
my \$dateTimeZone = Date_ConvTZ(\$dateLocal,"GMT","CST");

my \$dateStartTimezone = ParseDate(\$dateLocal);

my \$deltaTimezone = DateCalc( \$dateStartTimezone,
\$dateEnd,
1 );
say \$deltaTimezone;

my @dataTimezone = split(/:/, \$deltaTimezone);

my %hashTinezone;
@hashTinezone{@values} = @dataTimezone;

print Dumper \%hashTinezone;

__END__

\$ perl test.pl
0:2:3:1:9:13:31
\$VAR1 = {
'week(s)' => '3',
'month(s)' => '2',
'minute(s)' => '13',
'hour(s)' => '9',
'day(s)' => '1',
'year(s)' => '0'
};
0:2:3:1:9:13:31
\$VAR1 = {
'year(s)' => '0',
'day(s)' => '1',
'minute(s)' => '13',
'hour(s)' => '9',
'week(s)' => '3',
'month(s)' => '2'
};

Hope this helps, BR.

Seeking for Perl wisdom...on the process of learning...not there...yet!

53 weeks in a year?

The way forward always starts with a minimal test.

Yes. The year is 365-366 days, depending, whereas weeks are 7 days (where 52 weeks is only 364 days: not a full year). Businesses often use "work weeks", and every once in a while, there is a "leap-week", to get the calendar back in sync, so the first work week of a year re-aligns with the start of the business's fiscal or calendar year. See more at ISO_week_date and ISO_8601.

Yup, if the year starts on a thursday (if you use ISO reckoning).

365 days are 52 weeks + 1 day. Every 6 years or so, you have 7 of these remaining days, and they, too, belong to a certain year…

Hello 1nickt,

You are right the year has 52 weeks and 1 or 2 day(s) depending upon the number of days in the year.

Sample of calculation on calendar common year 365 days:

```1 common year = 365 days = (365 days) / (7 days/week) = 52.143 weeks =
+ 52 weeks + 1 day

Sample of calculation on leap year has 366 days, when February has 29 days:

```1 leap year = 366 days = (366 days) / (7 days/week) = 52.286 weeks = 5
+2 weeks + 2 days

I was counting the remaining days as a week. So the solution is to remove the last input and count in total the remaining weeks:

Sample bellow before and after:

```#!/usr/bin/perl
use strict;
use warnings;
use Date::Manip;
use Data::Dumper;

my (\$start, \$end) = qw(2017-01-01 2017-12-31);

# y:m:w:d:h:m:s
my @weeks = ParseRecur('0:0:1::0:0:0', \$start, \$start, \$end);

print Dumper \@weeks;

=sample
\$VAR1 = [
'2017010100:00:00',
'2017010800:00:00',
'2017011500:00:00',
'2017012200:00:00',
.
.
.
'2017121700:00:00',
'2017122400:00:00',
'2017123100:00:00' # Not a week (remaining days)
];
=cut

pop @weeks;

say "Number of weeks: " . scalar @weeks;

print Dumper \@weeks;

=output
\$VAR1 = [
'2017010100:00:00',
'2017010800:00:00',
'2017011500:00:00',
'2017012200:00:00',
.
.
.
'2017121000:00:00',
'2017121700:00:00',
'2017122400:00:00' # Last week on 2017
];
=cut

BR / Thanos

Seeking for Perl wisdom...on the process of learning...not there...yet!

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1200953]
Approved by 1nickt
Front-paged by 1nickt
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2018-02-25 02:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
When it is dark outside I am happiest to see ...

Results (312 votes). Check out past polls.

Notices?