首页 > 解决方案 > 仅跳过一年中的公共假期的 Cron 表达式

问题描述

我有一个 ASP.Net MVC 应用程序,我们正在使用日历控件来选择 UI 上的日期。我们使用 cron 表达式来设置公共假期日期。我的要求是 UI 上的日期选择器不应允许用户选择使用 cron 表达式设置的公共假期日期。我想验证我的 cron 表达式是否正确。如果它正确,我的 C# 代码有什么问题。我的函数没有返回有效日期。它的返回假期也作为有效日期的一部分。

以下是我需要跳过的假期列表 - 新年、阵亡将士纪念日、独立日、劳动节、感恩节、感恩节后一天、圣诞节晚上、圣诞节。

感谢你的帮助 !在代码和 cron 表达式下方,在 GetDate 函数的末尾,我试图获取有效日期。我正在寻找公共假期(不是周末,不是假期)的 cron 表达式。

List<DateTime> GetDates(DateTime cutOffDate, bool isAlways = false, string Code = null, string TestMethod = null)
        {
            var validDates = new List<DateTime>();
            try
            {
                List<string> cronExpressionStrings = new List<string>();
                cronExpressionStrings.Add("0 0 0 1 1 ? *"); // New Year Day
                cronExpressionStrings.Add("0 0 0 ? 5 MON#4 *"); //Memorial Day
                cronExpressionStrings.Add("0 0 0 4 7 ? *"); //Independence Day
                cronExpressionStrings.Add("0 0 0 ? 9 MON#1"); //Labor Day
                cronExpressionStrings.Add("0 0 0 ? 11 THU#4 *");//Thanksgiving
                cronExpressionStrings.Add("0 0 0 ? 11 FRI#4 *");//Day after Thanksgiving
                cronExpressionStrings.Add("0 0 0 24 12 ? *"); //Chrismas Evening
                cronExpressionStrings.Add("0 0 0 25 12 ? *"); //Chrismas

                var currentDateTimeWithPaddingDays = AddPaddingDaysToDate(DateTime.UtcNow);

                if (cronExpressionStrings?.Count > 0)
                {
                    foreach (string cronExpressionString in cronExpressionStrings)
                    {
                        var cronExpression = new CronExpression(cronExpressionString);

                        //If the first padded date is the same as the first Cron date then add that day to valid days
                        var firstCronDate = cronExpression.GetNextValidTimeAfter(DateTime.UtcNow);
                        if (firstCronDate.Value.Date == currentDateTimeWithPaddingDays.Date)
                        {
                            if (!validDates.Contains(currentDateTimeWithPaddingDays.Date))
                            {
                                validDates.Add(currentDateTimeWithPaddingDays.ToUniversalTime().Date);
                            }
                        }

                        DateTimeOffset? currentDateTimeWithPaddingDaysOffset = currentDateTimeWithPaddingDays;

                        //If no drop down padding days were used, then get next Cron date
                        if (currentDateTimeWithPaddingDays.Date == DateTime.UtcNow.Date)
                        {
                            currentDateTimeWithPaddingDaysOffset = cronExpression.GetNextValidTimeAfter(currentDateTimeWithPaddingDays).Value;
                        }

                        for (var dateTimeOffset = currentDateTimeWithPaddingDaysOffset;
                             (dateTimeOffset?.Date < cutOffDate.Date);)
                        {
                            if (!validDates.Contains(dateTimeOffset.Value.Date))
                            {
                                validDates.Add(dateTimeOffset.Value.Date);
                            }

                            dateTimeOffset = cronExpression.GetNextValidTimeAfter(dateTimeOffset.Value).Value;
                        }
                    }
                }
                else
                {
                    var dateOnly = new DateTime(currentDateTimeWithPaddingDays.Year, currentDateTimeWithPaddingDays.Month, currentDateTimeWithPaddingDays.Day);

                    validDates.AddRange(Enumerable.Range(0, 1 + cutOffDate.Subtract(dateOnly).Days)
                                                  .Select(offset => dateOnly.AddDays(offset))
                                                  .ToArray());
                }
            }
            catch (Exception ex)
            {
                log.Error("test", ex);
                throw;
            }

            return validDates.OrderBy(d => d).ToList();
        }


private DateTime AddPaddingDaysToDate(DateTime date)
        {
            try
            {
                var groupName = DropDownGroupName.PaddingMatrix.ToString();
                var paddingMatrix = (from b in context.DropDownValue.AsNoTracking()
                                     join d in context.DropDownGroup.AsNoTracking() on b.TableCode equals d.ID
                                     where d.TableName == groupName
                                     select new DropDownValueArgs
                                     {
                                         ID = d.ID,
                                         Name = b.Name,
                                         Value = b.Value,
                                         Description = b.Description,
                                         RegionCode = b.RegionCode
                                     }).ToList();
                if (paddingMatrix.Count > 0)
                {
                    var paddingdays = paddingMatrix.Where(z => string.Equals(z.Name, date.Hour.ToString(), StringComparison.InvariantCultureIgnoreCase) && string.Equals(z.RegionCode, date.DayOfWeek.ToString(), StringComparison.InvariantCultureIgnoreCase)).Select(z => z.Value).FirstOrDefault();
                    date = date.AddDays(double.Parse(paddingdays, System.Globalization.CultureInfo.InvariantCulture));
                }
            }
            catch (Exception ex)
            {
                log.Error("AddPaddingDaysToDate()", ex);
                throw;
            }

            return date;
        }

标签: c#asp.netasp.net-mvccron

解决方案


因此,您不希望任何有效日期成为您的 cron 表达式中定义的假期,但在您的代码中您说:

if (firstCronDate.Value.Date == currentDateTimeWithPaddingDays.Date)
{
    if (!validDates.Contains(currentDateTimeWithPaddingDays.Date))
    {
        validDates.Add(currentDateTimeWithPaddingDays.ToUniversalTime().Date);
    }
}

这基本上就像说“如果日期是假期,请将其添加到有效日期列表中”,这与您想要的完全相反,不是吗?

所以也许改为说:

if (firstCronDate.Value.Date != currentDateTimeWithPaddingDays.Date)

如果您的 cron 表达式有问题,可以在这里测试它们:https ://www.freeformatter.com/cron-expression-generator-quartz.html


推荐阅读