试着将今天的日期与一个月前的日期进行比较

本文关键字:日期 一个 比较 今天 | 更新日期: 2023-09-27 18:08:17

我有一个正在从数据库加载配置的对象。我用日期时间字段(称为GroupsLastRun)存储作业的最后一次运行时间,用字符串字段(称为Captureusersandgroups)存储作业的运行频率。Captureusersandgroups存储三种不同类型的'DAILY', 'WEEKLY'和'MONTHLY'。

基本上,我有一个循环应该只在作业即将运行时继续。到目前为止,我已经得到了以下几点:

if (configEntity.GroupsLastrun > DateTime.Now.AddDays(-1) && configEntity.Captureusersandgroups == "DAILY") continue;
if (configEntity.GroupsLastrun > DateTime.Now.AddDays(-7) && configEntity.Captureusersandgroups == "WEEKLY") continue;
if (configEntity.GroupsLastrun > DateTime.Now.AddDays(-30) && configEntity.Captureusersandgroups == "MONTHLY") continue;

我确信(肯定)有更好的方法来解决这个问题,但主要是作为一个SQL Server开发人员,我缺乏解决这个问题的批判性思维/工具。什么是更好的方法或者我应该学习什么以便更好地思考这个问题?

试着将今天的日期与一个月前的日期进行比较

几点说明:

  • 除非你想在时区和夏令时转换等的支配下,我会使用DateTime.UtcNow而不是DateTime.Now(并确保你存储 UTC值)
  • 正如p.s.w.g.所提到的,只要求当前日期/时间一次是值得的,而不是性能,我想说重要的原因是一致性。在这种情况下,看起来你只会实际使用其中一个值,但在其他情况下,我看到有人编写条件,同时使用两个评估,导致问题,如果代码在午夜运行
  • 由于检查条件同时确定截止日期,导致代码重复。我会把两者分开。

那么,我要写这样的代码:

// Consider whether you actually want DateTime.UtcNow.Date
DateTime now = DateTime.UtcNow;
DateTime deadline;
switch (configEntity.Captureusersandgroups)
{
    case "DAILY": deadline = now.AddDays(-1);
    case "WEEKYLY": deadline = now.AddDays(-7);
    case "MONTHLY": deadline = now.AddMonths(-1);
    // I'm assuming there's *always* a schedule
    default: throw new InvalidOperationException("Invalid schedule");
}
if (configEntity.GroupsLastrun > deadline)
{
    continue;
}

请注意,从"现在"减去一个月与从"那时"增加一个月是不一样的。例如,如果最后一次运行是在1月30日,那么使用上述代码,下一次运行将直到3月1日才运行—而如果您在1月30日添加了一个月,则下一次运行将在2月28日运行(除非您使用两个值的日期)。仔细考虑你想要的行为。

(作为一个快速插件,我还明显建议考虑使用我的Noda Time库进行日期/时间工作。它使任何特定值是本地时间,还是在某个时区等更清楚)

两点:

  1. DateTime.Now可以(潜在的)每次调用时返回不同的日期。它也不是很快。通过只调用一次,您将获得更好的一致性和非常轻微的性能提升。
  2. 你可能应该使用标准的方法来添加周和月,以保持一致性(例如,一个月并不总是有30天)和全球化(例如,不是所有的文化都有7天的一周)。请注意,没有简单的方法来增加周与DateTime单独;你将不得不使用Calendar代替。

试试这个:

var now = DateTime.UtcNow; // See Jon Skeet's answer
var cal = CultureInfo.InvariantCulture.Calendar;
if (configEntity.GroupsLastrun > now.AddDays(-1) && configEntity.Captureusersandgroups == "DAILY") continue;
if (configEntity.GroupsLastrun > cal.AddWeeks(now, -1) && configEntity.Captureusersandgroups == "WEEKLY") continue;
if (configEntity.GroupsLastrun > now.AddMonths(-1) && configEntity.Captureusersandgroups == "MONTHLY") continue;

或者只使用cal:

var now = DateTime.UtcNow; // See Jon Skeet's answer
var cal = CultureInfo.InvariantCulture.Calendar;
if (configEntity.GroupsLastrun > cal.AddDays(now, -1) && configEntity.Captureusersandgroups == "DAILY") continue;
if (configEntity.GroupsLastrun > cal.AddWeeks(now, -1) && configEntity.Captureusersandgroups == "WEEKLY") continue;
if (configEntity.GroupsLastrun > cal.AddMonths(now, -1) && configEntity.Captureusersandgroups == "MONTHLY") continue;

作为一种替代方法,您可以将运行周期存储在enum中,如:

enum RunPeriod
{
    Daily = 1,
    Weekly = 7,
    Monthly = 30
}

然后您可以在数据库中存储int值,而不是string值。这允许您在DB端进行过滤,例如:

var configsToRun = 
    from c in _myContext.Configs
    where EntityFunctions.AddDays(c.LastRun,(int)c.RunPeriod) > DateTime.Now);