Это в основном ответ CMS без опоры на конкретную языковую настройку. А поскольку мы снимаем для общего, это означает, что оно должно работать и для всех @@datefirst
настроек.
datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
/* if start is a Sunday, adjust by -1 */
+ case when datepart(weekday, <start>) = 8 - @@datefirst then -1 else 0 end
/* if end is a Saturday, adjust by -1 */
+ case when datepart(weekday, <end>) = (13 - @@datefirst) % 7 + 1 then -1 else 0 end
datediff(week, ...)
всегда использует границу от субботы до воскресенья в течение нескольких недель, так что выражение является детерминированным и не нуждается в изменении (при условии, что наше определение дней недели последовательно с понедельника по пятницу.) Нумерация дней меняется в соответствии с настройкой @@datefirst
и модифицированными вычислениями эта поправка обрабатывается с небольшим усложнением некоторой модульной арифметики.
Более понятный способ работы с субботой / воскресеньем - это перевод дат до извлечения значения дня недели. После сдвига значения вернутся в соответствие с фиксированной (и, вероятно, более знакомой) нумерацией, которая начинается с 1 в воскресенье и заканчивается 7 в субботу.
datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
+ case when datepart(weekday, dateadd(day, @@datefirst, <start>)) = 1 then -1 else 0 end
+ case when datepart(weekday, dateadd(day, @@datefirst, <end>)) = 7 then -1 else 0 end
Я проследил эту форму решения еще по крайней мере до 2002 года и опубликовал статью Ицик Бен-Ган. (https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx) Несмотря на необходимость небольшой настройки, поскольку более новые типы date
не допускают арифметику дат, в остальном она идентична.
EDIT:
Я добавил обратно +1
, который так или иначе был оставлен. Стоит также отметить, что этот метод всегда считает дни начала и окончания. Предполагается также, что дата окончания указана в или после даты начала.