public static string GetRecurStr(DateTime start, TimeUnitId unitId, int interval = 1, DaysOfWeek dowBits = DaysOfWeek.Any) { // Describe the recurrence pattern. scheduled recurrence rules. // Ignore that start may be in the future. // TODO ITranslatorProvider1 if (DateUtil.IsExtremeDate(start)) { return("Never"); } if (unitId <= TimeUnitId.None || unitId > TimeUnitId.Years) // does not repeat. { // "Once at " + date time return(start.ToDtTmString()); } if (interval <= 0) { interval = 1; } var sb = new StringBuilder(); int uniti = (int)unitId; sb.Append(interval > 1 ? $"Every {interval} {_Units[uniti * 2]}" : _Units[(uniti * 2) + 1]); // pluralize? switch (unitId) { case TimeUnitId.MilliSec: // fractional seconds. case TimeUnitId.Seconds: case TimeUnitId.Minutes: return(sb.ToString()); // done. // Say no more. case TimeUnitId.Hours: if (start.Minute > 0) { sb.Append($" at {start.Minute} minutes past"); // minutes into the hour. } return(sb.ToString()); // done. case TimeUnitId.Days: // daily. can use bitmask of days of the week. if (dowBits != 0 && dowBits != DaysOfWeek.Any) { // Only on specific days of the week. if (interval == 1) { sb.Clear(); sb.Append("Every "); } else { sb.Append(" if "); } int dowBit = 1; bool hasBit = false; for (int i = 0; i < 7; i++, dowBit <<= 1) { if ((((int)dowBits) & dowBit) != 0) { if (hasBit) { sb.Append(","); } sb.Append(((System.DayOfWeek)i).ToString()); hasBit = true; } } } break; case TimeUnitId.Weeks: // a single day of the week. if (interval == 1) { sb.Clear(); sb.Append($"Every {start.DayOfWeek.ToString()}"); break; } sb.Append($"on {start.DayOfWeek.ToString()}"); break; // Approximate unit times. case TimeUnitId.Months: // On same day of month. if (interval == 1) { sb.Clear(); sb.Append($"Every {Formatter.ToOrdinal(start.Day)} of the month"); break; } sb.Append($" on {Formatter.ToOrdinal(start.Day)} of the month"); break; case TimeUnitId.Quarters: // Name the months ?? Jan, Apr, Jul, Oct sb.Append($" on {Formatter.ToOrdinal(start.Day)} of the month"); break; case TimeUnitId.Years: sb.Append($" on {start.ToDtString("MMM", CultureInfo.InvariantCulture)} {start.Day:D2}"); break; default: return("?"); // not valid for TimeUnitId } sb.Append($" at {start.Hour:D2}:{start.Minute:D2}"); // at hr:minutes into the day. return(sb.ToString()); }
public static DateTime GetNextRecur(DateTime now, DateTime start, TimeUnitId unitId, int interval = 1, DaysOfWeek dowBits = DaysOfWeek.Any) { // Get the next date / time in the sequence after now. // start = anchor date. Was the last official time. for calculation of relative times, time of day, etc. kExtremeMax = never before // interval = quantity of TimeUnitId // dowBits = only on these days of the week. // RETURN: kExtremeMax = never again. // ASSUME times are GMT and have no DST weirdness. if (DateUtil.IsExtremeDate(start)) { return(DateUtil.kExtremeMax); // never start } if (now < start) // not until start date. { return(start); } if (unitId <= TimeUnitId.None || unitId > TimeUnitId.Years) // does not repeat. { return((now <= start) ? start : DateUtil.kExtremeMax); } if (interval <= 0) { interval = 1; } DateTime dtNext; int timeUnits = _TimeUnits[(int)unitId]; if (unitId <= TimeUnitId.Weeks) { // Discreet/Exact time units. long tickDiff = now.Ticks - start.Ticks; long intervalUnits = (timeUnits * TimeSpan.TicksPerMillisecond) * interval; long intervalsDiff = tickDiff / intervalUnits; int intervalInc = ((tickDiff % intervalUnits) == 0) ? 0 : 1; // increment? dtNext = new DateTime(start.Ticks + ((intervalsDiff + intervalInc) * intervalUnits)); if (unitId == TimeUnitId.Days) { // skips days if not on dowMask. if interval is multiple of 7 then this may never satisfy !! for (int i = 0; true; i++) { if (IsDowSet(dowBits, dtNext.DayOfWeek)) // good. { break; } if (i > 7) { return(DateUtil.kExtremeMax); // never } dtNext = dtNext.AddTicks(intervalUnits); } } } else { // month based time. not exact/Discreet time units. int monthsStart = start.Year * 12 + start.Month; int monthsNow = now.Year * 12 + now.Month; int monthsDiff = monthsNow - monthsStart; int intervalUnits = timeUnits * interval; int intervalsDiff = monthsDiff / intervalUnits; int intervalInc = ((monthsDiff % intervalUnits) == 0 && start.Day == now.Day && start.TimeOfDay == now.TimeOfDay) ? 0 : 1; // increment? dtNext = start.AddMonths((intervalsDiff + intervalInc) * intervalUnits); } return(dtNext); }