Skip to content

Commit 76f2879

Browse files
improvement
1 parent 5c823ac commit 76f2879

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceEvaluator.cs

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ public static bool MatchRecurrence(DateTimeOffset time, TimeWindowFilterSettings
9999
/// Try to find the closest previous recurrence occurrence before the provided time stamp according to the recurrence pattern.
100100
/// <param name="time">A time stamp.</param>
101101
/// <param name="settings">The settings of time window filter.</param>
102-
/// <param name="previousOccurrence">The closest orevious occurrence.</param>
103-
/// /// <returns>True if the closest previous occurrence is within the recurrence range, false otherwise.</returns>
102+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
103+
/// <returns>True if the closest previous occurrence is within the recurrence range, false otherwise.</returns>
104104
/// </summary>
105105
private static bool TryGetPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence)
106106
{
@@ -115,10 +115,6 @@ private static bool TryGetPreviousOccurrence(DateTimeOffset time, TimeWindowFilt
115115

116116
string patternType = settings.Recurrence.Pattern.Type;
117117

118-
RecurrenceRange range = settings.Recurrence.Range;
119-
120-
TimeSpan timeZoneOffset = GetRecurrenceTimeZone(settings);
121-
122118
int numberOfOccurrences;
123119

124120
if (string.Equals(patternType, Daily, StringComparison.OrdinalIgnoreCase))
@@ -150,6 +146,10 @@ private static bool TryGetPreviousOccurrence(DateTimeOffset time, TimeWindowFilt
150146
throw new ArgumentException(nameof(settings));
151147
}
152148

149+
RecurrenceRange range = settings.Recurrence.Range;
150+
151+
TimeSpan timeZoneOffset = GetRecurrenceTimeZone(settings);
152+
153153
if (string.Equals(range.Type, EndDate, StringComparison.OrdinalIgnoreCase))
154154
{
155155
DateTime alignedPreviousOccurrence = previousOccurrence.DateTime + timeZoneOffset - previousOccurrence.Offset;
@@ -171,6 +171,13 @@ private static bool TryGetPreviousOccurrence(DateTimeOffset time, TimeWindowFilt
171171
return true;
172172
}
173173

174+
/// <summary>
175+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "Daily" recurrence pattern.
176+
/// <param name="time">A time stamp.</param>
177+
/// <param name="settings">The settings of time window filter.</param>
178+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
179+
/// <param name="numberOfOccurrences">The number of complete recurrence intervals which have occurred between the time and the recurrence start.</param>
180+
/// </summary>
174181
private static void FindDailyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
175182
{
176183
RecurrencePattern pattern = settings.Recurrence.Pattern;
@@ -190,6 +197,13 @@ private static void FindDailyPreviousOccurrence(DateTimeOffset time, TimeWindowF
190197
numberOfOccurrences = numberOfInterval;
191198
}
192199

200+
/// <summary>
201+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "Weekly" recurrence pattern.
202+
/// <param name="time">A time stamp.</param>
203+
/// <param name="settings">The settings of time window filter.</param>
204+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
205+
/// <param name="numberOfOccurrences">The number of recurring days of week which have occurred between the time and the recurrence start.</param>
206+
/// </summary>
193207
private static void FindWeeklyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
194208
{
195209
previousOccurrence = DateTimeOffset.MaxValue;
@@ -269,6 +283,13 @@ private static void FindWeeklyPreviousOccurrence(DateTimeOffset time, TimeWindow
269283
}
270284
}
271285

286+
/// <summary>
287+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "AbsoluteMonthly" recurrence pattern.
288+
/// <param name="time">A time stamp.</param>
289+
/// <param name="settings">The settings of time window filter.</param>
290+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
291+
/// <param name="numberOfOccurrences">The number of complete recurrence intervals which have occurred between the time and the recurrence start.</param>
292+
/// </summary>
272293
private static void FindAbsoluteMonthlyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
273294
{
274295
RecurrencePattern pattern = settings.Recurrence.Pattern;
@@ -297,6 +318,13 @@ private static void FindAbsoluteMonthlyPreviousOccurrence(DateTimeOffset time, T
297318
numberOfOccurrences = numberOfInterval;
298319
}
299320

321+
/// <summary>
322+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "RelativeMonthly" recurrence pattern.
323+
/// <param name="time">A time stamp.</param>
324+
/// <param name="settings">The settings of time window filter.</param>
325+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
326+
/// <param name="numberOfOccurrences">The number of complete recurrence intervals which have occurred between the time and the recurrence start.</param>
327+
/// </summary>
300328
private static void FindRelativeMonthlyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
301329
{
302330
RecurrencePattern pattern = settings.Recurrence.Pattern;
@@ -343,6 +371,13 @@ private static void FindRelativeMonthlyPreviousOccurrence(DateTimeOffset time, T
343371
numberOfOccurrences = numberOfInterval;
344372
}
345373

374+
/// <summary>
375+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "AbsoluteYearly" recurrence pattern.
376+
/// <param name="time">A time stamp.</param>
377+
/// <param name="settings">The settings of time window filter.</param>
378+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
379+
/// <param name="numberOfOccurrences">The number of complete recurrence intervals which have occurred between the time and the recurrence start.</param>
380+
/// </summary>
346381
private static void FindAbsoluteYearlyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
347382
{
348383
RecurrencePattern pattern = settings.Recurrence.Pattern;
@@ -371,6 +406,13 @@ private static void FindAbsoluteYearlyPreviousOccurrence(DateTimeOffset time, Ti
371406
numberOfOccurrences = numberOfInterval;
372407
}
373408

409+
/// <summary>
410+
/// Find the closest previous recurrence occurrence before the provided time stamp according to the "RelativeYearly" recurrence pattern.
411+
/// <param name="time">A time stamp.</param>
412+
/// <param name="settings">The settings of time window filter.</param>
413+
/// <param name="previousOccurrence">The closest previous occurrence.</param>
414+
/// <param name="numberOfOccurrences">The number of complete recurrence intervals which have occurred between the time and the recurrence start.</param>
415+
/// </summary>
374416
private static void FindRelativeYearlyPreviousOccurrence(DateTimeOffset time, TimeWindowFilterSettings settings, out DateTimeOffset previousOccurrence, out int numberOfOccurrences)
375417
{
376418
RecurrencePattern pattern = settings.Recurrence.Pattern;
@@ -389,15 +431,18 @@ private static void FindRelativeYearlyPreviousOccurrence(DateTimeOffset time, Ti
389431

390432
if (alignedTime.Month < alignedStart.Month)
391433
{
434+
//
435+
// E.g. start: 2023.9 and time: 2024.8
436+
// Not a complete yearly interval
392437
yearGap -= 1;
393438
}
394-
else if (alignedTime.Month == alignedStart.Month)
439+
else if (alignedTime.Month == alignedStart.Month && !pattern.DaysOfWeek.Any(day =>
440+
alignedTime >= NthDayOfWeekInTheMonth(alignedTime, pattern.Index, day) + alignedStart.TimeOfDay))
395441
{
396-
if (!pattern.DaysOfWeek.Any(day =>
397-
NthDayOfWeekInTheMonth(alignedTime, pattern.Index, day) + alignedStart.TimeOfDay <= alignedTime))
398-
{
399-
yearGap -= 1;
400-
}
442+
//
443+
// E.g. start: 2023.9.1 (the first Friday in 2023.9) and time: 2024.9.2 (the first Friday in 2023.9 is 2024.9.6)
444+
// Not a complete yearly interval
445+
yearGap -= 1;
401446
}
402447

403448
int numberOfInterval = yearGap / interval;
@@ -1278,7 +1323,7 @@ private static bool IsDurationCompliantWithDaysOfWeek(TimeSpan duration, int int
12781323
if (interval == 1)
12791324
{
12801325
//
1281-
// Check the adjacent week
1326+
// It may across weeks. Check the adjacent week
12821327
date = date.AddDays(1);
12831328

12841329
TimeSpan gap = date - prevOccurrence;
@@ -1302,10 +1347,17 @@ private static int RemainingDaysOfWeek(int day, int firstDayOfWeek)
13021347
}
13031348
else
13041349
{
1305-
return 7 - remainingDays;
1350+
return WeekDayNumber - remainingDays;
13061351
}
13071352
}
13081353

1354+
/// <summary>
1355+
/// Find the nth day of week in the month of the date time.
1356+
/// </summary>
1357+
/// <param name="dateTime">A date time.</param>
1358+
/// <param name="index">The index of the day of week in the month.</param>
1359+
/// <param name="dayOfWeek">The day of week.</param>
1360+
/// <returns>The data time of the nth day of week in the month.</returns>
13091361
private static DateTime NthDayOfWeekInTheMonth(DateTime dateTime, string index, string dayOfWeek)
13101362
{
13111363
var date = new DateTime(dateTime.Year, dateTime.Month, 1);
@@ -1317,13 +1369,15 @@ private static DateTime NthDayOfWeekInTheMonth(DateTime dateTime, string index,
13171369
date = date.AddDays(1);
13181370
}
13191371

1320-
if (date.AddDays(7 * (IndexNumber(index) - 1)).Month == dateTime.Month)
1372+
if (date.AddDays(WeekDayNumber * (IndexNumber(index) - 1)).Month == dateTime.Month)
13211373
{
1322-
date = date.AddDays(7 * (IndexNumber(index) - 1));
1374+
date = date.AddDays(WeekDayNumber * (IndexNumber(index) - 1));
13231375
}
13241376
else // There is no the 5th day of week in the month
13251377
{
1326-
date = date.AddDays(21);
1378+
//
1379+
// Add 3 weeks to reach the fourth day of week in the month
1380+
date = date.AddDays(WeekDayNumber * 3);
13271381
}
13281382

13291383
return date;

src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceRange.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class RecurrenceRange
2626
public int? NumberOfOccurrences { get; set; }
2727

2828
/// <summary>
29-
/// Time zone for the StartDate and EndDate
29+
/// Time zone for recurrence settings, e.g. UTC+08:00
3030
/// </summary>
3131
public string RecurrenceTimeZone { get; set; }
3232
}

0 commit comments

Comments
 (0)