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.

Advertisement

Pages: 1 2

5 Responses to “Billing Period”

  1. Steve said

    Mumps/Cache version

    billingperiod ;
             q
             ;
    go(dt)   ;
             n adt,dti,dts,dtsi,i,period
             s dti=$zdh(dt),dts="01/01/"_$p(dt,"/",3),dtsi=$zdh(dts)
             s period=0
             f i=dtsi:1:dti d
             . s adt=$zd(i)
             . i $p(adt,"/",2)="01" s period=period+1
             . 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)   ;
             new adt,dti,dts,dtsi,i,period ; initialize variables
             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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: