Author Topic: Calculate week number  (Read 8506 times)

Offline jalih

  • Advocate
  • Posts: 111
Calculate week number
« on: November 06, 2018, 10:03:36 AM »
Your challenge is to write a procedure that returns the week number for a given date. If week number belongs to a week numbering of the previous year then that week number should be returned instead of the zero week.

Here is my PL/I version using bit strings to turn calculations into simple string search:
Code: [Select]

*PROCESS MARGINS(1, 140);

 test: proc options (main);
   dcl 1 date_type based,
         2 day   pic'99',
         2 month pic'99',
         2 year  pic'9999';

   dcl d like date_type;

   /* fill date structure */
   d.day   = '06';
   d.month = '11';
   d.year =  '2018';

   /* test our proggy */
   put skip list (trim(week(d)));

 /****************************************************************************************************************/
   week: proc (day) returns (fixed bin (31));
     dcl day like date_type;

     dcl (from, to) like date_type;
     dcl (days_from, days_to) fixed bin (31);
     dcl total_days fixed bin (31);
     dcl week_index fixed bin (31);
     dcl weeknro fixed bin (31);
     dcl result bit (*) aligned controlled;
     dcl weeks (7) bit (7) aligned nonasgn
         init ('0100000'b, '0010000'b, '0001000'b, '0000100'b, '0000100'b, '0000010'b, '0000001'b);
     dcl masks (7) bit (7) aligned nonasgn
         init ('0111100'b, '1111000'b, '1110001'b, '1100011'b, '1000111'b, '0001111'b, '0011110'b);
     dcl bool bit (1);

     dcl (days, weekday, tally, substr, lbound, hbound, copy, omitted) builtin;

     /* we start from first of january, naturally */
     from.day   = '01';
     from.month = '01';
     from.year  = day.year;

     to = day;

     days_from = days(string(from), 'DDMMYYYY');
     days_to   = days(string(to), 'DDMMYYYY');

     /* calculate required length for the bit string */
     total_days = days_to - days_from + 1;

     /* allocate bit string, holding date range */
     allocate result bit (total_days);

     /* fill bit string with correct rotation of the week pattern */
     week_index = weekday(days_from);
     result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));

     /* find the number of weeks starting on monday */
     weeknro = tally(result, '1'b);

     /* free allocated storage */
     free result;

     /* first week can be partial and if it includes thursday, then add it to the result */
     bool = substr(masks(week_index), 1, 1);
     if bool then weeknro += 1;

     /* maybe first days of the year belong to week numbering of the previous year? */
     if weeknro = 0 then
       do;
         from.year -= 1;
         to = from;
         to.day   = '31';
         to.month = '12';

         days_from = days(string(from), 'DDMMYYYY');
         days_to   = days(string(to), 'DDMMYYYY');

         total_days = days_to - days_from + 1;
         allocate result bit (total_days);

         week_index = weekday(days_from);

         result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));
         weeknro = tally(result, '1'b);
         free result;
       end;
     return (weeknro);
   end week;
 /****************************************************************************************************************/
 end test;

Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #1 on: November 06, 2018, 11:27:09 AM »
Perl

Code: Perl
  1. use DateTime;
  2.  
  3. print DateTime->now->week_number,"\n";
  4.  


$ perl weeknow.pl
45
$

Offline jalih

  • Advocate
  • Posts: 111
Re: Calculate week number
« Reply #2 on: November 06, 2018, 11:54:27 AM »
Perl
Code: Perl
  1. use DateTime;
  2.  
  3. print DateTime->now->week_number,"\n";
  4.  

Okay, that is certainly shorter than my PL/I version.  ???

Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #3 on: November 06, 2018, 03:12:11 PM »
PHP

Code: PHP
  1. <?php
  2. echo date('W')."\n";
  3. ?>
  4.  


$ php weeknow.php
45
$




Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #4 on: November 06, 2018, 03:41:47 PM »
Python

Code: Python
  1. from datetime import date
  2.  
  3. print date.today().isocalendar()[1]
  4.  


$ python weeknow.py
45
$



Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #5 on: November 06, 2018, 07:12:41 PM »
Your challenge is to write a procedure that returns the week number for a given date. If week number belongs to a week numbering of the previous year then that week number should be returned instead of the zero week.

Sometimes the most obvious solution is one that isn't considered:

Code: Bash
  1. /bin/date -d "20100215" +%V

Returns Week #7 of 2010.   ;D ;D

AIR.

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #6 on: November 06, 2018, 08:55:27 PM »
Okay, all kidding aside, here's a function written in BaCon (compile with: bacon -y -o -D_GNU_SOURCE weekofdate.bac):

Code: Text
  1. PRAGMA INCLUDE <time.h>
  2.  
  3. DECLARE tmm TYPE struct tm
  4.  
  5. PROTO strptime
  6. PROTO strftime
  7.  
  8.  
  9. FUNCTION getWeekNumber$(int yr, int mon, int day) TYPE STRING
  10.     LOCAL format$
  11.     PRINT yr,mon,day FORMAT "%d-%02d-%02d" TO format$
  12.     strptime(format$, "%Y-%m-%d", &tmm)
  13.     strftime(format$, SIZEOF(format$), "%V", &tmm)
  14.     RETURN format$
  15. END FUNCTION
  16.  
  17.  
  18. PRINT "WEEK Number is: ", getWeekNumber$(2010,02,15)
  19.  

AIR.

Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #7 on: November 06, 2018, 09:09:55 PM »
I swear SB had a WEEKNUMBER() or FORMATDATE() option to return the week number. No joy.  :-\

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #8 on: November 06, 2018, 09:40:56 PM »
You're getting old, John.  You have FORMATDATE and TIMEVALUE.  LOL.

Look in examples/testtime.bas.

Geez, I don't even use SB that much and I know this!!!

AIR.

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #9 on: November 06, 2018, 10:28:39 PM »
This is one of those things you could stick in a utility module.  I called it "timeutils".

Code: ScriptBasic
  1. import timeutils.bas
  2.  
  3. print timeutils::WeekNumber(2015,02,15)
  4.  

riveraa@nas:~/src/sb_ubuntu-64$ ./AppRun testweek.bas
07


Interface:

Code: ScriptBasic
  1. /*
  2. READ THIS FILE AND CHANGE THE SOURCE WHEREVER YOU SEE COMMENTS STARTING
  3. WITH THE WORD *TODO*
  4.  
  5. WHEN YOU ARE FINISHED YOU CAN
  6.  
  7.   FILE   : interface.c
  8.   HEADER : interface.h
  9.   BAS    : timeutils.bas
  10.   AUTHOR : AIR
  11.  
  12.   DATE:
  13.  
  14.   CONTENT:
  15.   This is the interface.c file for the ScriptBasic module timeutils
  16. ----------------------------------------------------------------------------
  17.  
  18.  
  19.  
  20. UXLIBS:-lm -ldl
  21. ----------------------------------------------------------------------------
  22.  
  23. DWLIBS:
  24.  
  25. */
  26.  
  27.  
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <time.h>
  33. #include "../../basext.h"
  34.  
  35.  
  36. typedef struct _ModuleObject {
  37.   char a; /* You may delete this. It is here to make the initial interface.c compilable. */
  38.   }ModuleObject,*pModuleObject;
  39.  
  40.  
  41.  
  42. besVERSION_NEGOTIATE
  43.   return (int)INTERFACE_VERSION;
  44. besEND
  45.  
  46.  
  47. besSUB_ERRMSG
  48.  
  49.   switch( iError ){
  50.     case 0x00080000: return "ERROR HAS HAPPENED";
  51.     }
  52.   return "Unknown timeutils module error.";
  53. besEND
  54.  
  55.  
  56. besSUB_START
  57.   pModuleObject p;
  58.  
  59.   besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
  60.   if( besMODULEPOINTER == NULL )return 0;
  61.  
  62. besEND
  63.  
  64.  
  65. besSUB_FINISH
  66.   pModuleObject p;
  67.  
  68.   /*
  69.     YOU CERTAINLY NEED THIS POINTER TO FREE ALL RESOURCES THAT YOU ALLOCATED
  70.     YOU NEED NOT CALL besFREE TO FREE THE MEMORY ALLOCATED USING besALLOC
  71.     CLOSE ANY FILE THAT REMAINED OPEN, RELEASE DATABASE HANDLES AND ALL
  72.     OTHER RESOURCES INCLUDING MEMORY *NOT* ALLOCATED CALLING besALLOC
  73.   */
  74.   p = (pModuleObject)besMODULEPOINTER;
  75.   if( p == NULL )return 0;
  76.  
  77.   return 0;
  78. besEND
  79.  
  80.  
  81. /**
  82. =section WeekNumber
  83. =H title that goes into the BASIC documentation for this function
  84.  
  85. detail here what the function does so that the BASIC programmer
  86. can understand how he/she can use it
  87. */
  88. besFUNCTION(WeekNumber)
  89.   pModuleObject p;
  90.   struct tm tm;
  91.   char format[32];
  92.   int yr,mon,day;
  93.  
  94.   p = (pModuleObject)besMODULEPOINTER;
  95.  
  96.   besARGUMENTS("iii")
  97.   &yr,&mon,&day
  98.   besARGEND
  99.  
  100.   sprintf(format,"%d-%02d-%02d",yr,mon,day);
  101.   strptime(format, "%Y-%m-%d", &tm);
  102.   strftime(format, sizeof(format),"%V", &tm);
  103.   besSET_RETURN_STRING(format);
  104. besEND
  105.  
  106.  
  107. SLFST TIMEUTILS_SLFST[] ={
  108.  
  109. { "versmodu" , versmodu },
  110. { "bootmodu" , bootmodu },
  111. { "finimodu" , finimodu },
  112. { "emsgmodu" , emsgmodu },
  113. { "WeekNumber" , WeekNumber },
  114. { NULL , NULL }
  115.   };
  116.  

AIR.

Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #10 on: November 06, 2018, 10:49:45 PM »
You are the master extension builder! SQLite, MiniXML, ...

THANKS!

Quote
You're getting old, John.  You have FORMATDATE and TIMEVALUE.  LOL.

Neither helps to return a week number.

FWIW

I tried to use the SQLite DateTime() function to return to week number (%W) but it didn't seem to work.

« Last Edit: November 07, 2018, 01:39:52 AM by John »

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #11 on: November 07, 2018, 06:28:06 AM »
One way of doing it:

Code: ScriptBasic
  1. INCLUDE sqlite.bas
  2.  
  3. hdb=sqlite::open("testsql")
  4. sqlite::execute(hdb,"create table demo (week text);")
  5. sqlite::execute(hdb, "INSERT INTO demo VALUES (strftime('%W','now'));")
  6. stmt = sqlite::query(hdb,"SELECT week FROM demo;")
  7. while (sqlite::row(stmt) = 100)
  8.         print sqlite::row_value(stmt,0),"\n"
  9. wend
  10.  
  11. sqlite::close(hdb)

AIR.

Offline John

  • Forum Support / SB Dev
  • Posts: 3597
    • ScriptBasic Open Source Project
Re: Calculate week number
« Reply #12 on: November 07, 2018, 08:14:34 AM »
Cool!

I was a little Lite with my SQL code.

I'm officially adding your WEEKNUMBER() function to the T (Tools) extension module today.
« Last Edit: November 07, 2018, 08:58:34 AM by John »

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #13 on: November 07, 2018, 09:40:44 AM »
Or........


Code: ScriptBasic
  1. print formatdate("Today is WDN MON DD, YEAR"),"\n"
  2.  
  3. print formatdate("The current week number of the year is: WEEKNUM"),"\n"

AIR.

Edit:  Set img to a more reasonable size!! LOL
« Last Edit: November 07, 2018, 09:44:19 AM by AIR »

Offline AIR

  • BASIC Developer
  • Posts: 932
  • Coder
Re: Calculate week number
« Reply #14 on: November 07, 2018, 09:55:15 AM »
I'm officially adding your WEEKNUMBER() function to the T (Tools) extension module today.

Note that it makes use of a function that is not available in VC on Windows, but IS available in MinGW.