Heyho!
Im back working on this again after needing to do other things.
Since I have an MVP im currently looking into how to display, manage and edit the recurrence rules in a better way and given the lack of documentation regarding the JSCalendar logic im left with some questions. While yes, the implementation is trying to follow the JSCalendar Specs i’ve found some edge cases for which im not entirely sure how they are/should/will be handled, partly given that the JSCalendar logic isn’t fully written yet.
Here a TypeScript representation of how im interpreting the (relevant) Specs
This isnt exactly how the Spec define it, but a mix how im understanding the Specs in regards to what this feature should do and a bit of what the Java Implementation is currently doing.
/**
* Format: ${year}-${month}-${date}T${hour}:${minutes}:${seconds}Z
*/
export type JSC_LocalDateTime = string;
/**
* Format: P${weeks}W${days}D${hours}H${minutes}M${seconds}S
*
* if for example ${weeks}W == "0W", then this parameter can be just ""
*/
export type JSC_Duration = string;
export interface JSC_NDayJson {
"@type": "NDay",
"day": "mo" | "tu" | "we" | "th" | "fr" | "sa" | "su",
"nthOfPeriod": number; // between -5 and 5 and never 0
}
export interface JSC_RecurrenceRuleJson {
"@type": "RecurrenceRule",
"frequency": "daily" | "weekly" | "monthly" | "yearly",
"byDay"?: JSC_NDayJson[],
"byMonth"?: string[], // months by number but as a string
"byMonthDay"?: number[], // day of month -31 to 31. If day is out of range -> ignore
"byWeekNo"?: number[], // weeks of the year from -53 to 53
"byYearDay"?: number[], // days of the year from -366 to 366. If day is out of range -> ignore
};
export interface JSC_TaskJson<Payload> {
"@type": "Task",
"uid": string,
"title"?: string,
"description"?: string,
"start"?: JSC_LocalDateTime,
"until"?: JSC_LocalDateTime,
"duration"?: JSC_Duration,
"recurrenceRules"?: JSC_RecurrenceRuleJson[],
"excludeRecurrenceRules"?: JSC_RecurrenceRuleJson[],
/** key = isoDate */
"recurrenceOverride"?: Record<JSC_LocalDateTime, JSC_RecurrenceOverride>,
"openems.io:Payload": Payload
}
export type JSC_RecurrenceOverride = {
"start"?: JSC_LocalDateTime,
"duration"?: JSC_Duration,
};
First of all, is this Interpretation of the Specs correct? and will it be implemented like that at some point?
-
Looking at the code it seems like the daily frequency doesn’t have any parameters
Is this assumption correct? Because Technically every frequency can have every “by…” rule. But that means frequencies are somewhat redundant.
For example you can say {frequency: “daily”, byYearDay: [5]} which behaves the same way as any other frequency. (As far as I understand it)
So the frequency parameter may as well be discarded.
-
The weekly frequency only runs on the given byDay (weekdays)?
Here is the same thing as daily: by the looks of things the code (currently) only supports this option while all the other options are still valid according to the specs.
-
For monthly it gets more complicated.
it has a byMonthDay parameter which contains an int array like 1, 6, 24 (meaning the task should run on those day of the month). But this parameter - as i understand it - is only expected when the skip parameter of the recurrenceRule is set to omit which is only the case when using a calendar format without leap years. Since the we are using the Gregorian Calendar, this is not the case, so its never omit , so theoretically byMonthDay is not a valid parameter here, even though it’d be fairly useful in my opinion.
-
When a Task has multiple recurrenceRules for example
1: ”Every Monday”
2: “Every Friday”
(disregarding the fact that they could be written as one Rule) are they handled in an additive way (aka. “Monday and Friday") or are they handled in an overlap way (aka “Never” (because Monday and Friday dont overlap))?
I can imagine that separate Recurrence rules are Additive while a single Rule’s by-“filters” are over overlaps, like:
1: “Every Monday”
2: “Yearly during JAN-SEP on Fridays” (...frequency: “yearly”, byDay: [“Fr”], byMonth: [...)
Resulting in “Every Monday and every (Friday during Janunary till September).”
Is this assumption correct?
Further more the Specs define things like firstDayOfWeek, bySecond, byMinute, byHour, interval or until. While the first 5 only have debatable purpose here, an until parameter however would be very useful i can image. While on the other hand rscale(+skip) is completely useless for this usecase.
Another Question which has presented itself to me is that excludedRecurrenceRules as well as recurrenceOverrides remain unseen in the “backend”. So are there plans to support those in the Future?
Especially recurrenceOverrides which allows you to specify a given Task should run once at an arbitrary moment in time, can be pretty handy i believe.
But excludedRecurrenceRules can be a powerful tool as well. If you for example want to run a Task during the week but another on the Weekend and have a half-a-year schedule like
”I want to run A during the summer and B during the winter, but C at all Weekends”
Using excludes it would be fairly easy to just say
- A: Run in the Summer months, but exclude Saturday and Sunday
- B: Run in the Winter months, but exclude Saturday and Sunday
- C: Run every Saturday and Sunday
Also since
JSCalendar.Tasks by design do not support overlapping OneTask. This is intended behaviour. Instead Tasks respect the priority given by the position in the JSON Array.
The JUnit tests show this behaviour
im wondering how overlapping tasks could be detected and shown to the user so they know their configuration might not run as they’ve intended. Sure i can just give everything a priority, but that doesnt really properly communicate to the user what that actually means and if there are collisions…
I very likely wont implement all the features i’ve mentioned here since they aren’t supported (yet) or require really good UI in order to be useful for anyone, and im quite frankly not this good.
It’d be nice to have an idea of what will be possible - at some point - though, so i can make everything future proof (to the best of my abilities).
Thats a lot of text, here the TL;DR of Questions
- Is my Specs interpretation correct?
- What features are gonna end up in the EMS implementation of the JSCalendar Specs
- Which parameters are allowed for each frequency we support / Are Frequencies of any use?
- How are multiple RecurrenceRules handled
- What about values like
until? Are they relevant? Will they be supported?
- Whats the plan for
excludedRecurrenceRules or recurrenceOverrides? Or rather more complicated schedules in general
- How can I detect Task overlaps in order to show them to the user