25.02.2021, 09:49
I'm sharing this script for a purpose of using "do not run on holidays" exception in the scheduler. The main concern was on how to obtain proper schedule of all weekends and holidays for the year without having to enter them manually. This script does that using 3rd party service.
It can be configured with the country code, and the best way to use it is to create it as a scheduled script to run once a year on the date of your choice (for ex. middle of December).
Note that it will clean up existing holidays schedule! Check if service returns correct schedule for your country before use.
It can be configured with the country code, and the best way to use it is to create it as a scheduled script to run once a year on the date of your choice (for ex. middle of December).
Note that it will clean up existing holidays schedule! Check if service returns correct schedule for your country before use.
Code:
-- Fills in holiday schedule for this and next years
-- License: do whatever you want
local http = require('socket.http')
local ltn12 = require('ltn12')
local country_code = 'ru'
function get_holidays(year)
local url = string.format('https://isdayoff.ru/api/getdata?cc=%s&year=%s', country_code, year)
local tbl = {}
local status, code = http.request({
url = url,
sink = ltn12.sink.table(tbl)
})
if(status) then
return table.concat(tbl)
else
error(string.format('Failed to get holidays for the year: status(%s), code(%s)', status, code))
return ''
end
end
function day_to_date(year, day)
return os.date('*t', os.time({year=year, month=1, day=day}))
end
function holiday_iterator(year, data)
local workday = string.byte('0')
local len = #data
local i = 0
return function()
while(i < len) do
i = i + 1
if(data:byte(i) ~= workday) then
return day_to_date(year, i)
end
end
end
end
function create_record(date, duration)
local name = string.format('%s.%02d.%02d', date.year, date.month, date.day)
if(duration > 1) then
local nd = day_to_date(date.year, date.yday + duration - 1)
name = string.format('%s-%02d.%02d', name, nd.month, nd.day)
end
if(date.wday == 7) then
name = string.format('weekend (%s)', name)
end
return {
name = name,
year = date.year,
month = date.month,
day = date.day,
duration = duration,
}
end
function holiday_group_iterator(year, data)
local accum = nil
local iter = holiday_iterator(year, data)
return function()
local res = nil
repeat
local date = iter()
if(date and accum and date.yday == (accum.date.yday + accum.duration)) then
-- group if we can
accum.duration = accum.duration + 1
else
-- return result and restart accumulator
res = accum
accum = {
date = date,
duration = 1,
}
end
if(res and res.date) then
return create_record(res.date, res.duration)
end
until accum == nil or accum.date == nil
end
end
function delete_holidays()
db:query('DELETE FROM scheduler_holidays')
end
function create_holidays(year)
for record in holiday_group_iterator(year, get_holidays(year)) do
db:insert('scheduler_holidays', record)
--log('inserting', record.name)
end
end
delete_holidays()
local this_year = os.date('*t').year
create_holidays(this_year)
create_holidays(this_year + 1)