Cleaning rota/schedule

I created a little typst document including some scripting to create a cleaning schedule by just entering the names of the people involved, the starting date and the number of rows. So you can just update the starting date and maybe the person to begin with and have an up to date plan.

screenshot

code
// settings
#let start_time = datetime(day: 28, month: 10, year: 2024)
// set start_time to today
// #let start_time = datetime.today()
#let weeks = 38
// begin with name <names[start_name]>
#let start_name = 0
#let names = ("name 1", "name 2", "name 3", "name 4")

// script
#let array = ("name", "date", "signature")
#for i in range(weeks) {
  array.push(names.at(calc.rem(i + start_name, names.len())))
  array.push((start_time + duration(days: 7*i)).display("[year]-[month]-[day] - " + (start_time + duration(days: 7*i + 6)).display("[year]-[month]-[day]")))
  array.push("                                                       ")
}

// displaying
#align(center + horizon)[
#heading()[cleaning schedule]
  #table(
  columns: 3,
  ..array
)
]
3 Likes

I added a function to determine the next date a specified weekday is reached, so you can now just say like “next monday” as your starting date. See the updated code:

code
// calculates the next date which has weekday <weekday>
// @param weekday: written in letters or with numbers
// @return: returns the date the weekday is reached again
#let next(weekday) = {
  let sWeekday = ("", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")
  let day = datetime.today()
  assert((weekday in range(1, 8)) or weekday in sWeekday, message: "please enter a weekday (monday-sunday) or a number from 1 to 7!")
  for i in range(7) {
    if (weekday == day.weekday() or weekday == sWeekday.at(day.weekday())) {
      return day
    }
    day = day + duration(days: 1)
  }
}

// settings
// first date: next <weekday> (monday-sunday or 1-7)
#let start_time = {next("monday")}

// specified first date
// #let start_time = datetime(day: 28, month: 10, year: 2024)

// set first date to today
// #let start_time = datetime.today()

#let weeks = 38
// begin with name <names[start_name]>
#let start_name = 0
#let names = ("name 1", "name 2", "name 3", "name 4")

// script
#let array = ("name", "date", "signature")
#for i in range(weeks) {
  array.push(names.at(calc.rem(i + start_name, names.len())))
  array.push((start_time + duration(days: 7*i)).display("[year]-[month]-[day] - " + (start_time + duration(days: 7*i + 6)).display("[year]-[month]-[day]")))
  array.push("                                                       ")
}

// displaying
#align(center + horizon)[
#heading()[cleaning schedule]
  #table(
  columns: 3,
  ..array
)
]

I like it. Provides a tool for a problem we all encounter in our lives and keeps things simple.

If you’re looking for other ways to tweak it, here are some ideas:

  • Make the heading more distinct - Maybe make it bold, or filled with a color
  • Turn the whole thing into a function - Not needed, but could make using it in another context easier
  • More direct way to adjust the signature column width - the third element added to the array per week could be none and then the column width specified in the call to table later on. Or adding a h(2cm) to the array

Thanks for the inspiration :slight_smile:
At the moment, I don’t want to put more time into it, but when I have more time, I might. Also, feel free to tweak it yourself and post your results.
PS: I threw it together pretty quickly, so the code quality is not the best, I know :wink:

I did pretty much everything you said:

new script
// calculates the next date which has weekday <weekday>
// @param: weekday: written in letters or with numbers
// @return: returns the date the weekday is reached again
#let next(weekday) = {
  let sWeekday = ("", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday")
  let day = datetime.today()
  assert((weekday in range(1, 8)) or weekday in sWeekday, message: "please enter a weekday (monday-sunday) or a number from 1 to 7!")
  for i in range(7) {
    if (weekday == day.weekday() or weekday == sWeekday.at(day.weekday())) {
      return day
    }
    day = day + duration(days: 1)
  }
}
// names: an array with names the schedule should include
// specified starting time
// #let start_date = datetime(day: 28, month: 10, year: 2024)
// set start_date to today
// #let start_date = datetime.today()
// start next __ (monday-sunday or 1-7)
// #let start_time = {next("monday")}
// start_name: begin with name <names[start_name]>
// weeks: amount of weeks displayed in the table
// signature_width: width of the signature column (like 6cm, 3em, ...)
// heading: content above the table
#let cleaning_schedule(names, start_date: next("monday"), start_name: 0, weeks: 38, signature_width: 6cm, heading: [#heading()[cleaning schedule]]) = {
  let array = ("Name", "Datum", "Unterschrift")
  for i in range(weeks) {
    array.push(names.at(calc.rem(i + (start_name), names.len())))
    array.push((start_date + duration(days: 7*i)).display("[day].[month].[year] - " + (start_date + duration(days: 7*i + 6)).display("[day].[month].[year]")))
    array.push(h(signature_width))
  }
  
  // displaying
  align(center + horizon)[
  #heading
  #table(
    columns: 3,
    ..array
  )
]
}
# examples: 
#cleaning_schedule(("name 1", "name 2"))
#cleaning_schedule(("name 1", "name 2"), [#heading()[#text(blue)[cleaning schedule]]])
#cleaning_schedule(("name 1", "name 2", "name 3", "name 4"), start_date: {next("wednesday")}, start_name: 2, weeks: 30, signature_width: 9cm, heading: [#heading()[#text(red)[cleaning schedule]]])

everything is withing the function cleaning_schedule now (except the function next of course). Also, you can now change the heading and change the width of the signature column with units like cm, em etc. You can even use relative units like percent which refers the remaining space I think. Almost everything has useful preset values, so you only HAVE to enter the names, but you can change other parameters if you like to as demonstrated in the examples at the end of the new script.

2 Likes