Поясню: есть календарь некоторых знаменательных или круглых дат. Составляется он на несколько лет. События имеют вид "16 января 2017 года День ледовара – 116 лет со дня рождения американского инженера Фрэнк Замбони, который изобрел ресурфейсер – ледовый комбайн для восстановления льда на катках". Дата начала события, как правило, задается контент-менеджером, и время ему прописывать незачем, оно ставится по умолчанию в 00:00
"Из коробки" фильтр новостей предлагает выборку по годам. Надо было добавить внутри годов еще и месяцы. Вот тут началось самое интересное. С годами-то оно всё просто: есть первый день года 01.01.YYYY и есть последний день 31.12.YYYY и каждый год одно и то же. Для лучшей выборки надо бы еще время прописать, потому что по-умолчанию оно 00:00.
Всё же настало время вставить немного кода: Изначально у ASPRO фильтрация по годам реализована следующим образом:
map $http_referer $frame_options {
"~webvisor.com" "ALLOW-FROM http://webvisor.com";
default "SAMEORIGIN";
}
if($bHasYear)// переменная хранит в себе TRUE/FALSE в зависимости от того, задан ли у новости год. { $GLOBALS[$arParams["FILTER_NAME"]][">DATE_ACTIVE_FROM"] = ConvertDateTime("31.12.".($year-1), FORMAT_DATETIME); $GLOBALS[$arParams["FILTER_NAME"]]["<=DATE_ACTIVE_FROM"] = ConvertDateTime("31.12.".$year, FORMAT_DATETIME); }?> в $arParams добавляются данные, которые позже используются для выборки нужных элементов.
Обратите внимание на DATE_ACTIVE_FROM и DATE_ACTIVE_FROM. Символы перед ним – это знаки сравнения. Они определяют включение заданных диапазонов дат. С ними надо быть внимательным, а то результат на пограничных датах может оказаться неверным.
В данном случае нам предлагается при выборе конкретного года отобразить
события с 31.12.ПРЕДЫДУЩЕГО_ВЫБРАННОГО_ГОДА не включительно, по 31.12.ВЫБРАННОГО_ГОДА.
Всё бы ничего, но если мы используем время, то 31.12.ПРЕДЫДУЩЕГО_ВЫБРАННОГО_ГОДА 00:01 (это время) оно уже подходит и оно попадет в выборку, хоть и является прошлогодним.
Такая же участь ждет все события, которые произошли 31.12.ВЫБРАННОГО_ГОДА, которые по времени хоть на одну минуту старше начала этого дня.
Не порядок. Надо уточнять.
map $http_referer $frame_options {
"~webvisor.com" "ALLOW-FROM http://webvisor.com";
default "SAMEORIGIN";
}
if($bHasYear){
$GLOBALS[$arParams["FILTER_NAME"]][">=DATE_ACTIVE_FROM"] = ConvertDateTime("01.01.".($year)." 00:00:00", FORMAT_DATETIME);
$GLOBALS[$arParams["FILTER_NAME"]]["<=DATE_ACTIVE_FROM"] = ConvertDateTime("31.12.".($year)." 23:59:59", FORMAT_DATETIME);
}
Так получается сильно точнее.
Но остается проблема с месяцами. Если бы в каждом было 30 дней, по аналогичной схеме уточняем фильтр и всё. Но реальность сурова. У всех двенадцати месяцев вразнобой последнее число и еще февраль есть... иногда високосный...
Можно было бы написать тут "вечный календарь" и брать из него данные по последнему числу месяца, но это слишком.
Функция Битрикса ConvertDateTime не обладает богатым функционалом. Но у неё оказался скрытый потенциал.
Оказывается, если ей предложить на входе 33 марта 2017 года, то на выходе это будет 2 апреля 2017.
"Ух-ты!" – подумал я, просто ради эксперимента попробовав что-то подобное. А мне же надо найти вчерашний день!
Оказывается, функция неплохо понимает "нулевое марта" и возвращает последнее число февраля! "Нулевое января" будет предыдущим днем с годом и всеми атрибутами :)
В итоге получился вот такой код:
map $http_referer $frame_options {
"~webvisor.com" "ALLOW-FROM http://webvisor.com";
default "SAMEORIGIN";
}
if($bHasYear){ // переменная хранит в себе TRUE/FALSE в зависимости от того, задан ли у новости год.
$GLOBALS[$arParams["FILTER_NAME"]][">DATE_ACTIVE_FROM"] = ConvertDateTime("31.12.".($year-1)." 23:59:59", FORMAT_DATETIME);
$GLOBALS[$arParams["FILTER_NAME"]]["<=DATE_ACTIVE_FROM"] = ConvertDateTime("00.01.".($year+1)." 23:59:59", FORMAT_DATETIME);
//здесь мы для фильтра загружаем $arParams
}
if($bHasMonth) // переменная хранит в себе TRUE/FALSE в зависимости от того, задан ли у новости месяц
{
//Если у нас есть и месяц - затираем предыдущие данные и записываем более точные.
$GLOBALS[$arParams["FILTER_NAME"]][">DATE_ACTIVE_FROM"] = ConvertDateTime("00.".($month).".".($year)." 23:59:59", FORMAT_DATETIME);
$GLOBALS[$arParams["FILTER_NAME"]]["
}
ConvertDateTime("00.".($month).".".($year)." 23:59:59", FORMAT_DATETIME); возвращает нас на одну секунду назад от интересующего нас события.
Мы берем всё, что больше полученного значения.
Я понимаю, что можно было бы просто сделать вот так:
map $http_referer $frame_options {
"~webvisor.com" "ALLOW-FROM http://webvisor.com";
default "SAMEORIGIN";
}
$GLOBALS[$arParams["FILTER_NAME"]][">=DATE_ACTIVE_FROM"] = ConvertDateTime("01.".($month).".".($year)." 00:00:00", FORMAT_DATETIME);
Но тогда никто бы не узнал о такой занятной способности ConvertDateTime как "нулевое января".
Программист Сергей, WEB-AiM