Лучшая практика игнорирования года в дате для диапазонов дат
Вопрос
Мне нужно смоделировать некоторую информацию о сезонах и отслеживать их на основе даты начала/окончания независимо от года.Т.е.Мне нужно разрешить пользователям определять лето как период, скажем, с 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.