Создайте дату из месяца и года дня с помощью T-SQL

Я пытаюсь преобразовать дату с отдельными частями, такими как 12, 1, 2007, в datetime в SQL Server 2005. Я попробовал следующее:

CAST(DATEPART(year, DATE)+'-'+ DATEPART(month, DATE) +'-'+ DATEPART(day, DATE) AS DATETIME)

но это приводит к неправильной дате. Как правильно превратить три значения даты в правильный формат datetime.

14 ответов


предполагая, что y, m, d все int, как:

CAST(CAST(y AS varchar) + '-' + CAST(m AS varchar) + '-' + CAST(d AS varchar) AS DATETIME)

см. мой другой ответ для SQL Server 2012 и выше


попробуйте это:

Declare @DayOfMonth TinyInt Set @DayOfMonth = 13
Declare @Month TinyInt Set @Month = 6
Declare @Year Integer Set @Year = 2006
-- ------------------------------------
Select DateAdd(day, @DayOfMonth - 1, 
          DateAdd(month, @Month - 1, 
              DateAdd(Year, @Year-1900, 0)))

Он также работает, добавил преимущество не делать никаких преобразований строк, поэтому это чистая арифметическая обработка (очень быстрая), и она не зависит от формата даты Это основывается на том факте, что внутреннее представление SQL Server для значений datetime и smalldatetime представляет собой значение из двух частей, первая часть которого представляет собой целое число, представляющее количество дней с 1 января 1900 года, а вторая часть-десятичную дробь, представляющую дробную часть часть одного дня (для времени) - - - поэтому целое значение 0 (ноль) всегда переводится непосредственно в полночь 1 января 1900 года...

или, благодаря предложению от @brinary,

Select DateAdd(yy, @Year-1900,  
       DateAdd(m,  @Month - 1, @DayOfMonth - 1)) 

Отредактировано Октябрь 2014. Как отметил @cade Roux, SQL 2012 теперь имеет встроенную функцию:
DATEFROMPARTS(year, month, day)
это то же самое.

отредактировано 3 окт. 2016, (спасибо @bambams за это замечание и @brinary за его исправление), последнее решение, предложенное @brinary. кажется, не работает в високосные годы, если сначала не выполняется добавление лет

select dateadd(month, @Month - 1, 
     dateadd(year, @Year-1900, @DayOfMonth - 1)); 

SQL Server 2012 имеет замечательную и долгожданную новую функцию DATEFROMPARTS (которая вызовет ошибку, если дата недействительна - мое главное возражение против решения этой проблемы на основе DATEADD):

http://msdn.microsoft.com/en-us/library/hh213228.aspx

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

или

DATEFROMPARTS(@y, @m, @d)

или используя только одну функцию dateadd:

DECLARE @day int, @month int, @year int
SELECT @day = 4, @month = 3, @year = 2011

SELECT dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)

Sql Server 2012 имеет функцию, которая будет создавать дату на основе частей (DATEFROMPARTS). Для остальных из нас, вот функция db, которую я создал, которая определит дату из частей (спасибо @Charles)...

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[func_DateFromParts]'))
    DROP FUNCTION [dbo].[func_DateFromParts]
GO

CREATE FUNCTION [dbo].[func_DateFromParts]
(
    @Year INT,
    @Month INT,
    @DayOfMonth INT,
    @Hour INT = 0,  -- based on 24 hour clock (add 12 for PM :)
    @Min INT = 0,
    @Sec INT = 0
)
RETURNS DATETIME
AS
BEGIN

    RETURN DATEADD(second, @Sec, 
            DATEADD(minute, @Min, 
            DATEADD(hour, @Hour,
            DATEADD(day, @DayOfMonth - 1, 
            DATEADD(month, @Month - 1, 
            DATEADD(Year, @Year-1900, 0))))))

END

GO

вы можете назвать это так...

SELECT dbo.func_DateFromParts(2013, 10, 4, 15, 50, DEFAULT)

возвращает...

2013-10-04 15:50:00.000

попробуйте преобразовать вместо CAST.

CONVERT позволяет третий параметр, указывающий формат даты.

список форматов здесь:http://msdn.microsoft.com/en-us/library/ms187928.aspx

обновление после того, как другой ответ был выбран в качестве "правильного" ответа:

Я действительно не понимаю, почему выбран ответ, который явно зависит от настроек NLS на вашем сервере, без указания этого ограничения.


вы также можете использовать

select DATEFROMPARTS(year, month, day) as ColDate, Col2, Col3 
From MyTable Where DATEFROMPARTS(year, month, day) Between @DateIni and @DateEnd

работает в SQL с ver.2012 и AzureSQL


безопаснее и аккуратнее использовать явную отправную точку '19000101'

create function dbo.fnDateTime2FromParts(@Year int, @Month int, @Day int, @Hour int, @Minute int, @Second int, @Nanosecond int)
returns datetime2
as
begin
    -- Note! SQL Server 2012 includes datetime2fromparts() function
    declare @output datetime2 = '19000101'
    set @output = dateadd(year      , @Year - 1900  , @output)
    set @output = dateadd(month     , @Month - 1    , @output)
    set @output = dateadd(day       , @Day - 1      , @output)
    set @output = dateadd(hour      , @Hour         , @output)
    set @output = dateadd(minute    , @Minute       , @output)
    set @output = dateadd(second    , @Second       , @output)
    set @output = dateadd(ns        , @Nanosecond   , @output)
    return @output
end

Если вы не хотите держать строки из него, это также работает (поместите его в функцию):

DECLARE @Day int, @Month int, @Year int
SELECT @Day = 1, @Month = 2, @Year = 2008

SELECT DateAdd(dd, @Day-1, DateAdd(mm, @Month -1, DateAdd(yy, @Year - 2000, '20000101')))

Я добавляю однострочное решение, если вам нужно datetime от обеих частей даты и времени:

select dateadd(month, (@Year -1900)*12 + @Month -1, @DayOfMonth -1) + dateadd(ss, @Hour*3600 + @Minute*60 + @Second, 0) + dateadd(ms, @Millisecond, 0)

попробовать

CAST(STR(DATEPART(year, DATE))+'-'+ STR(DATEPART(month, DATE)) +'-'+ STR(DATEPART(day, DATE)) AS DATETIME)

для версий SQL Server ниже 12 я могу рекомендовать использование CAST в сочетании с SET DATEFORMAT

-- 26 February 2015
SET DATEFORMAT dmy
SELECT CAST('26-2-2015' AS DATE)

SET DATEFORMAT ymd
SELECT CAST('2015-2-26' AS DATE)

как вы создаете эти строки до вас


попробуйте выполнить этот запрос:

    SELECT SUBSTRING(CONVERT(VARCHAR,JOINGDATE,103),7,4)AS
    YEAR,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),1,2)AS
MONTH,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),4,3)AS DATE FROM EMPLOYEE1

результат:

2014    Ja    1
2015    Ja    1
2014    Ja    1
2015    Ja    1
2012    Ja    1
2010    Ja    1
2015    Ja    1

Я лично предпочитаю подстроку, поскольку она обеспечивает параметры очистки и возможность разбить строку по мере необходимости. Предполагается, что данные имеют формат "dd, mm, yyyy".

--2012 and above
SELECT CONCAT (
        RIGHT(REPLACE(@date, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1)),2)
        )

--2008 and below
SELECT   RIGHT(REPLACE(@date, ' ', ''), 4)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5),2)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1),2)

вот демонстрация того, как можно подать в суд, если данные хранятся в столбце. Излишне говорить, что его идеально проверить результирующий набор перед применением к столбцу

DECLARE @Table TABLE (ID INT IDENTITY(1000,1), DateString VARCHAR(50), DateColumn DATE)

INSERT INTO @Table
SELECT'12, 1, 2007',NULL
UNION
SELECT'15,3, 2007',NULL
UNION
SELECT'18, 11 , 2007',NULL
UNION
SELECT'22 , 11, 2007',NULL
UNION
SELECT'30, 12, 2007  ',NULL

UPDATE @Table
SET DateColumn = CONCAT (
        RIGHT(REPLACE(DateString, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), CHARINDEX(',', REPLACE(DateString, ' ', '')) + 1, LEN(REPLACE(DateString, ' ', '')) - CHARINDEX(',', REPLACE(DateString, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), 1, CHARINDEX(',', REPLACE(DateString, ' ', '')) - 1)),2)
        ) 

SELECT ID,DateString,DateColumn
FROM @Table