Лучшая практика игнорирования года в дате для диапазонов дат - PullRequest
4 голосов
/ 02 марта 2009

Мне нужно смоделировать некоторую информацию о сезонах, и мне нужно отслеживать их, основываясь на дате начала / окончания, независимо от года. То есть Мне нужно разрешить пользователям определять лето как, скажем, между 15 мая и 10 сентября, и делать это на протяжении всех лет.

Мне нужно много проверить типа isThisDateInSeason). Кажется, что все функции манипуляции с датами (то есть дата, календарь) работают только с действительными датами, то есть с информацией о году.

Есть ли лучшие практики, как это сделать? Я могу придумать несколько хакерских способов сделать это (например, сохранить месяц и день месяца или сохранить даты и просто перенести их в базовый год, чтобы я мог сравнить), но кажется, что может быть лучший способ ,

Я пишу это на Java или Groovy.

Поможет ли здесь библиотека Joda-Time ? У меня нет опыта работы с ним, но, похоже, он обладает большей гибкостью.

Я нашел этот вопрос о том, как определить сезон с датой, но он сосредоточен на месяцах, и мне нужно больше гибкости, чтобы включать даты.

Ответы [ 3 ]

4 голосов
/ 02 марта 2009

Если у каждого пользователя есть свои собственные данные (то есть они задают свои сезоны, а затем вводят свою собственную информацию), то вы можете просто сохранить данные вместе с сезоном как часть этого, однако у меня есть ощущение, что сценарий, который вам нужен, для общих данных среди многочисленных пользователей, которые по-разному определяют времена года.

Вы должны быть очень осторожны, чтобы «нормализовать» даты, поскольку високосный год может вызвать непредвиденные проблемы, т. Е. Попытка установить 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;
        }

    }
}

Обратите внимание, что в приведенном выше коде делается предположение, что сезон не начнется и не закончится в одном и том же месяце - я думаю, что он довольно безопасный!

2 голосов
/ 02 марта 2009

Где данные? Если он находится в базе данных, я бы рассмотрел создание таблицы для дат (например, измерение времени в OLAP). Затем вы можете рассчитать столбец для ваших сезонов, как и для финансовых кварталов, в некоторых примерах измерения времени. (это предполагает, что ваш сезон не меняется, но имеет фиксированные даты).

Все проверки типа «если дата в сезоне» будут выполнены заранее, что приведет к увеличению затрат на подсчет времени года во время настройки, а не во время выполнения.

Редактировать: Только что увидел ваш комментарий о настраиваемых пользователем датах сезона. Это все равно будет работать, так как вы можете выполнить объединение в базе данных, включая измерение времени, которое может быть легче работать с набором данных, чем в Java.

2 голосов
/ 02 марта 2009

Я думаю, что вам придется свернуть свой собственный класс DateRange, хотя это такая распространенная проблема, что вы могли бы надеяться, что уже есть умная утилита, которая делает это. Как правило, при работе с временами года вы также должны учитывать географию, которая действительно усложнит жизнь. В Оз мы противоположны США, поэтому лето длится с ноября по февраль.

...