# AllBASIC

## BASIC User Group => Code Challenges => Topic started by: jalih on November 06, 2018, 10:03:36 am

Title: Calculate week number
Post by: jalih 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;`
Title: Re: Calculate week number
Post by: John 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
\$
Title: Re: Calculate week number
Post by: jalih 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.  ???
Title: Re: Calculate week number
Post by: John on November 06, 2018, 03:12:11 pm
PHP

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

\$ php weeknow.php
45
\$

Title: Re: Calculate week number
Post by: John 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
\$

Title: Re: Calculate week number
Post by: AIR 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.
Title: Re: Calculate week number
Post by: AIR 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.
Title: Re: Calculate week number
Post by: John on November 06, 2018, 09:09:55 pm
I swear SB had a WEEKNUMBER() or FORMATDATE() option to return the week number. No joy.  :-\
Title: Re: Calculate week number
Post by: AIR 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.
Title: Re: Calculate week number
Post by: AIR 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: Script BASIC
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: Script BASIC
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
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.
Title: Re: Calculate week number
Post by: John 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.

Title: Re: Calculate week number
Post by: AIR on November 07, 2018, 06:28:06 am
One way of doing it:

Code: Script BASIC
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.
Title: Re: Calculate week number
Post by: John 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.
Title: Re: Calculate week number
Post by: AIR on November 07, 2018, 09:40:44 am
Or........

(https://binarymagic.net/images/formatdate.png)

Code: Script BASIC
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
Title: Re: Calculate week number
Post by: AIR 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.

Title: Re: Calculate week number
Post by: John on November 07, 2018, 10:05:07 am
There was no WEEKNUM option in the FORMATDATE() function docs. I even looked at the SB source. I was really surprised Peter missed it.

Obviously NOT.
Title: Re: Calculate week number
Post by: AIR on November 07, 2018, 10:11:24 am
There was no WEEKNUM option in the FORMATDATE() function docs. I even looked at the SB source. I was really surprised Peter missed it.

Obviously NOT.

AIR.
Title: Re: Calculate week number
Post by: John on November 07, 2018, 11:38:33 am
Sounds like a great plan.

I can't thank you enough for all your efforts. You breath life into everything you do.
Title: Re: Calculate week number
Post by: John on November 07, 2018, 12:38:42 pm
I would like to thank jalih for starting this challenge. A good challenge that ended up filling a hole in SB.
Title: Re: Calculate week number
Post by: AIR on December 13, 2018, 04:09:58 pm
MBC Version:

Code: Text
1. \$EXECON
2.
3. print "Today is: ", time\$(FULLDATE), " and the Week Number is: ", time\$(WEEKNUMBER)
4.

[riveraa@MPD ~/Projects/mbc] \$ ./datetest
Today is: Thursday, December 13, 2018 and the Week Number is: 50
[riveraa@MPD ~/Projects/mbc] \$

I'm going to add NAMED PARAMETERS so that you don't need to look up what each number fed to TIME\$() represents....

Options are:

TIME - HH:MM:SS,
HOUR - HH,
MINUTE - MM,
SECOND - SS,
APM - AM/PM,
YEAR - YYYY,
MONTH - MONTH NUMBER,
DAY - DAY NUMBER,
DAYNAME - NAME OF DAY,
WEEKDAY - NUMBER OF DAY IN WEEK ,
YEARDAY - NUMBER OF DAY IN YEAR,
WEEKNUMBER - NUMBER OF WEEK IN YEAR,
DATE - MONTH/DAY/SHORT YEAR,
FULLDATE - NAME OF DAY, NAME OF MONTH, DAY, FULL YEAR

All are based on current date.

AIR.