根据日期,时间和子午线字段构建时间戳

时间:2015-10-23 18:36:22

标签: sql-server datetime

我有一个遗留系统,它使用四个离散字段来捕获日期时间:一个用于日期(例如2015年10月23日),一个用于小时(例如10),一个用于分钟(例如,45) ),一个用于子午线(A或P)。

我正在尝试在MSSQL 2008 R2中构建一个标量函数,该函数将上面的所有字段作为参数,并返回使用所有提供的值创建的日期时间值。

这就是我到目前为止:

CREATE FUNCTION f_getTimeStamp (@date Date, @hour Varchar, @minute Varchar, @meridian Varchar)
    RETURNS Datetime
    AS
    BEGIN
        DECLARE @createdDateTime datetime
        DECLARE @createdTime varchar

        SELECT @createdTime = @hour + ':' + @minute +
            CASE
                WHEN @meridian = 'A' Then 'am'
                WHEN @meridian = 'P' Then 'pm'
                Else 'pm'
            END

        SET @createdDateTime = @date + CAST(@createdTime AS DATETIME)

        RETURN @createdDateTime
    END

我们的想法是获取创建时间所需的字段,并将它们组合成一个看起来像时间值的字符串,然后将其添加到现有的日期字段中。

我目前在查询中收到以下错误:

  

从字符串转换日期和/或时间时转换失败。

我应该注意,在使用此函数的查询中,我只发送非空值。

非常感谢任何帮助。

感谢。

3 个答案:

答案 0 :(得分:1)

您的代码中只有一个点正在尝试从字符串转换日期/时间:

CAST(@createdTime AS DATETIME)

某些地方的值不会产生可转换的字符串。

您可以在ISDATE()子句中使用时间构建逻辑和WHERE找到有问题的值:

SELECT *
FROM YourTable
WHERE ISDATE(CAST(Hour AS VARCHAR(10)+':'+CAST(Minute AS VARCHAR(10)) = 0

'2:4am'之类的内容会在没有问题的情况下投放到日期时间,因此您的格式本身并不存在问题。

解决此问题后,您应该遇到有关不兼容数据类型的其他错误,因为您无法添加DATEDATETIME,因此您需要更改:< / p>

SET @createdDateTime = @date + CAST(@createdTime AS DATETIME)

要:

SET @createdDateTime = CAST(@date AS DATETIME) + CAST(@createdTime AS DATETIME)

答案 1 :(得分:0)

那里正在进行大量的类型转换。此表达式@date + CAST(@createdTime AS DATETIME)很可能是给您错误的行。输出可能是`2012-01-01 00:00:002012-01-01 10:45:00&#39;

更好的方法是简单地将时间添加到原始日期。请注意,我更改了函数中的数据类型,以使类型转换不会发生在函数中。

CREATE FUNCTION f_getTimeStamp (@date Date, @hour INT, @minute INT, @meridian CHAR(1))
RETURNS Datetime
AS
BEGIN
    DECLARE @TEMP DATETIME
    SET @TEMP = @date
    IF @hour < 12
        SET @TEMP = DATEADD(HOUR, @date, @hour)
    SET @TEMP = DATEADD(MINUTE, @date, @minute)

    IF @meridian = 'P' AND @hour < 13 -- the hour must already be PM
        SET @TEMP = DATEADD(HOUR, @date, 12)

    RETURN @TEMP
END

注意:我没有在SQL Server中测试过这个。我可能在那里有一两个错字。但是,这个概念应该是合理的。

答案 2 :(得分:0)

我带来了这个解决方案。我认为使用DATEADDDATEPART这样的内置函数可以解决这个问题。那是我用过的剧本:

<强> DATEADD:

  

返回具有指定数字间隔的指定日期(已签名)   整数)添加到该日期的指定日期部分。

<强> DATEPART:

  

返回一个表示指定datepart的整数   指定日期。

实际查询:

DECLARE @date DATETIME = '10/23/2015'
  , @hour VARCHAR(20) = 10
  , @minute VARCHAR(20) = 45
  , @meridian VARCHAR(20) = 'P'
  , @time DATETIME;

SELECT @time = @hour + ':' + @minute + CASE @meridian
    WHEN 'A' THEN 'AM'
    WHEN 'P' THEN 'PM'
    ELSE 'PM'
  END


SELECT DATEADD(MINUTE, DATEPART(MINUTE, @time), DATEADD(HOUR, DATEPART(HOUR, @time), @date));

我在Stack Exchange Data Explorer上构建了一个查询。它为我的场景带来了这个结果:

2015-10-23 22:45:00

它做什么?

  1. 它会创建一个时间字符串,然后将其转换为日期时间
  2. 然后使用DATEPART从创建的字符串中提取分钟和小时(已经处理子午线)并使用DATEADD将值添加到给定日期
  3. P.S。始终为您的VARCHAR声明长度。

      

    如果您没有定义长度,SQL Server将为您分配一个,和   它可能没有你想象的那么宽。在某些情况下,它将是1.

    来源:Bad habits to kick : declaring VARCHAR without (length)