-
Notifications
You must be signed in to change notification settings - Fork 119
Support recurring time window filter for TimeWindowFilter #256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabExpression.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabExpression.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabExpression.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabExpression.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabExpression.cs
Outdated
Show resolved
Hide resolved
| // The field can be a list which is a set of numbers or ranges separated by commas. | ||
| // Ranges are two numbers/name separated with a hyphen or an asterisk which represents all possible values in the field. | ||
| // Step values can be used in conjunction with ranges after a slash. | ||
| string validSegmentPattern = @"^(?:[0-9]+|[a-zA-Z]{3}|(?:\*|(?:[0-9]+|[a-zA-Z]{3})-(?:[0-9]+|[a-zA-Z]{3}))(/[0-9]+)?)$"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we using one single regex to test all fields? this makes the regex very complex and hard to understand. Any way to make it more comprehensible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also the pattern should be constant. Or a static Regex for reuse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add more comments to explain this regex. But I think using one single regex can make the code tidy and simple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid regex. Regex has been the cause of countless server hangs. As such, by principle I always seek to avoid it. In this case, I almost expect it to be easier to pattern match without regex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-implemented the CrontabField.TryParse() without using regex.
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabField.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabField.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.FeatureManagement/FeatureFilters/Crontab/CrontabField.cs
Outdated
Show resolved
Hide resolved
| [Theory] | ||
| [InlineData("* * * * *", true)] | ||
| [InlineData("1 2 3 Apr Fri", true)] | ||
| [InlineData("00-59/3,1,2-2 01,3,20-23 */10,31-1/100 Apr,1-Feb,oct-DEC/1 Sun-Sat/2,1-7", true)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain the 31-1/100 part of the day value? Does cron support the day of the month wrapping around from 31 to 1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IBM doc and man page of crontab(5) both don't mention whether this is valid.
https://crontab.guru/ this website will consider this invalid. (By the way, this website recognized the step value 100, it only denies range like 31-1)
However, the Quartz and NCronTab libs will treat "31-1/100" as a valid expression.
I think the range 31-1 and step value 100 can be interpreted as the from 31st to 1st day of month per 100 days, which will give us only the 31st day of the month. From the code perspective, this makes sense.
This is not a critical error, so I believe it should be toleranted by the crontab parser.
I can add some extra logics to check whether the step value is within the max value of crontab field and check whether the range is from a smaller number to a a larger number.
What do you think? Should we treat "31-1/100" as an invalid one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize NCronTab treated that expression as valid, so it makes more sense to stick with what the NCronTab implementation is and treat that expression as just the 31st day. As long as it's clear that we're sticking with this library then I think it's ok. Thanks for the explanation!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "first-last/step" should be interpreted to something like a for loop: for (int i = first; i<= last; i+=step). If we consider it in this way, everything will make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: The range like "31-1" should be forbidden. The reasons are as follow:
- The portal should validate the Crontab expression typed by user. If such reversed range is allowed, user may be confused because they may not consider the range in the for-loop manner.
- Although Quartz and NCronTab will treat this as a valid expression, I found that it might be a bug or a corner case they didn't handle. After more tests, I found that the behavior of NextOccurence(), IsSatisfiedBy(DateTimeOffset) would be extremly strange when both libraries were handling the Crontab like "* * 31-1/100 * *".
For example:
UTs for NCronTab:
[InlineData("* * 31-29/2 * *", "Tue, 29 Aug 2023 00:00:00 +00:00", true)]
[InlineData("* * 31-1/30 * *", "Thu, 31 Aug 2023 01:00:00 +00:00", true)]
[InlineData("* * 31-1/30 * *", "Fri, 1 Sep 2023 01:00:00 +00:00", true)]
[InlineData("* * 31-1/31 * *", "Fri, 1 Sep 2023 01:00:00 +00:00", true)]
[InlineData("* * 31-1/31 * *", "Thu, 31 Aug 2023 01:00:00 +00:00", false)]
[InlineData("* * 31-1/100 * *", "Thu, 31 Aug 2023 01:00:00 +00:00", false)]
[InlineData("* * 1-31/100 * *", "Fri, 1 Sep 2023 01:00:00 +00:00", true)]
[InlineData("* * 1-31/100 * *", "Thu, 31 Aug 2023 01:00:00 +00:00", false)]
public void IsCronSatisfiedByTimestamp(string cron, string timeString, bool expected)
{
Assert.Equal(expected, IsSatisfiedBy(cron, timeString));
}
private static bool IsSatisfiedBy(string cron, string timeString)
{
CrontabSchedule schedule = CrontabSchedule.Parse(cron, new CrontabSchedule.ParseOptions { IncludingSeconds = false });
DateTime dateTime = DateTime.Parse(timeString);
DateTime withoutSeconds = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, 0);
DateTime timeAfter = schedule.GetNextOccurrence(withoutSeconds.AddMinutes(-1));
if (timeAfter.Equals(withoutSeconds))
{
return true;
}
else
{
return false;
}
}
UTs for Quartz:
[InlineData("* * * 31-1/100 * ?", "Thu, 31 Aug 2023 21:00:00 +08:00", true)]
[InlineData("* * * 31-1 * ?", "Fri, 1 Sep 2023 21:00:00 +08:00", true)]
[InlineData("* * * 31-1/30 * ?", "Fri, 1 Sep 2023 21:00:00 +08:00", false)]
[InlineData("* * * 31-1 * ?", "Sat, 2 Sep 2023 21:00:00 +08:00", false)]
[InlineData("* * * 31-1/100 * ?", "Fri, 1 Sep 2023 21:00:00 +08:00", false)]
public void IsCronSatisfiedByTimestamp(string cron, string timeString, bool expected)
{
DateTimeOffset dateTimeOffset = DateTimeOffset.Parse(timeString);
CronExpression test = new CronExpression(cron);
Assert.Equal(expected, test.IsSatisfiedBy(dateTimeOffset));
}
Their behaviors are super weird. I cannot understand how both libraries interpret the range "31-1/100". For me, it seems more like a bug or a corner case which is not handled.
By the way, the step value like 100 is still allowed.
2f27438 to
78430c4
Compare
78430c4 to
555c2da
Compare
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html Follow the Crontab syntax on the open group page Update: 1. Only 0 can represent Sunday, 7 no longer represents Sunday, instead, 7 will be invalid for the day of week field 2. if either the month or day of month is specified as an element or list, and the day of week is also specified as an element or list, then any day matching either the month and day of month, or the day of week, shall be matched.
| /// The recurring time windows are represented in the form of Crontab expression. | ||
| /// If any recurring time window filter is specified, to enable the feature flag, the current time also needs to be within at least one of the recurring time windows. | ||
| /// </summary> | ||
| public List<CrontabExpression> Filters { get; set; } = new List<CrontabExpression>(); // E.g. ["* 18-19 * * Mon"] which means the recurring time window of 18:00~20:00 on Monday |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any reason to define public type for cron tab expression. I expect string to suffice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the job for the IFilterParametersBinder.BindParameters() is to pre-process the configuration paramters to some settings that filter can use directly during the evaluation. For example, the "Start" and "End" parameters are just string in the configuration, but it will become a DataTimeOffset in the TimeWindowFilterSettings.
The FeatureManager has the _parametersCache which will cached the filter parameters and settings which are bound from the raw filter parameters. So I think the raw Crontab string should be converted into CronExpression in TimeWindowFilterSettings.
Ah, I see the reason why we should store raw Cron strings in the filter settings. In this way, we can make CronExpressionClass internal.
| /// The recurring time windows are represented in the form of Crontab expression. | ||
| /// If any recurring time window filter is specified, to enable the feature flag, the current time also needs to be within at least one of the recurring time windows. | ||
| /// </summary> | ||
| public List<CrontabExpression> Filters { get; set; } = new List<CrontabExpression>(); // E.g. ["* 18-19 * * Mon"] which means the recurring time window of 18:00~20:00 on Monday |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use Cron Expression nomenclature that seems to be a norm.
src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilterSettings.cs
Outdated
Show resolved
Hide resolved
| /// The recurring time windows are represented in the form of Crontab expression. | ||
| /// If any recurring time window filter is specified, to enable the feature flag, the current time also needs to be within at least one of the recurring time windows. | ||
| /// </summary> | ||
| public List<CrontabExpression> Filters { get; set; } = new List<CrontabExpression>(); // E.g. ["* 18-19 * * Mon"] which means the recurring time window of 18:00~20:00 on Monday |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. ["* 18-19 * * Mon"] which means the recurring time window of 18:00~20:00 on Monday
This looks more like it should belong in a doc than as a comment here. Also this seems kind of like a stray comment, was it intended to be part of the method summary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, because we have comments like this on the other properties. Those seem odd. I would suggest the opposite, that we remove the stray comments from the existing properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed these comments.
src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilterSettings.cs
Outdated
Show resolved
Hide resolved
| /// <summary> | ||
| /// Define an enum of all required fields of the Crontab expression. | ||
| /// </summary> | ||
| public enum CrontabFieldKind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not expecting any new public types as part of this enhancement.
| i++; | ||
| } | ||
|
|
||
| fields[pos] = expression.Substring(start, i - start); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better if we can use ReadOnlySpan<char> to avoid allocating new strings.
| TimeSpan utcOffsetForCron = new TimeSpan(0, 0, 0); // By default, the UTC offset is UTC+00:00. | ||
| utcOffsetForCron = settings.Start.HasValue | ||
| ? settings.Start.Value.Offset | ||
| : settings.End.HasValue | ||
| ? settings.End.Value.Offset | ||
| : utcOffsetForCron; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| TimeSpan utcOffsetForCron = new TimeSpan(0, 0, 0); // By default, the UTC offset is UTC+00:00. | |
| utcOffsetForCron = settings.Start.HasValue | |
| ? settings.Start.Value.Offset | |
| : settings.End.HasValue | |
| ? settings.End.Value.Offset | |
| : utcOffsetForCron; | |
| TimeSpan offset; | |
| if (settings.Start.HasValue) | |
| { | |
| offset = settings.Start.Value.Offset; | |
| } | |
| else if (settings.End.HasValue) | |
| { | |
| offset = settings.End.Value.Offset | |
| } | |
| else | |
| { | |
| // | |
| // By default, the UTC offset is UTC+00:00. | |
| offset = new TimeSpan(0, 0, 0); | |
| } |
| "* 18-19 * * Mon-Fri", | ||
| // 18:00-22:00 on weekends | ||
| "* 18-21 * * Sat,Sun" | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really have to support an array of crontab expressions, or is one sufficient for most scenarios? Even if someone really needs more than one, they can always add more Time Window filters with different configurations.
I'm concerned this complicates the usage of the recurring Time Window filter. I can already see this complicates the UI design.
BTW, having a 'Filters' parameter in a feature filter is also confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scenario when the user want to activate a feature flag during 18:00-20:00 on every weekend and during 18:00-22:00 on holidays requires a list to specify recurring time windows with different durations.
Using multiple timewindow filters may not be a good choice, since the feature flag may also use other filters(e.g. targeting), in this case, the "RequirementType" is "All".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the parameter name 'Filters' is kind of confusing. But the cron expression does serve as "filters" since we also have the parameter "Start" and "End" which should be considered as the timestamp when the filter starts to work("FilterStart") and when the filter ends working("FilterEnd").
The reason why we use "Filters" instead of "Recurrence" is that we will treat an empty list of "Filters" as not specified.
When "Filters" is not specifed, the TimeWindowFilter will revert to the original fixed time window filter.
The name "Filters" makes more sense.
Let's take a look at two choices:
Choice A:
"Start" : "2023-9-19-00:00",
"End": "2024-9-19-00:00",
"Filters": [ ]
Choice B:
"Start" : "2023-9-19-00:00",
"End": "2024-9-19-00:00",
"Recurrence": [ ]
If "Filters" or "Recurrence" is not specified, there is no confusion.
If "Filters" or "Recurrence" is not empty, the filter will only enable the feature during the recurring time window listed in the list "Filters" or "Recurrence". However, for the “Recurrence" choice, the parameter "Start" and "End" serve as the "RecurrenceStart" and "RecurrentEnd" instead of "FilterStart" and "FilterEnd". This will make the scenario that the "Recurrence" is specified as an empty list confusing. The function of "Start" and "End" will be inconsistent if we use name "Recurrence".
The user who uses FeatureManagement-Dotnet is expected to read the README before using it. The user who uses FeatureManagement through portal will never know the backend data schema for TimeWindowFilter unless they use "Advanced Edit"(in this case, the user should be considered as a pro who has read our doc). On the Portal, the scenarios of setting a fixed time window and setting recurring time window will have different UI and will not mention the "Filters" parameter.
For me, I will vote for the name "Filters" because it makes the role of "Start" and "End" parametes consistent. I also believe it will not cause confusion for the user who uses FeatureManagement-Dotnet lib directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scenario when the user want to activate a feature flag during 18:00-20:00 on every weekend and during 18:00-22:00 on holidays requires a list to specify recurring time windows with different durations.
I'm sure we can come up with even more complex scenarios. The question is how realistic they are. Outlook doesn't support infinite recurrence patterns, just one pattern at a time. Without the array, the parameters can be simplified to "Start", "End" and "RecurrencePattern". The UI design doesn't need an add button for more than one recurrence pattern anymore.
Using multiple timewindow filters may not be a good choice, since the feature flag may also use other filters(e.g. targeting), in this case, the "RequirementType" is "All".
We know the "RequirementType" doesn't support all possible logical operations. It was a conscious decision. It's a balance between complexity and the most common scenarios. The choice of that design shouldn't be the reason for us to complicate the design of each feature filter. We have a reasonable workaround. We know there are scenarios that won't be supported out-of-box no matter how. That's where customers should consider custom filters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do not want to use a single parameter "RecurrencePattern", then we cannot use cron expression any more. The reason is that we have to use at least three cron expressions to describe the time span 18:30`20:30. e.g. "30-59 18 * * ", " 19 * * *“ and "0-29 20 * * *".
I have proposed a lot of schema designs to describe the recurrence. Some of them are deprecated early and are not included in the design doc.
The best way to describe recurrence is to specify the duration and recurrence pattern (i.e. when we want to make the recuurence happen).
At first, I want to use two parameters "Duration" and "RecurWhen".
// 18:30-20:30 every Friday
"Duration": {
"Type": "Hour",
"Length": 2
},
"RecurWhen": "30 18 * * 5"
This represents 18:00-22:00 every Friday.
This design will use cron expression in classic way where the cron expression represents the schedule (time points instead of time spans).
But Jimmy thought we can include the duration information in the cron expression, in this way the json schema will be very simple. The above configuration can be simplified to a single cron "* 18-22 * * 5".
Jimmy thought the current design achieved the balance between simplicity, offering to customers and implementation/maintenance. I completly agree with Jimmy, that's the reason why we finally decided to use the current cron design for the recurrence configuration.
Besides, the current design also provides a benefit that it will make the process to check whether the current time is within any recurring time window very simple. We only need to check whether five fields are compliant with current timestamp.
If we use the "Duration" and "RecurWhen" design, we need to compute the previous occurrence of the cron schedule which is the start of the recurring time window and then check whether the current time is within that recurring time windows.
These are some basic scenarios we want to support(you can find it in the design doc):
- Basic Scenarios
a) Recur during a certain time window every day
- Turn on a feature flag during 16:00~20:00 every day
b) Recur during a certain time window on certain days of a week - Turn on a feature flag during 16:00~20:00 on Monday and Friday every week
- Turn on a feature flag from Saturday evening to Monday morning every week
c) Recur during a certain time window on certain days of a month - Turn on a feature flag during 18:00~20:00 every Sunday in August
- Turn on a feature flag on the first/last three days of each month
- Turn on a feature flag during 18:00~23:00 on Feb 14, Dec 24 and 25 every year
- Turn on a feature flag on Dec 31 and Jan 1 every year.
I think all of them are reasonable scenarios and we should support all of them.
The current design is the simplest one which can support all of these scenarios.
In fact, the cron expression is the most compact format to describe the recurrence and it is a well-known and standardized format. We can invent some formats to describe the recurrence, but it would be better to use something standardized. (This discussion can be found in the comments of the design doc.)
If you go to see the AKS doc, you will find AKS has a feature called maintenance schedule: https://learn.microsoft.com/en-us/azure/aks/planned-maintenance.
This is a very similar scenario where user can configure some recurring time windows to let AKS cluster to upgrade.
The AKS team designs a quite complicated schema

The AKS team invents a very complex schema to descibe the recurring maintenance time window.

It will look like this.
AKS even does not support configuring this on the Portal. It can only be configured through CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow what you said here. I did NOT suggest we abandon the usage of cron expression. I am only suggesting we support one cron expression per Time Window filter instead of an array of them. Here is an example.
"EnhancedPipeline": {
"EnabledFor": [
{
"Name": "Microsoft.TimeWindow",
"Parameters": {
"Start": "2023-09-06T00:00:00+08:00",
"RecurrencePattern": "* 18-19 * * Mon-Fri" // 18:00-20:00 on weekdays
}
}
]
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if I want the recurrence happen during 18:30`20:30 every day?
You cannot represent 18:30-20:30 in a single cron.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scenario when the user want to activate a feature flag during 18:00-20:00 on every weekend and during 18:00-22:00 on holidays requires a list to specify recurring time windows with different durations.
I'm sure we can come up with even more complex scenarios. The question is how realistic they are. Outlook doesn't support infinite recurrence patterns, just one pattern at a time. Without the array, the parameters can be simplified to "Start", "End" and "RecurrencePattern". The UI design doesn't need an add button for more than one recurrence pattern anymore.
Using multiple timewindow filters may not be a good choice, since the feature flag may also use other filters(e.g. targeting), in this case, the "RequirementType" is "All".
We know the "RequirementType" doesn't support all possible logical operations. It was a conscious decision. It's a balance between complexity and the most common scenarios. The choice of that design shouldn't be the reason for us to complicate the design of each feature filter. We have a reasonable workaround. We know there are scenarios that won't be supported out-of-box no matter how. That's where customers should consider custom filters.
Hi @zhenlan, I thinks scenario like 18:30-20:30 everyday is a very common scenario, not something that rarely happens. And current design does not allow us to use one single cron to describe it. Since they are closely tied together, adding two cron expressions makes more sense to me than adding two TimeWindow filters. If we don't support cron array, probablly customers will have to add more Feature filters, which means inceasing size/complexity in another level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@juniwang Yes, we chatted offline, and I understand this now. This limitation imposes challenges on our portal to properly break down 18:30-20:30 into 3 crontabs and reconstruct it back from crontabs to a human-readable time duration. We need to rethink our design choices.
|
|
||
| /// <summary> | ||
| /// Field Name: Day of week | ||
| /// Allowed Values: 0-7 (0 or 7 is Sunday, or use the first three letters of the day name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0 or 7 is Sunday
Is this from the standard?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is according to the linux man page https://man7.org/linux/man-pages/man5/crontab.5.html
Some cron implementations may not allow 0 to represent Sunday.
|
Update: |
|
We spoke about requiring the If we do that, |
|
@rossgrambo
For me, I think the first time window is unnecessary to follow the recurrence pattern and range. My impletation for the validation of the parameter "Recurrence.Range.StartDate" will be like |
For the discussion, in this example (sorry, there is no 9/31 :) so I change it to 9/25) IMO, we have two options
I don't like treating |
|
date ends up being important if you have an event that spans across midnight. |
It's important to be defined on the field. But if you're extracting duration from it as Zhenlan suggested, you don't need date anymore, as start + duration tells you everything. But regardless, I think @zhiyuanliang-ms 's version makes the most sense.
If we really want to support hourly recurrance then bullet 2 would need to change. But without that, I think that's the cleanest way to do it. |
@rossgrambo that's how I imagine it working. |
|
Users shouldn't have a recurring time window that has any occurrence outside the range. |
|
Zhenlan, Ross, and I discussed this. We came up with the following points.
|
|
@jimmyca15 Got it. |
|
@rossgrambo @zhenlan @jimmyca15 Since we have decided to remove "Recurrence.Range.StartDate", I am wondering whether we still need "Recurrence.Range.RecurrenceTimeZone". We can mandate that the time zone of "Start" will be applied to the recurrence. Update: |
|
I noticed that the current behavior of Portal is that the "Start" and "End" will be converted into GMT format string rather than using the time zone selected by the user. The time zone information will not be provided in "Start" or "End". If the "RecurrenceTimeZone" is specified, it will be applied to the "Start" and then we will check whether the "Start" timestamp is valid for the Recurrence.Pattern under the "RecurrenceTimeZone". Besides, I believe Portal should provide the time zone information in the datetime string by using format like "Sat, 23 Sep 2023 08:00:00 GMT+0800" rather than "Sat, 23 Sep 2023 00:00:00 GMT", since we allow user to select the timezone on the Portal. If the time zone information is provided in the string for "Start", then we can discard the parameter "Recurrence.Range.RecurrenceTimeZone". |
I think the current behavior of Portal will break the recurrence pattern. If user selects 2023-9-24 6:00-8:00 and time zone +08:00, this time window will be converted into "Sat, 23 Sep 2023 22:00:00 GMT to "Sun, 24 Sep 2023 00:00:00 GMT". |
My understanding is It allows you to pick what day is the first day of the week. If you pass sunday, nothing changes (at least that's what i'm used to). If you pass monday, then the value in index might be affected. For example: With this, the "first" week is considered ending on Sun, Oct 1st. Mon, Oct 2nd would be the "second" week. We would never hit "Wednesday" of the "first" week. Europe generally starts weeks on Monday while the US starts weeks on Sunday. I think we should include it.
I'm a little lost here. If we use the Start time zone and Sept 23rd would be "converted" to Sept 24th, that's fine. There's no actual conversion. If they use UTC and sept 23rd, that's the start. If they use +08:00, and pick sept 23rd, then that's the start instead. These are different times in UTC. This means: Would repeat at "Sat, 25 Sep 2023 06:00:00 GMT+0800" / "Sun, 24 Sep 2023 22:00:00 GMT" Let me know if I'm missing something |
"Sat, 25 Sep 2023 06:00:00 GMT+0800" and "Sun, 24 Sep 2023 22:00:00 GMT" are the same timestamp, they are representing the same physical time. Currently, no matter what time zone you choose on the Portal, the timestamp will be converted into GMT time(which is under UTC+0:00) For the recurrence, according to Jimmy's comment, we should add this check for the "Start".
It is possible that under UTC+08:00 the "Start" is on Monday and ,when it is converted to GMT time, it becomes Sunday. |
|
I see, so it's a concern for the portal, as it's already doing the conversion, but you're worried the rest of the settings won't be accurate anymore. I think there's 3 options:
I'd prefer 1, but we can go with 3 if we're concerned with the impact of 1. |
|
I like the option 1. But we need to investigate whether there is a format with the time zone info which can be parsed by spring, dotnet and javascript. |
|
Closing this PR for now in favor of #266 |


Implemented the CrontabField and CrontabExpression classes and wrote some unit tests