netlogo

execute monthly task at end of month with netlogo time:schedule-repeating-event-with-period


I need to run a procedure once a month at the end of the month. I haven't found specific primitives for this, so I figured out this code.

I can start my simulation when I want by inputting a date in the interface, the global is start-date-default

So I instantiate the model and anchor ticks to this start time.

;; holds last day for each month
set month-end table:make
table:put month-end 1 31
table:put month-end 2 28
table:put month-end 3 31
table:put month-end 4 30
table:put month-end 5 31
table:put month-end 6 30
table:put month-end 7 31
table:put month-end 8 31
table:put month-end 9 30
table:put month-end 10 31
table:put month-end 11 30
table:put month-end 12 31

set start-date time:create-with-format start-date-default "dd-MM-YYYY"
set tick-date time:anchor-to-ticks start-date 1 "day"
time:anchor-schedule start-date 1 "day"

;; to find end of month for the select start month I do
let month time:get "month" tick-date
let day table:get month-end month
let year time:get "year" tick-date
let end-of-month time:create-with-format (word day ifelse-value month < 10 ["-0"]["-"] month "-" year) "dd-MM-YYYY"

at this point something weird happens. If I run the procedure every two months, like:

time:schedule-repeating-event-with-period (one-of org) [ -> pay-bills ] end-of-month 2 "month"

if I run for, say, 11 months, I correctly have this output:

(org 0): "monthly pay-bills{{time:logotime 31-01-2023}}"
(org 0): "monthly pay-bills{{time:logotime 31-03-2023}}"
(org 0): "monthly pay-bills{{time:logotime 31-05-2023}}"
(org 0): "monthly pay-bills{{time:logotime 31-07-2023}}"
(org 0): "monthly pay-bills{{time:logotime 30-09-2023}}"
(org 0): "monthly pay-bills{{time:logotime 30-11-2023}}"

however, if I run the procedure monthly like:

time:schedule-repeating-event-with-period (one-of org) [ -> pay-bills ] end-of-month 1 "month"

then I have this weird output:

(org 0): "monthly pay-bills{{time:logotime 31-01-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-02-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-03-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-04-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-05-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-06-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-07-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-08-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-09-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-10-2023}}"
(org 0): "monthly pay-bills{{time:logotime 28-11-2023}}"

there is something I am missing, I guess... I don't understand why all happens on 28 after the second month...


Solution

  • I am not sure why the one-month scheduling doesn't work; without more information it looks like it could be a bug in schedule-repeating-event.

    You could work around it by instead having a statement executed each day, like this:

    if (time:difference-between last-pay-time tick-date "months") = 2
    [
     pay-bills
     set last-pay-time time:copy tick-date
    ]