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

时间:2013-04-10 05:35:43

标签: c# .net date datetime

我有一个从数据库加载配置的对象。我存储上次使用日期时间字段(称为GroupsLastRun)运行作业的时间,并存储作业应该使用名为Captureusersandgroups的字符串字段运行的频率。 Captureusersandgroups存储三种不同类型'每日','每周'和'每月'。

基本上,如果作业要运行,我只能继续循环。到目前为止,我已经达到了以下几点:

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开发人员,我缺乏批判性思维/工具来接近这个。什么是更好的方法或我应该学习什么,所以我可以更好地考虑这个?

3 个答案:

答案 0 :(得分:7)

几点:

  • 除非你想受时区和夏令时过渡等的影响,否则我会使用DateTime.UtcNow而不是DateTime.Now(并确保你存储也是UTC值)
  • as 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;
}

请注意,从“now”减去一个月与从“then”添加一个月不同。例如,如果最后一次运行是在1月30日,那么下一次运行将不会在3月1日之前使用上述代码 - 而如果您在1月30日添加了一个月,那么接下来将在2月28日运行(除非您使用两个值的日期)。仔细考虑您想要的行为。

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

答案 1 :(得分:3)

两点:

  1. DateTime.Now可以(潜在)每次调用时返回不同的日期。它也不是很快。只需调用一次,您就可以获得更好的一致性和非常轻微的性能提升。
  2. 您应该使用标准方法添加数周和数月,以保持一致性(例如,一个月内不总是30天)和全球化(例如,并非所有文化都有7天工作周)。请注意,单独使用DateTime添加周数并不容易;你必须使用Calendar代替。
  3. 试试这个:

    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;
    

答案 2 :(得分:1)

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

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

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

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