This document is meant to document how the calendar-functionality works in the events-section of this website.
An event-page can have an eventInfo
key, which describes the dates that the event happens (note: if there are multiple translations of the same page, only one of them can have this eventInfo
key, and those events are used for all translations).
This key has (for now) three (optional) subkeys: organizer
, timezone
and dates
. In time it could make sense to add additional keys here, like location
, or type={inperson/remote/both}
, rsvp_requested
, etc.
eventInfo.organizer
has two optional subkeys, name
and email
. Right now these are only used in building the ics
file, but it could certainly make sense to show them on the webpage as well.
timezone
should contain an IANA timezone (e.g. Europe/Warsaw
) if the events in this page are not in the default timezone of the site.
dates
has 4 optional subkeys. periodics
allows one to make a recurring rule, extra
allows one to make one-off events, cancelled
allows cancelling a recurring event, and changes
allows changes to an event (either date, or time, or add a message).
periodics
has an array of dicts with keys: start
(date), end
(date) rule
(see below), starttime
(time) endtime
(time) and comment
(optional, string).
All recurring rules need to have a start and end date; without one, Hugo would need to generate an infinite amount of events. I would advice to keep the end
s about 2 years in the future, in cases no end
date is known.
The rule
can be one of two types:
first Tuesday of the month
(Tuesday
can be any weekday name,first
can be any of {first
,second
,third
,fourth
,fifth
,last
,penultimate
} -- if there is ever a need, adding apen-penultimate
is easy (but not supported atm). There is an idea to in the future allowmonth
to also bemonth / x
meaning everyx
months (counting fromstart
date).every X days
Adding additional rules is possible, but not always super easy.
cancelled
has a date as a key, and a message (reason why cancelled) as value. At the moment, only events generated by periodics
can be cancelled (although it might make sense to allow one-off events to be cancelled as well). Cancelled events will still be shown in the interface, and in the ics
files, but marked as cancelled (for now there is no way to completely delete recurring event).
extra
takes as key date+starttime+endtime (e.g. 2023-05-04 12:00-14:00
), and as value a comment for that event (e.g. the reason why there is an extra event).
changes
takes as key a change-rule (which is one of the following) and as value a comment (e.g. reason for the change):
2023-05-04
: no changes in date/time, just in properties of event (=comment)2023-05-04->2023-05-05
: change date, same time, changed comment2023-05-04->19:00-20:00
: change time, same date, changed comment2023-05-04->2023-05-05 19:00-20:00
: change date and time, changed comment
It makes sense that in the future, we'll change the values of the items in extra
and changes
to be dicts themselves, with keys as comment
, location
, organizer
, etc, to allow more flexibility in the events.
There is also a proposal to allow bigger changes to individual events.
Example:
eventInfo:
organizer:
name: Hackerspace Trójmiasto
dates:
periodics:
- start: 2022-10-01
end: 2024-01-02
rule: last Friday of the month
starttime: 18:00
endtime: 02:00
- start: 2022-12-01
end: 2023-02-10
rule: every 14 days
starttime: 12:00
endtime: 14:00
comment: Winter lunch meeting
cancelled:
2023-02-24: "Too cold"
2023-07-28: vacation
extra:
2022-12-07 18:00-19:00: extra meeting too
2023-08-27 18:00-19:00: extra meeting
2022-10-29 18:00-05:00: DLS change party!
changes:
2022-10-28->2022-10-27: "moved because of planning issues"
2022-12-30: bring 🍾
2023-04-28->19:00-01:00: "starting a bit later"
2023-10-27->2023-10-20 19:00-21:00: moved a week earlier
There are some limitations to how events work at the moment:
- Events cannot last longer than 24 hours. If the endtime < starttime, then an event lasts past midnight, but at the moment there is no way to have an event last 2 days.
- If the periodics work so that there are multiple events on the same day, the latter event will overwrite the former one (even if the times are different).
- You cannot make an extra event on the same day there is already an event (or move an event to the day with an event)
- During DST change, no way to specify if you mean time before or after change (basically what the
is_dst
inpytz
is for) 🤓
The events are put on the page in Microformat's event format.
If there are events, a section is shown at the top of the event page, with three tabs "Upcoming", "Past" and "Calendar" (showing upcoming and past events, and a calendar view). Hugo fills the Upcoming and Past sections with events, but this is done t page-creation time (rather than page-view time). In order to make sure the events appear in the right spot, some JS is run to move them. This JS also creates a calendar-functionality view (JS uses the microformat to read the events).
There are pages that show lists of events (e.g. https://hs3.pl/wydarzenia/
, but also taxonomy pages like https://hs3.pl/tags/druk-3d/
). On these pages we can also generate the Upcoming/Past/Calendar box.
At the moment, only the section head (https://hs3.pl/wydarzenia/
, and https://hs3.pl/en/events/
) has this functionality; it's planned to add this functionality later to the taxonomy pages as well.
On these pages, we show the events in long-form (including picture, and title).
Every page and section under wydarzenia
section (basically every page that can have the Upcoming/Past/Calendar box) also generates an .ics
icalendar-file. These files can either be downloaded and then imported into one's calendar-application, or the URL can be given in the subscribe to calendar
box (at least in Apple Calendar and iPhone calendar, supposedly also in Google/Outlook). This latter method allows the calendar to auto-sync and stay up to date (sync frequency can be set by user).
Timezones are the programmer's biggest friend :(.
When events are declared, they are declared in:
- The timezone explicitly given in the
eventInfo.timezone
key; or if not present - The timezone set in
config.toml
; or if not set - The timezone of the server
Hugo only has functions to change timezone to Local (which is timezone of the server, not (as you may think) timezone set in config.toml
, or to UTC. This means we must make sure that the server that Hugo runs on, uses our default timezone (Europe/Warsaw
). Luckily this can be set in netlify.toml
; it does mean however that if someone ever runs Hugo on their laptop, while not having their laptop at CET, they may see the wrong times.
The .ics
files have their times in UTC
(yeah!). It does mean that they show up in calendars using the local device time (i.e. if Picnics start at 18:00 local time, and you're in London, you'll see 17:00
in your calendar).
However for the calendar on the website, it's very confusing if the calendar follows the same rules; Hugo hard-prints on the website: Picnic 18:00 - 23:00
, it would be very confusing, if then it would show as 17:00 - 22:00
in the calendar.
A lot of special hacky code is needed to convince javascript to do the right thing, but in the end, it works :).
I wrote a blog post on the previous iteration of the event-code. Most things in this post are still accurate.