%D \module %D [ file=t-interval-calender, %D version=2023.04.15, %D title=Interval calendar \CONTEXT\ User Module, %D subtitle=Interval Calendar, %D author=Willi Egger, %D date=\currentdate, %D copyright=Willi Egger, %D email=w.egger@boede.nl, %D license=Public Domain] \startmodule[intervalcalendar] \writestatus{loading}{ConTeXt User Module / Interval Calendar} %D \startsubject[title=Introduction] %D After announcing a presentation for the 16th \CONTEXT -Meeting in Dreifelden, %D Germany, over a new version of the PocketDiary module, Taco Hoekwater asked %D whether the PocketDiary module might also be %D able to produce lists with calendar-dates in intervals like \quote{weekly}, %D \quote{twoweekly} or \quote{monthly} for the purpose of taking notes for %D checks on a regular base. -- The lists should be configurable for the length %D of the list, the number of columns and the possibility to assign an %D individual %D column-header. -- Quickly it appeared, that the use of the PocketDiary module %D is not necessary. In order to be able to do math on dates it is the easiest %D to convert a date to a timestamp in seconds or what is used by the %D operating-system. -- Due to the fact that there are repeating calculations %D done it is easiest to keep as much as possible at the lua end. Therefore the %D out-put is prepared as a \CONTEXT -LUA-document (cld). %D \stopsubject %D \startsubject[title=One Mode for Each List] %D %D The module can be used for the production of different lists. For each %D list we define a mode. \definemode[weekly][keep] \definemode[twoweekly][keep] \definemode[monthly][keep] %D None of the modes are activated. %D \stopsubject %D \startsubject[title=General Setups] \setupbodyfont[dejavu,ss,12pt] \setuppagenumbering[location=] \setuppapersize[A4,portrait][A4,portrait] \setuplayout [topspace=20mm, backspace=12mm, header=10mm, footer=2\bodyfontsize, height=middle, width=middle] \setupfootertexts [\jobname .pdf] [\pagenumber\ / \totalnumberofpages] %D \stopsubject %D \startsubject[title=LUA-Code] \startluacode thirddata = thirddata or { } thirddata.calendar = { } local calendar = thirddata.calendar local report = logs.reporter("Interval Checks") local interval_dates = {} function calendar.interval_checks(startdate,stopdate,cols,intval) local startdate_string =startdate local stopdate_string =stopdate local columns=cols local intervaldays = intval local year,month,day = calendar.date(startdate_string) local start_time_stamp = os.time({year=year,month=month,day=day}) --report("Starttimestamp: %s", start_time_stamp) local year,month,day = calendar.date(stopdate_string) local end_time_stamp = os.time{year=year,month=month,day=day} local interval = intervaldays * 24 * 60 * 60 for i = start_time_stamp, end_time_stamp, interval do local interval_date = os.date("%d-%m-%Y",i) table.insert(interval_dates,interval_date) report("%s",interval_date) end calendar.print_interval_checks(columns) end function calendar.print_interval_checks(cols) local columns = cols context.bTABLE({setups="table:interval_check"}) context.bTABLEhead() context.bTR() for i = 1,columns do context.bTH() context.labeltext("c"..i) context.eTH() end context.eTR() context.eTABLEhead() context.bTABLEbody() for k,v in ipairs(interval_dates) do context.bTR() context.bTD() context(v) context.eTD() for i=1,columns-1 do context.bTD() context.strut() context.eTD() end context.eTR() end context.eTABLEbody() context.eTABLE() end function calendar.date(inputstr) --report("Input : %s",inputstr) local sep = "%-%s/" if sep == nil then sep = "%s" end local t={} i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str --report("Actual string %s", str) i = i + 1 end --report("Datum strings: %s, %s, %s", t[1],t[2],t[3]) return t[1],t[2],t[3] end \stopluacode %D The main function is the \quote{calendar.interval_ckecks} function %D with 4 parameters. The function needs a start-date, an end-date, %D the number of columns for the table in the out-put and the interval %D in days. The function calculates all dates fitting into the start %D and end dates based on the epoch-time. It converts the timestamp %D into a human readable date format and puts the values into a %D table \quote{interval_dates}. %D %D The second function is called from within the first function and %D gets the number of columns as parameter. This function creates the %D out-put table. It is a flexible setup, which is based on the %D number of the columns provided as a parameter. Label-texts are used %D for the column heads and the column heads are repeated at the top %D of each following page. %D %D The third function is there to deal with the preparation of the dates, %D which are sent to LUA as strings. It extracts the year (yyyy) the %D month (m) and day (d). The extracted values are put into a table. The dates %D can be entered in the format 2022-8-21 or as 2022/8/21. %D \stopsubject %D \startsubject[title=Macro for Calling the List Generator] %D The command needs 4 parameters: Start-date, stop-date, number of %D columns in the table and the interval in days. \define[4]\Checklist{\ctxlua{thirddata.calendar.interval_checks(#1,#2,#3,#4)}} %D \stopsubject %D \startsubject[title=Setups for the Out-Put Table] %D The layout of the out-put table is organized at the \TEX\ end. If %D the table design changes in terms of more or less columns, this %D setup has to be adapted. \startsetups table:interval_check \setupTABLE[split=repeat] \setupTABLE[r][each][height=12mm,align=lohi] \setupTABLE[r][1][style=bold,align={lohi,middle}] \setupTABLE[c][1][width=0.2\textwidth] \setupTABLE[c][2,3,4][width=0.15\textwidth] \setupTABLE[c][5][width=0.3\textwidth] \stopsetups %D \stopsubject %D \startsubject[title=Column Head Texts] %D It has been chosen to use the label-text mechanism to implement %D the head texts of the columns. Depending on the design of the %D out-put table the names can be adapted, the list can be made longer %D or shorter according to the needs. \setuplabeltext[en][c1=Datum] \setuplabeltext[en][c2=Gas] \setuplabeltext[en][c3=Electricity] \setuplabeltext[en][c4=Water] \setuplabeltext[en][c5=Observation] %D \stopsubject %D \startsubject[title=Header Texts of Out-Put] %D %D Also for the header texts the label text mechanism is used. Now only three %D intervals are defined, but this mechanism allows easily to extend the list %D of possible header texts. It also allows to implement other languages. %D Depending on the setting of the \type{\mainlanguage[]} the correct labels %D are picked up and typeset. \setuplabeltext[en][weekly={Weekly Checks}] \setuplabeltext[en][twoweekly={Two-weekly Checks}] \setuplabeltext[en][monthly={Monthly Checks}] \setuplabeltext[de][weekly={Wochen Checks}] \setuplabeltext[de][twoweekly={Zwei Wochen Checks}] \setuplabeltext[de][monthly={Monatliche Checks}] \setuplabeltext[nl][weekly={Weekelijkse Checks}] \setuplabeltext[nl][twoweekly={Twee-weekelijkse Checks}] \setuplabeltext[nl][monthly={Maandelijkse Checks}] %D \stopsubject %D \startsubject[title=Header Text Setup] %D Each list gets a header text fitting the purpose of the list. \startmode[weekly] \setupheadertexts [\midaligned{\bfc \labeltext{weekly}}] [] \stopmode \startmode[twoweekly] \setupheadertexts [\midaligned{\bfc \labeltext{twoweekly}}] [] \stopmode \startmode[monthly] \setupheadertexts [\midaligned{\bfc \labeltext{monthly}}] [] \stopmode %D \stopsubject \stopmodule