【问题标题】:Best practice for ignoring year in date for date ranges忽略日期范围的日期年份的最佳做法
【发布时间】:2010-10-10 16:54:51
【问题描述】:

我需要对一些关于季节的信息进行建模,并且需要根据开始/结束日期以与年份无关的方式跟踪它们。 IE。我需要允许用户将夏季定义为介于 5 月 15 日和 9 月 10 日之间,并且在所有年份都这样做。

我需要对 isThisDateInSeason 类型进行大量检查)。所有日期操作功能(即日期、日历)似乎只适用于有效日期,即包括年份信息。

有没有关于如何做到这一点的最佳做法?我可以想出一堆骇人听闻的方法(即存储月份和日期或存储日期并将它们带到基线年份,以便我可以比较),但似乎有更好的方法.

我正在用 Java 或 Groovy 编写这个。

Joda-Time 库会在这里提供帮助吗?我没有这方面的经验,但它看起来更灵活。

我找到了 this question 关于如何识别从日期开始的季节,但它侧重于月份,我需要更大的灵活性来包含日期。

【问题讨论】:

  • 是否会跨用户使用相同的数据?即 1 个数据输入和几个用户可以根据他们的位置将其视为夏季或冬季?还是每个用户都有自己的数据?
  • 这取决于位置,用户可以进一步自定义。

标签: java groovy date jodatime


【解决方案1】:

如果每个用户都拥有自己的数据(即他们指定了他们的季节,然后他们输入了自己的信息),那么您可以将数据与季节一起作为其中的一部分来存储,但是我感觉您所追求的场景是用于在定义不同季节的众多用户之间共享数据。

您必须非常小心地“标准化”日期,因为闰年​​可能会导致意外问题,即尝试将 2 月 29 日设置为非闰年会导致问题/异常。

我将以下内容放在一起,不幸的是它的 c# 但概念是相同的。我还没有实际测试过代码,但作为伪代码它可能会有所帮助。

public class SeasonChecker
{
    public enum Season {Summer, Autumn, Winter, Spring};
    private List<SeasonRange> _seasons = new List<SeasonRange>();

    public void DefineSeason(Season season, DateTime starting, DateTime ending)
    {
        starting = starting.Date;
        ending = ending.Date;

        if(ending.Month < starting.Month)
        {
            // split into 2
            DateTime tmp_ending = new DateTime(ending.Year, 12, 31);
            DateTime tmp_starting = new DateTime(starting.Year, 1, 1);

            SeasonRange r1 = new SeasonRange() { Season = season, Starting= tmp_starting, Ending = ending };
            SeasonRange r2 = new SeasonRange() { Season = season, Starting= starting, Ending = tmp_ending };

            this._seasons.Add(r1);
            this._seasons.Add(r2);
        }
        else
        {
            SeasonRange r1 = new SeasonRange() { Season = season, Starting= starting, Ending = ending };
            this._seasons.Add(r1);
        }
    }

    public Season GetSeason(DateTime check)
    {
        foreach(SeasonRange range in _seasons)
        {
            if(range.InRange(check))
                return range.Season;
        }

        throw new ArgumentOutOfRangeException("Does not fall into any season");
    }


    private class SeasonRange
    {
        public DateTime Starting;
        public DateTime Ending;
        public Season Season;

        public bool InRange(DateTime test)
        {
            if(test.Month == Starting.Month)
            {
                if(test.Day >= Starting.Day)
                {
                    return true;
                }
            }
            else if(test.Month == Ending.Month)
            {
                if(test.Day <= Ending.Day)
                {
                    return true;
                }
            }
            else if(test.Month > Starting.Month && test.Month < Ending.Month)
            {
                return true;
            }

            return false;
        }

    }
}

请注意,上面的代码假设赛季不会在同一个月开始和结束 - 我认为这是一个相当安全的假设!

【讨论】:

  • Ross - 非常感谢伟大的代码示例。我既需要地理的通用定义,也需要用户自定义的能力。奇怪的是,没有存储年份就无法做到这一点,无论是在 Java 还是 C# 中,但我想它出现的频率不足以证明特殊 API 的合理性。
  • NYWebGuy - N.P.是的,这似乎是一个相当普遍的问题,有兴趣知道你最终想出了什么。我唯一可以补充的是,您可以有 2 个模板来覆盖 n/s 半球,并且用户可以在那里自定义表单?
【解决方案2】:

我认为您必须推出自己的 DateRange 类,尽管这是一个常见的问题,但您希望已经有一个聪明的工具可以做到这一点。作为处理季节的一般要点,您还必须考虑地理因素,这将使生活变得非常艰难。在奥兹,我们与美国相反,所以夏季从 11 月持续到 2 月。

【讨论】:

    【解决方案3】:

    数据在哪里?如果它在数据库中,我会考虑为日期制作一个表(如 OLAP 中的时间维度)。然后,您可以在某些时间维度示例中为您的季节计算一个列,就像它们为财务季度一样。 (这是假设您的季节没有变化但有固定日期)。

    所有“如果在季节中的日期”类型检查将预先构建,将计算季节的成本推到您的设置时间而不是运行时间。

    编辑:刚刚看到您对用户可配置季节日期的评论。这仍然可以工作,因为您可以在包括时间维度的数据库中进行连接,这可能比在 Java 中更容易处理数据集。

    【讨论】:

    • 谢谢,@Leah。看起来我必须做一些类似于你建议的事情,虽然我正在使用 Groovy / GORM,所以我最初试图保持比 DB 级别高一点,并且稍后会努力优化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多