Лучшая практика игнорирования года в дате для диапазонов дат

StackOverflow https://stackoverflow.com/questions/601036

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

Будет ли Джода-Время здесь поможет библиотека?У меня нет опыта работы с ним, но, похоже, он гораздо более гибкий.

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

Это было полезно?

Решение

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

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

    }
}

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

Другие советы

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top