2016-04-14 6 views
3

Из DATEADD документации:DATEADD проблема, когда отрицательное число используется с МЕСЯЦА DATEPART

Если DatePart в месяц и дата месяц имеет больше дней, чем возвращение месяц и дата день не существует в обратном месяц, последний возвращается день возврата. Например, сентябрь имеет 30 дней; поэтому возвращаются следующие два отчета 2006-09-30 00: 00: 00.000:

ВЫБЕРИТЕ ДАТАДД (месяц, 1, '2006-08-30');

SELECT DATEADD (месяц, 1, '2006-08-31');

SQL Server знает, что в последний день 2016-03 является 31 и последний день 2016-04 является 30:

SELECT DAY(EOMONTH('2016-03-01')) -- 31 
SELECT DAY(EOMONTH('2016-04-01')) -- 30 

Тогда почему следующие:

SELECT DATEADD(MONTH, -1, '2016-04-30') 

возвращает 2016-03-30 00:00:00.000 вместо 2016-03-31 00:00:00.000 ?

Кроме того, если у меня есть следующие:

SELECT DATEADD(MONTH, -1, '2016-03-31') 

он правильно возвращает 2016-02-29 00:00:00.000.

+3

Ответ есть в вашем самом вопросе :) –

+3

... «и день не существует в месяц возвращения» ... - поскольку 30-й день существует в марте, он правильно возвращает 30-е марта – pastacool

+0

, если функции EOMONTH недостаточно для вас, и вы хотите «придерживаться некоторого подхода DATEADD, вы можете использовать что-то вроде« SELECT DATEADD »(MM, DATEDIFF (MM, -1, GETDATE()), 0) - 1 LastDayOfMonth' – pastacool

ответ

0

простой рабочий процесс для функции даты и времени

ie. за день - добавить день (следующий действительный день) за неделю - добавить неделю (следующие 7 дней) за месяц - добавить месяц (только в следующем месяце и заполнить, если дата недействительна) за год - добавить год

SELECT DATEADD(MONTH, -1, '2016-03-31')

output: 2016-02-29 00:00:00.000

в вашем примере:

2016-03-31 - 2016-02-31 (вычесть 1 месяц), но это не является допустимой датой, поэтому функция попытаться заполнить назад (в negtive) \ заполнять форвардную дату (в положительном). поэтому следующая действительная обратная дата - 2016-02-29.

заключение: функция используется для заполнения и заполнения назад.

0

Он не работает с положительными числами происходит от 30 -> 31 либо, например:

SELECT DATEADD(MONTH, 1, '2016-09-30') 

Урожайность 2016-10-30 00:00:00.000 вместо 2016-10-31 00:00:00.000

Предположительно это происходит потому, что вы не можете иметь тридцать первый день месяц с 30 днями, он переполнит поле даты, однако у вас может быть 30-е число месяца в месяц с 31-дневным штрафом.

+1

работает точно так, как описано в документации. – pastacool

+0

Он работает, вы ищете дату через месяц от даты начала поэтому месяц с 2016-09-30 составляет 2016-10-30. DATEADD не предназначен для предоставления вам значений конца месяца. Как это бывает, расчет месяца с этого момента для дат 20xx-08-30 и 20xx-08-31 - это та же дата 20xx-09-30. –

1

Как отмечалось в других комментариях, если день месяца существует в предыдущем месяце, DATEADD будет использовать его и не предполагать, что вы хотите «последний день месяца».

Если вы действительно хотите «Последний день месяца», вам придется обрюхатить немного больше логики, такие как:

DECLARE @date DATETIME = '30 April 2016' 
SELECT CASE WHEN DATEDIFF(MONTH, @date, DATEADD(DAY, 1, @date)) = 1 THEN  DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, @date), 0)) 
     ELSE DATEADD(MONTH, -1, @date) 
    END 

Это будет предполагать, что, если это последний день месяц, вы хотите последний день месяца в предыдущем месяце, а не явно 28, 29 или 30-е.