c# - 使用 NodaTime(或替代方法)比较期间的最佳方法

标签 c# nodatime

我需要有一个能够存储在数据库中的相对最小/最大日期验证,以便为每个客户定制应用程序。我认为 NodaTime.Period 是最佳选择,因为它能够指定年份。但是,NodaTime.Period 不提供将自身与另一个时期进行比较的方法。

为此验证提供的示例数据:

  • 最低年龄为 18 岁。
  • 最大年龄 o 100 岁。
  • 最短销售时间为 1 个月
  • 最长销售期限为 3 个月
  • 至少 7 天的广告事件

(注意:目前的要求是年/月/日不会在验证中合并)

验证是:

public Period RelativeMinimum { get; set; }
public Period RelativeMaximum { get; set; }

给定用户输入的日期(和现在):

var now = new LocalDate(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
var userValue = new LocalDate(date.Year, date.Month, date.Day);
var difference = Period.Between(userValue, now);

我有一个比较:

if(RelativeMinimum != null && difference.IsLessThan(RelativeMinimum))))
{
    response.IsValid = false;
    response.Errors.Add(MinimumErrorMessage);
}

正在使用扩展类:

public static class PeriodExtensions
{
    public static bool IsLessThan(this Period p, Period p2)
    {
        return (p.Years < p2.Years) || (p.Years == p2.Years && p.Months < p2.Months) || (p.Years == p2.Years && p.Months == p2.Months && p.Days < p2.Days);
    }

    public static bool IsGreaterThan(this Period p, Period p2)
    {
        return (p.Years > p2.Years) || (p.Years == p2.Years && p.Months > p2.Months) || (p.Years == p2.Years && p.Months == p2.Months && p.Days > p2.Days);
    }
}

虽然这种方法有效,但考虑到我的测试条件,我想知道为什么 @jon-skeet 没有实现它,并且立即不得不担心我遗漏了什么以及我应该使用什么替代方案?

最佳答案

周期不可比的主要原因是它们可以包含可变长度的组件。

两个为期一个月的时间段的天数不一定相同。例如,哪个更大:1 个月还是 30 天?如果月份是一月,则超过 30 天。如果月份是二月,则少于 30 天。

这同样适用于年份。有些是 365 天,有些是 366。

当然,所有这些都假设您使用的是公历。野田时间支持其他日历系统,这些系统也有类似的怪癖。

关于代码:

  • 如果您想要 DateTime 中的 LocalDate,请使用 LocalDateTime.FromDateTime(dt).Date

    /li>
  • 要获取当前日期,请使用 SystemClock.Instance.Now.InZone(tz).Date

    • 如果您希望它与 DateTime.Now 相同,它使用运行代码的计算机的本地时区,则通过调用获取 tz DateTimeZoneProviders.Tzdb.GetSystemDefault()
  • 为了比较您所描述的问题类型,请考虑定义最小和最大,而不是最小和最大周期。那么你就不会有这样的单位变化。你可以在这样的日子里得到不同:

    long days = Period.Between(d1, d2, PeriodUnits.Days).Days;
    

我相信这样的事情会很适合你的用例:

public static bool IsDifferenceLessThan(LocalDate d1, LocalDate d2, Period p)
{
    if (p.HasTimeComponent)
        throw new ArgumentException("Can only compare dates.", "p");

    if (p.Years != 0)
    {
        if (p.Months != 0 || p.Weeks != 0 || p.Days != 0)
            throw new ArgumentException("Can only compare one component of a period.", "p");

        var years = Period.Between(d1, d2, PeriodUnits.Years).Years;
        return years < p.Years;
    }

    if (p.Months != 0)
    {
        if (p.Weeks != 0 || p.Days != 0)
            throw new ArgumentException("Can only compare one component of a period.", "p");

        var months = Period.Between(d1, d2, PeriodUnits.Months).Months;
        return months < p.Months;
    }

    if (p.Weeks != 0)
    {
        if (p.Days != 0)
            throw new ArgumentException("Can only compare one component of a period.", "p");

        var weeks = Period.Between(d1, d2, PeriodUnits.Weeks).Weeks;
        return weeks < p.Weeks;
    }

    var days = Period.Between(d1, d2, PeriodUnits.Days).Days;
    return days < p.Days;
}

关于c# - 使用 NodaTime(或替代方法)比较期间的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30226705/

相关文章:

c# - VS 强制抛出异常

c# - "The type mapping for ' Instant ' has not implemented code literal generation"分割实体时

c# - Noda Time WeekOfWeekYear 从星期日开始而不是星期一

c# - 问题从标准模式解析 NodaTime LocalDate

c# - 使用 Url.Link 在 Web API 中生成 HTTPS 链接

c# - 我在哪里可以找到 Visual Studio 2017 中的 trackbar winforms 控件?

c# - 使用 Unity 中的 slider 更改数组中一个 AudioSource 的音量

c# - 字符串 "search and replace"使用 .NET 正则表达式

c# - 如何在同一个 JSON 对象中反序列化不同的 NodaTime LocalDate 模式

nodatime - Noda 的收盘/开盘时间表示为一整天(24 小时周期)