## Billing Period

### May 18, 2018

I’m not sure of the origin of today’s exercise, but given the contrived nature of the calculation, I suspect it’s a programming exercise for beginning programming students:

Our merchants receive “weekly” invoices, following these rules:

• Each Saturday marks the beginning of a new billing period.
• Each 1st of a month marks the begining of a new billing period.
• Within a year, billing periods are numbered consecutively, starting with billing period 1 on January 1st.

Thus, a billing period can be referenced by a year and period number.

Your task is to write a program that calculates the billing period for a given date. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 5 Responses to “Billing Period”

1. Steve said

Mumps/Cache version

```billingperiod ;
q
;
go(dt)   ;
s dti=\$zdh(dt),dts="01/01/"_\$p(dt,"/",3),dtsi=\$zdh(dts)
s period=0
f i=dtsi:1:dti d
. e  i i#7=2 s period=period+1 ; Saturday
q period

---

f dt="01/01/2018","01/05/2018","01/06/2018","01/12/2018","01/13/2018","01/19/2018","01/20/2018","01/26/2018","01/27/2018","01/31/2018","02/01/2018","08/31/2018","09/01/2018","09/02/2018" w !,dt," -- ",\$\$go^billingperiod(dt)

01/01/2018 -- 1
01/05/2018 -- 1
01/06/2018 -- 2
01/12/2018 -- 2
01/13/2018 -- 3
01/19/2018 -- 3
01/20/2018 -- 4
01/26/2018 -- 4
01/27/2018 -- 5
01/31/2018 -- 5
02/01/2018 -- 6
08/31/2018 -- 42
09/01/2018 -- 43
09/02/2018 -- 43
```
2. WWW.ХХХ.ZСVIW.ХУZ said

What ?

3. Steve said

Mumps/Cache version, with comments and expanded commands, etc

```billingperiod ;
quit
;
go(dt)   ;
set dti=\$zdh(dt),dts="01/01/"_\$p(dt,"/",3),dtsi=\$zdh(dts) ; get internal date,external Jan 1 date,internal Jan 1 date
set period=0 ; initialize period count
for i=dtsi:1:dti do  ; loop through dates from Jan 1 to target date
. set adt=\$zd(i) ; get external form of date from loop
. if \$piece(adt,"/",2)="01" set period=period+1 ; if loop date is first of the month, increment counter
. else  if i#7=2 set period=period+1 ; Otherwise, if loop date is Saturday, increment counter
q period

---
; For each of these dates, print date and calculated period  (\$\$go^billingperiod is the called function)
for dt="01/01/2018","01/05/2018","01/06/2018","01/12/2018","01/13/2018","01/19/2018","01/20/2018","01/26/2018","01/27/2018","01/31/2018","02/01/2018","08/31/2018","09/01/2018","09/02/2018" write !,dt," -- ",\$\$go^billingperiod(dt)

01/01/2018 -- 1
01/05/2018 -- 1
01/06/2018 -- 2
01/12/2018 -- 2
01/13/2018 -- 3
01/19/2018 -- 3
01/20/2018 -- 4
01/26/2018 -- 4
01/27/2018 -- 5
01/31/2018 -- 5
02/01/2018 -- 6
08/31/2018 -- 42
09/01/2018 -- 43
09/02/2018 -- 43
```
4. Daniel said

Here’s a solution in C.

```#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int calc_julian(int year, int month, int day) {
int m1 = (month-14)/12;
int y1 = year+4800;
int julian = 1461*(y1+m1)/4;
julian += (367*(month-2-12*m1))/12;
julian += (-3*((y1+m1+100)/100))/4;
julian += day-32075;
return julian;
}

int calc_billing_period(int year, int month, int day) {
int billing_period = 0;
int start = calc_julian(year, 1, 1);
int end = calc_julian(year, month, day);
// Add the number of full weeks (each of these includes a Saturday).
int n_days = end - start + 1;
int n_full_weeks = n_days / 7;
billing_period += n_full_weeks;
// Add 1 if there is a Saturday in the partial week.
int remainder = n_days % 7;
int start_day = start % 7;
bool another_saturday = (remainder > 0)
&& (start_day != 6)
&& (start_day + remainder - 1 >= 5);
billing_period += another_saturday;
// Add the months that didn't start on Saturday.
for (int i = 1; i <= month; ++i) {
billing_period += (calc_julian(year, i, 1) % 7) != 5;
}
return billing_period;
}

int main(int argc, char* argv[]) {
if (argc != 4) {
fprintf(stderr, "Usage: %s <YEAR> <MONTH> <DAY>\n", argv[0]);
return EXIT_FAILURE;
}
int year = atoi(argv[1]);
int month = atoi(argv[2]);
int day = atoi(argv[3]);
int billing_period = calc_billing_period(year, month, day);
printf("%d\n", billing_period);
return EXIT_SUCCESS;
}
```

Example:

```\$ ./billing_period 2018 5 18
24
```
5. V said

In Ruby.

```require 'date'

def billing_period(date_str)
target_date  = Date.parse(date_str)
jan_first    = Date.new(target_date.year, 1,1)
(jan_first..target_date).reduce(0) do |period, date|
date.day == 1 || date.saturday? ? period + 1 : period
end
end

[
'2018-01-01',
'2018-01-03',
'2018-01-06',
'2018-01-10',
'2018-01-26',
'2018-02-01',
'2018-05-18'
].each do |date|
puts "#{date} -> #{billing_period(date)}"
end

```

Output:

2018-01-01 -> 1
2018-01-03 -> 1
2018-01-06 -> 2
2018-01-10 -> 2
2018-01-26 -> 4
2018-02-01 -> 6
2018-05-18 -> 24