convert Excel Date Serial Number to Regular Date

2019-01-06 18:09发布

问题:

I got a column called DateOfBirth in my csv file with Excel Date Serial Number Date

Example:

      36464
      37104
      35412

When i formatted cells in excel these are converted as

      36464 => 1/11/1999
      37104 => 1/08/2001
      35412 => 13/12/1996

I need to do this transformation in SSIS or in SQL. How can this be achieved?

回答1:

In SQL:

select dateadd(d,36464,'1899-12-30')
-- or thanks to rcdmk
select CAST(36464 - 2 as SmallDateTime)

In SSIS, see here

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



回答2:

The marked answer is not working fine, please change the date to "1899-12-30" instead of "1899-12-31".

select dateadd(d,36464,'1899-12-30')


回答3:

You can cast it to a SQL smalldatetime:

cast(41869 - 2 as smalldatetime)

SQL Server counts its dates from 01/01/1900 and Excel from 12/30/1899 = 2 days less.



回答4:

this actually worked for me

dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-30') 

(minus 1 more day in the date)

referring to the negative commented post



回答5:

Found this topic helpful so much so created a quick SQL UDF for it.

CREATE FUNCTION dbo.ConvertExcelSerialDateToSQL
(
    @serial INT
)
RETURNS DATETIME
AS
BEGIN
    DECLARE @dt AS DATETIME
    SELECT @dt = 
        CASE
            WHEN @serial is not null THEN CAST(@serial - 2 AS DATETIME)
            ELSE NULL
        END
    RETURN @dt              
END
GO


回答6:

SSIS Solution

"The DT_DATE data type is implemented using an 8-byte floating-point number. Days are represented by whole number increments, starting with 30 December 1899, and midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number. However, a floating point value cannot represent all real values; therefore, there are limits on the range of dates that can be presented in DT_DATE." Read more

From the description above you can see that you can convert these values implicitly when mapping them to a DT_DATE Column after converting it to a 8-byte floating-point number DT_R8.

Use a derived column transformation to convert this column to 8-byte floating-point number:

(DT_R8)[dateColumn]

Then map it to a DT_DATE column

Or cast it twice:

(DT_DATE)(DT_R8)[dateColumn]

You can check my full answer here:

  • Is there a better way to parse [Integer].[Integer] style dates in SSIS?


回答7:

In addition of @Nick.McDermaid answer I would like to post this solution, which convert not only the day but also the hours, minutes and seconds:

SELECT DATEADD(s, (42948.123 - FLOOR(42948.123))*3600*24, dateadd(d, FLOOR(42948.123),'1899-12-30'))

For example

  • 42948.123 to 2017-08-01 02:57:07.000
  • 42818.7166666667 to 2017-03-24 17:12:00.000


回答8:

You can do this if you just need to display the date in a view:

CAST will be faster than CONVERT if you have a large amount of data, also remember to subtract (2) from the excel date:

CAST(CAST(CAST([Column_With_Date]-2 AS INT)AS smalldatetime) AS DATE)

If you need to update the column to show a date you can either update through a join (self join if necessary) or simply try the following:

You may not need to cast the excel date as INT but since the table I was working with was a varchar I had to do that manipulation first. I also did not want the "time" element so I needed to remove that element with the final cast as "date."

UPDATE [Table_with_Date]
SET [Column_With_Excel_Date] = CAST(CAST(CAST([Column_With_Excel_Date]-2 AS INT)AS smalldatetime) AS DATE)

If you are unsure of what you would like to do with this test and re-test! Make a copy of your table if you need. You can always create a view!



回答9:

I had to take this to the next level because my Excel dates also had times, so I had values like this:

42039.46406 --> 02/04/2015 11:08 AM
42002.37709 --> 12/29/2014 09:03 AM
42032.61869 --> 01/28/2015 02:50 PM

(also, to complicate it a little more, my numeric value with decimal was saved as an NVARCHAR)

The SQL I used to make this conversion is:

SELECT DATEADD(SECOND, (
                        CONVERT(FLOAT, t.ColumnName) - 
                        FLOOR(CONVERT(FLOAT, t.ColumnName))
                       ) * 86400,
               DATEADD(DAY, CONVERT(FLOAT, t.ColumnName), '1899-12-30')
              )


回答10:

Google BigQuery solution

Standard SQL

Select Date, DATETIME_ADD(DATETIME(xy, xm, xd, 0, 0, 0),  INTERVAL xonlyseconds SECOND) xaxsa
from (
  Select Date, EXTRACT(YEAR FROM xonlydate) xy, EXTRACT(MONTH FROM xonlydate) xm, EXTRACT(DAY FROM xonlydate) xd, xonlyseconds
  From (
     Select Date
        , DATE_ADD(DATE '1899-12-30', INTERVAL cast(FLOOR(cast(Date as FLOAT64)) as INT64) DAY )   xonlydate
        , cast(FLOOR( ( cast(Date as FLOAT64) - cast(FLOOR( cast(Date as FLOAT64)) as INT64)  ) * 86400 ) as INT64) xonlyseconds
     FROM (Select '43168.682974537034' Date) -- 09.03.2018  16:23:28
   ) xx1
 )


回答11:

Try the approach discussed in the following link, which involves creating a function that performs the converstion and applying the function in your SQL.

http://www.ehow.com/how_12073756_convert-julian-date-sql.html



回答12:

This worked for me because sometimes the field was a numeric to get the time portion.

Command:

 dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-31')