Converting Hour and Minute to Decimal

  • Quick solution, returns the hour + time fraction (minutes and seconds / 3600)

    😎

    USE tempdb;

    GO

    DECLARE @DATE_VAL DATETIME = '2014-07-29 08:16:31.000'

    SELECT @DATE_VAL

    SELECT DATEPART(HOUR,@DATE_VAL) + (DATEDIFF(SECOND,'00:00:00.000',DATEADD(HOUR, - DATEPART(HOUR, CONVERT(time(3),@DATE_VAL)),CONVERT(time(3),@DATE_VAL))) / 3600.0)

    Result

    8.275277

    Edit: Oops, feel a little silly here, didn't see the answers:-P

  • Sean Lange (7/31/2014)


    Sql server stores datetime as decimal. You can easily cast a datetime to decimal. But what is the point? What are you trying to do with it?

    I use to think that until I saw a proof and tried it all myself.

    If you look at the DATETIME data type in 2005 BOL, it states...

    Values with the datetime data type are stored internally by the Microsoft SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900. The base date is the system reference date. The other 4 bytes store the time of day represented as the number of milliseconds after midnight.

    The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.

    Here's a good link that demonstrates... http://blogs.lessthandot.com/index.php/datamgmt/datadesign/how-are-dates-stored-in-sql-server/

    The bad part is that, as of 2008, they no longer tell you how the date/time is stored.

    Shifting gears a bit, I love DATETIME instead of DATETIME2. You can convert DATETIME into a DECIMAL or FLOAT number, etc, as expected and, as you stated, the number to the left of the decimal place is the number of whole days since the first of January 1900 and every thing to the right of the decimal is fractional days which can easily be manipulated as time. You cannot do such conversions with the "new" DATETIME2 data type, which is really disappointing.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden (8/2/2014)


    Sean Lange (7/31/2014)


    Sql server stores datetime as decimal. You can easily cast a datetime to decimal. But what is the point? What are you trying to do with it?

    I use to think that until I saw a proof and tried it all myself.

    If you look at the DATETIME data type in 2005 BOL, it states...

    Values with the datetime data type are stored internally by the Microsoft SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900. The base date is the system reference date. The other 4 bytes store the time of day represented as the number of milliseconds after midnight.

    The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.

    Here's a good link that demonstrates... http://blogs.lessthandot.com/index.php/datamgmt/datadesign/how-are-dates-stored-in-sql-server/

    The bad part is that, as of 2008, they no longer tell you how the date/time is stored.

    Shifting gears a bit, I love DATETIME instead of DATETIME2. You can convert DATETIME into a DECIMAL or FLOAT number, etc, as expected and, as you stated, the number to the left of the decimal place is the number of whole days since the first of January 1900 and every thing to the right of the decimal is fractional days which can easily be manipulated as time. You cannot do such conversions with the "new" DATETIME2 data type, which is really disappointing.

    Doesn't look like the format has changed, look at this query

    DECLARE @DT2_0 DATETIME2(0) = '1900-01-01 00:00:00'

    DECLARE @DT2_1 DATETIME2(1) = '1900-01-01 00:00:00.1'

    DECLARE @DT2_7 DATETIME2(7) = '1900-01-01 00:00:00.0000001'

    DECLARE @dt DATETIME = '1900-01-01 00:00:00.003'

    SELECT CONVERT(VARBINARY(12),@DT2_0,0) UNION ALL

    SELECT CONVERT(VARBINARY(12),@DT2_1,0) UNION ALL

    SELECT CONVERT(VARBINARY(12),@DT2_7,0) UNION ALL

    SELECT CONVERT(VARBINARY(12),@DT,0)

    Results

    0x000000005B950A

    0x010100005B950A

    0x0701000000005B950A

    0x0000000000000001

    The datetime2 format is first byte is precision, last two are the number of days since year 1 and the middle holds the number of time units since midnight depending on the precision. Mind you, one has to reverse the bytes as it is small endian 😉

    The datetime format is still the same upto and including 2014.

    😎

  • Here's what I'd use to solve this problem on my systems because it's short and accurate with the accuracy limits of DATETIME. No... it's not ANSI/ISO compliant and no... it won't work with DATETIME2() data types. Of course, if you know me, you'll know that I don't believe in either when it comes to T-SQL, especially when it comes to performance. 😛

    DECLARE @UPH datetime = '2014-07-29 08:16:31.000';

    SELECT CAST(@UPH AS DECIMAL(17,12))%1*24;

    1. The DATETIME is converted to decimal.

    2. That is played against Modulus(1) (%1) to return only the fractional part (the REMAINDER from the MODULUS) of the decimal value, which is TIME represented as a fractional day.

    3. That is multiplied by 24 hours because there are 24 hours in 1 day, and we're done.

    It's a real shame that you can't convert the DATETIME2() directly to decimal to make such problems so easy.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden (8/2/2014)


    Here's what I'd use to solve this problem on my systems because it's short and accurate with the accuracy limits of DATETIME. No... it's not ANSI/ISO compliant and no... it won't work with DATETIME2() data types. Of course, if you know me, you'll know that I don't believe in either when it comes to T-SQL, especially when it comes to performance. 😛

    DECLARE @UPH datetime = '2014-07-29 08:16:31.000';

    SELECT CAST(@UPH AS DECIMAL(17,12))%1*24;

    The DATETIME is converted to decimal.

    That is play against Modulus(1) (%1) to return only the fractional part of the decimal value, which is TIME represented as a fractional day.

    That is multiplied by 24 hours because there are 24 hours in 1 day, and we're done.

    It's a real shame that you can't convert the DATETIME2() directly to decimal to make such problems so easy.

    Short, sweet (and ansi sour):-P

    😎

  • Ed Wagner (7/31/2014)


    It sounds to me like you're after the number of units picked per hour for a specific period of time. It reminds me of a shop floor productivity report. Is this correct? If so, simply subtract the times and divide the quantity by the difference. This example uses the difference in minutes for precision.

    with times as (

    select dateadd(minute, -90, getdate()) starting_time,

    GETDATE() ending_time,

    14 quantity

    union all

    select dateadd(hour, -2, getdate()) starting_time,

    GETDATE() ending_time,

    160 quantity)

    select starting_time, ending_time, quantity,

    convert(numeric(12, 6), DATEDIFF(minute, starting_time, ending_time)) / 60 hours,

    round(quantity / convert(numeric(12, 6), DATEDIFF(minute, starting_time, ending_time)) * 60, 3) uph

    from times;

    Am I over-simplifying this?

    No. But it can be made a bit simpler still using the hidden power of the DATETIME data type.

    WITH TestData (StartDT,EndDT,Quantity) AS

    (

    SELECT DATEADD(mi,-90,GETDATE()), GETDATE(), 14 UNION ALL

    SELECT DATEADD(hh,- 2,GETDATE()), GETDATE(), 160

    )

    SELECT StartDT

    ,EndDT

    ,Quantity

    ,UPH = CAST(Quantity/(CAST(EndDT-StartDT AS DECIMAL(17,12))%1*24) AS DECIMAL(9,3))

    FROM TestData

    ;

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Eirikur Eiriksson (8/2/2014)


    The datetime format is still the same upto and including 2014.

    😎

    Thanks Eirikur. I've never looked at it but figured it might be so. That does, however, make my disappointment in the DATETIME2 data type even deeper. Except for the precision byte, it's virtually identical to DATETIME... why would they cripple the data type by making direct addition and subtraction impossible?

    What adds to the disappointment is that the DATETIME2 data type, even when scaled back to DATETIME2(3) to produce the same number of digits (but, not the same accuracy) as DATETIME is 49% slower than when the same code is used for DATETIME. Yeah, it takes millions of rows for that to really add up but I have millions of rows that I work with.

    The DATETIME2 solution that requires DATEPART is also 72% slower than DATETIME with the decimal conversion.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • For anyone that would like to do their own testing, here's the test table I've been using for all of this...

    WITH cteRandomDT AS

    (

    SELECT TOP 1000000

    DateTimeDT = RAND(CHECKSUM(NEWID())) * DATEDIFF(dd,'2000','2020') + CAST('2000' AS DATETIME)

    FROM sys.all_columns ac1

    CROSS JOIN sys.all_columns ac2

    )

    SELECT DateTimeDT

    ,DateTime2DT = CAST(DateTimeDT AS DATETIME2(3))

    INTO #JBMTest

    FROM cteRandomDT

    ;

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Jeff Moden (8/2/2014)


    Eirikur Eiriksson (8/2/2014)


    The datetime format is still the same upto and including 2014.

    😎

    Thanks Eirikur. I've never looked at it but figured it might be so. That does, however, make my disappointment in the DATETIME2 data type even deeper. Except for the precision byte, it's virtually identical to DATETIME... why would they cripple the data type by making direct addition and subtraction impossible?

    What adds to the disappointment is that the DATETIME2 data type, even when scaled back to DATETIME2(3) to produce the same number of digits (but, not the same accuracy) as DATETIME is 49% slower than when the same code is used for DATETIME. Yeah, it takes millions of rows for that to really add up but I have millions of rows that I work with.

    The DATETIME2 solution that requires DATEPART is also 72% slower than DATETIME with the decimal conversion.

    I agree, as anything that sounds too good to be true, datetime2 isn't. Although it saves 3 bytes and it's ansi/ iso compliant, honestly, no improvement over smalldatetime though, same number of bytes and realistically, unless one is doing far fetched statistics, the range of smalldatetime is more than enough.

    😎

  • Eirikur Eiriksson - Saturday, August 2, 2014 12:38 PM

    Jeff Moden (8/2/2014)


    Sean Lange (7/31/2014)


    Sql server stores datetime as decimal. You can easily cast a datetime to decimal. But what is the point? What are you trying to do with it?

    I use to think that until I saw a proof and tried it all myself. If you look at the DATETIME data type in 2005 BOL, it states...

    Values with the datetime data type are stored internally by the Microsoft SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900. The base date is the system reference date. The other 4 bytes store the time of day represented as the number of milliseconds after midnight. The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.

    Here's a good link that demonstrates... http://blogs.lessthandot.com/index.php/datamgmt/datadesign/how-are-dates-stored-in-sql-server/ The bad part is that, as of 2008, they no longer tell you how the date/time is stored. Shifting gears a bit, I love DATETIME instead of DATETIME2. You can convert DATETIME into a DECIMAL or FLOAT number, etc, as expected and, as you stated, the number to the left of the decimal place is the number of whole days since the first of January 1900 and every thing to the right of the decimal is fractional days which can easily be manipulated as time. You cannot do such conversions with the "new" DATETIME2 data type, which is really disappointing.

    Doesn't look like the format has changed, look at this query DECLARE @DT2_0 DATETIME2(0) = '1900-01-01 00:00:00' DECLARE @DT2_1 DATETIME2(1) = '1900-01-01 00:00:00.1' DECLARE @DT2_7 DATETIME2(7) = '1900-01-01 00:00:00.0000001' DECLARE @dt DATETIME = '1900-01-01 00:00:00.003' SELECT CONVERT(VARBINARY(12),@DT2_0,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_1,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_7,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT,0) Results 0x000000005B950A 0x010100005B950A 0x0701000000005B950A 0x0000000000000001 The datetime2 format is first byte is precision, last two are the number of days since year 1 and the middle holds the number of time units since midnight depending on the precision. Mind you, one has to reverse the bytes as it is small endian 😉 The datetime format is still the same upto and including 2014. 😎

    How to convert VarBinary to DateTime2

  • ravikaliappan - Wednesday, August 9, 2017 3:37 AM

    Eirikur Eiriksson - Saturday, August 2, 2014 12:38 PM

    Jeff Moden (8/2/2014)


    Sean Lange (7/31/2014)


    Sql server stores datetime as decimal. You can easily cast a datetime to decimal. But what is the point? What are you trying to do with it?

    I use to think that until I saw a proof and tried it all myself. If you look at the DATETIME data type in 2005 BOL, it states...

    Values with the datetime data type are stored internally by the Microsoft SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900. The base date is the system reference date. The other 4 bytes store the time of day represented as the number of milliseconds after midnight. The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.

    Here's a good link that demonstrates... http://blogs.lessthandot.com/index.php/datamgmt/datadesign/how-are-dates-stored-in-sql-server/ The bad part is that, as of 2008, they no longer tell you how the date/time is stored. Shifting gears a bit, I love DATETIME instead of DATETIME2. You can convert DATETIME into a DECIMAL or FLOAT number, etc, as expected and, as you stated, the number to the left of the decimal place is the number of whole days since the first of January 1900 and every thing to the right of the decimal is fractional days which can easily be manipulated as time. You cannot do such conversions with the "new" DATETIME2 data type, which is really disappointing.

    Doesn't look like the format has changed, look at this query DECLARE @DT2_0 DATETIME2(0) = '1900-01-01 00:00:00' DECLARE @DT2_1 DATETIME2(1) = '1900-01-01 00:00:00.1' DECLARE @DT2_7 DATETIME2(7) = '1900-01-01 00:00:00.0000001' DECLARE @dt DATETIME = '1900-01-01 00:00:00.003' SELECT CONVERT(VARBINARY(12),@DT2_0,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_1,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_7,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT,0) Results 0x000000005B950A 0x010100005B950A 0x0701000000005B950A 0x0000000000000001 The datetime2 format is first byte is precision, last two are the number of days since year 1 and the middle holds the number of time units since midnight depending on the precision. Mind you, one has to reverse the bytes as it is small endian 😉 The datetime format is still the same upto and including 2014. 😎

    How to convert VarBinary to DateTime2

    How to conver varbinary to date with time?

  • ravikaliappan - Wednesday, August 9, 2017 3:45 AM

    ravikaliappan - Wednesday, August 9, 2017 3:37 AM

    Eirikur Eiriksson - Saturday, August 2, 2014 12:38 PM

    Jeff Moden (8/2/2014)


    Sean Lange (7/31/2014)


    Sql server stores datetime as decimal. You can easily cast a datetime to decimal. But what is the point? What are you trying to do with it?

    I use to think that until I saw a proof and tried it all myself. If you look at the DATETIME data type in 2005 BOL, it states...

    Values with the datetime data type are stored internally by the Microsoft SQL Server 2005 Database Engine as two 4-byte integers. The first 4 bytes store the number of days before or after the base date: January 1, 1900. The base date is the system reference date. The other 4 bytes store the time of day represented as the number of milliseconds after midnight. The smalldatetime data type stores dates and times of day with less precision than datetime. The Database Engine stores smalldatetime values as two 2-byte integers. The first 2 bytes store the number of days after January 1, 1900. The other 2 bytes store the number of minutes since midnight.

    Here's a good link that demonstrates... http://blogs.lessthandot.com/index.php/datamgmt/datadesign/how-are-dates-stored-in-sql-server/ The bad part is that, as of 2008, they no longer tell you how the date/time is stored. Shifting gears a bit, I love DATETIME instead of DATETIME2. You can convert DATETIME into a DECIMAL or FLOAT number, etc, as expected and, as you stated, the number to the left of the decimal place is the number of whole days since the first of January 1900 and every thing to the right of the decimal is fractional days which can easily be manipulated as time. You cannot do such conversions with the "new" DATETIME2 data type, which is really disappointing.

    Doesn't look like the format has changed, look at this query DECLARE @DT2_0 DATETIME2(0) = '1900-01-01 00:00:00' DECLARE @DT2_1 DATETIME2(1) = '1900-01-01 00:00:00.1' DECLARE @DT2_7 DATETIME2(7) = '1900-01-01 00:00:00.0000001' DECLARE @dt DATETIME = '1900-01-01 00:00:00.003' SELECT CONVERT(VARBINARY(12),@DT2_0,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_1,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT2_7,0) UNION ALL SELECT CONVERT(VARBINARY(12),@DT,0) Results 0x000000005B950A 0x010100005B950A 0x0701000000005B950A 0x0000000000000001 The datetime2 format is first byte is precision, last two are the number of days since year 1 and the middle holds the number of time units since midnight depending on the precision. Mind you, one has to reverse the bytes as it is small endian 😉 The datetime format is still the same upto and including 2014. 😎

    How to convert VarBinary to DateTime2

    How to conver varbinary to date with time?

    I tried this it doesn't work

    SELECT CONVERT(datetime, 0x17041D49FCC2D488)
    SELECT CONVERT(datetime2, 0x17041D49FCC2D488)

  • ravikaliappan - Wednesday, August 9, 2017 3:47 AM

    I tried this it doesn't work

    SELECT CONVERT(datetime, 0x17041D49FCC2D488)
    SELECT CONVERT(datetime2, 0x17041D49FCC2D488)

    First, you should start your own thread instead of reopening an old thread.  This one is three years old.

    Second, saying that something doesn't work isn't helpful.  Does fail?  If so, what is the error message?  Does it produce results, but the results are incorrect?  How exactly doesn't it work?

    Finally, you need to give expected results.  It also might help if you indicated where the binary data is coming from.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • drew.allen - Wednesday, August 9, 2017 7:54 AM

    ravikaliappan - Wednesday, August 9, 2017 3:47 AM

    I tried this it doesn't work

    SELECT CONVERT(datetime, 0x17041D49FCC2D488)
    SELECT CONVERT(datetime2, 0x17041D49FCC2D488)

    First, you should start your own thread instead of reopening an old thread.  This one is three years old.

    Second, saying that something doesn't work isn't helpful.  Does fail?  If so, what is the error message?  Does it produce results, but the results are incorrect?  How exactly doesn't it work?

    Finally, you need to give expected results.  It also might help if you indicated where the binary data is coming from.

    Drew

    He has a thread in here: https://www.sqlservercentral.com/Forums/1890993/RE-How-to-convert-varbinary-to-date
    Not much information, though.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • drew.allen - Wednesday, August 9, 2017 7:54 AM

    First, you should start your own thread instead of reopening an old thread.  This one is three years old.

    Second, saying that something doesn't work isn't helpful.  Does fail?  If so, what is the error message?  Does it produce results, but the results are incorrect?  How exactly doesn't it work?

    Finally, you need to give expected results.  It also might help if you indicated where the binary data is coming from.

    Drew

    They did, also, start their own thread here: https://www.sqlservercentral.com/Forums/1890993/How-to-convert-varbinary-to-date

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

Viewing 15 posts - 16 through 29 (of 29 total)

You must be logged in to reply to this topic. Login to reply