




Предполагая, что «Неделя» и «Год» означают неделю и год в соответствии с ИСО-8601, вы можете использовать эту функцию:
CREATE OR REPLACE FUNCTION ISOWeekDate(YEAR INTEGER, WEEK INTEGER, DAY INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF WEEK > 53 OR WEEK < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - INTERVAL '7' DAY, 'MONDAY') + ( WEEK - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res + DAY - 1;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
Я думаю, что для этого нет встроенной функции, вам придется создать ее самостоятельно. ниже приведено одно из решений, которое вы можете использовать.
WITH FUNCTION getDate(p_year IN NUMBER, p_weeks IN NUMBER, p_day in NUMBER) RETURN DATE
IS
v_tmp date;
v_day number;
BEGIN
v_tmp := to_date('01/01/'||to_char(p_year),'dd/mm/yyyy');
v_day := to_char(v_tmp,'D');
RETURN v_tmp+(p_weeks-1)*7+p_day-(v_day)+1;
END;
SELECT getDate(2019,22,2)
FROM DUAL;
/
Согласно моим настройкам NLS_TERRITORY, Oracle нумерует день недели, начиная с воскресенья, но из вашего примера вы, похоже, считаете понедельник первым днем недели. Таким образом, такая же корректировка вносится в функцию, чтобы вернуть ожидаемый результат.
Также обратите внимание, что функция предложения with — это новая функция Oracle 12c, и если вы используете более старую версию Oracle, вам придется создать хранимую функцию перед ее вызовом.
«Оракул нумерует день недели, начиная с воскресенья» неверно. Это зависит от текущей настройки сеанса пользователя NLS_TERRITORY.
Я не знал об этом. Спасибо, @WernfriedDomscheit за разъяснение.
Эта функция работает не для всех дат. Например, 2016-W52 — это неделя с 2016-12-26 по 2017-01-01 (согласно ISO 8601). getDate(2016,52,2) возвращается 2016-12-20 но так и должно быть 2016-12-27
Я думаю, это зависит от того, как мы нумеруем неделю в году. Немногие веб-сайты считают период с 28 декабря 2015 года по 3 января 2016 года 53-й неделей 2015 года. Если это так, 52-я неделя будет с 26 декабря 2016 года по 1 января 2017 года. Но если мы рассмотрим неделю 01 января 2016 года как первую неделю дня, независимо от дня, 52 неделя будет с 19 декабря 2016 года по 25 декабря 2016 года.
В Excel также есть функция WEEKNUM для возврата номера недели определенной даты, она также возвращает 20-12-2016 как неделю 52. WEEKNUM("20-dec-2016")
Да, это причина моего первого вопроса Как вы определяете «неделю», на который до сих пор нет ответа.
Я думаю, что для данного примера ввода и вывода должны быть выполнены следующие критерии. 1. Начать нумерацию недель с 01 января независимо от дня недели. 2. Дни в неделе должны нумероваться с понедельника, а не с воскресенья.
Логически, номер недели ISO — это количество четвергов в этом (григорианском) календарном году. Год ISO недели ISO — это год по григорианскому календарю, на который приходится четверг этой недели ISO.
В схеме ISO недели всегда содержат 7 дней. Недели начинаются в понедельник, заканчиваются в воскресенье, а дни этой недели нумеруются от 1 до 7.
Эта схема нумерации дней недели часто отличается от схемы, возвращаемой встроенными функциями WEEKDAY и аналогичной в разных пакетах программного обеспечения (или требует определенных настроек базы данных), о чем следует знать. Вам понадобится доступная функция, которая возвращает день недели определенной даты в соответствии со схемой нумерации ISO.
Первый четверг года может произойти в любом месте в диапазоне от 01 января до 07 января.
Если первый четверг выпадает на 01 января, то первая ISO-неделя этого года будет включать дни (29/31 декабря) из предыдущего года по григорианскому календарю.
Если первый четверг выпадает на 07 января, то последняя неделя ISO предыдущего года по григорианскому календарю будет включать дни (01/03 января) текущего года по григорианскому календарю.
Если первый четверг выпадает на 04 января, то подразумевается, что первая неделя ISO в году начинается с понедельника, 01 января.
Чтобы разработать алгоритм, самый простой подход, вероятно, состоит в том, чтобы установить, на какой день недели приходится 04 января в данном году, а затем применить следующий расчет 4 - weekday. Если день недели 04-января выпадает на четверг, результат будет 0. Если это понедельник, результат будет 3 (4-1). Если это воскресенье, результат будет -3 (4-7). Мы сохраним это смещение для использования после следующего шага.
Мы можем получить предварительное смещение дня года из номеров недель и дней ISO следующим образом: (((iso_week - 1) * 7) - (4 - iso_day)).
Затем мы применяем смещение, полученное на первом этапе, для окончательного смещения дня-года. Это смещение от 04 января данного года по григорианскому календарю. Это смещение может быть минусовой цифрой, если соответствующий день приходится на 04 января данного года.
Учитывая это смещение дня года, мы можем затем использовать встроенные функции для получения 04 января данного года и применить смещение дня года для получения окончательной даты по григорианскому календарю.
Например, учитывая 2019-W01-1.
2019-01-04 — пятница, поэтому день недели — 5. Результат первого шага — -1 (4-5). Результат второго шага равен -3 (((1-1)*7) - (4-1)). Сложенные вместе, они дают смещение дня года, равное -4. 04 января 2019 г. компенсировано на -4 результата 31 декабря 2018 г.
И это наш результат: 2019-W01-1 = 2018-12-31.
Как вы определяете "Неделя" - есть несколько определений, см. Нумерация недель