【问题标题】:convert Excel Date Serial Number to Regular Date将 Excel 日期序列号转换为常规日期
【发布时间】:2012-11-30 19:08:13
【问题描述】:

我的 csv 文件中有一个名为 DateOfBirth 的列,其中包含 Excel 日期序列号日期

例子:

  36464
  37104
  35412

当我在 excel 中格式化单元格时,这些单元格被转换为

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

我需要在 SSIS 或 SQL 中进行此转换。如何实现?

【问题讨论】:

  • 顺便说一下,那些不是朱利安日期,它们是 Excel 日期序列号。 35464 是 BCE 4614 年 11 月 1 日 12:00:00.0 UT 星期二在儒略日期和 CE 1958 年 9 月 18 日 00:00:00.0 UT 星期四在修改儒略日期。有关 Julian Dates 的说明,请参见此处:aa.usno.navy.mil/data/docs/JulianDate.php

标签: sql sql-server tsql ssis etl


【解决方案1】:

在 SQL 中:

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

在 SSIS 中,请参见此处

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

【讨论】:

    【解决方案2】:

    标记的答案不能正常工作,请将日期更改为“1899-12-30”而不是“1899-12-31”。

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

    【讨论】:

      【解决方案3】:

      您可以将其转换为 SQL SMALLDATETIME:

      CAST(36464 - 2 as SMALLDATETIME)
      

      MS SQL Server 从 01/01/1900 开始计算日期,而 Excel 从 12/30/1899 开始计算日期 = 少了 2 天。

      【讨论】:

      • 仅供参考:少 2 天的问题比您的错误评估有趣得多。盖茨先生本人批准了这个奇怪的日期。请参阅这两个资源:MS SupportThe real Story 是的,Stack Overflow 的创建者确实在整个过程中发挥了巨大的作用。
      • 我认为这个答案更简洁一些,上面的评论提供了 Joel 博客文章的链接,真是太棒了!
      【解决方案4】:

      这实际上对我有用

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

      (在日期中再减去 1 天)

      指的是负面评论的帖子

      【讨论】:

      【解决方案5】:

      tldr:

      select cast(@Input - 2e as datetime)
      

      说明:

      Excel stores datetimes as a floating point number 表示自 20 世纪初以来经过的时间,SQL Server 可以以相同的方式轻松地在 floats 和日期时间之间转换。 Excel 和 SQL Server 将此数字转换为日期时间的时间差为 2 天 (as of 1900-03-01, that is)。使用 2e 的文字来表示这种差异会通知 SQL Server 将其他数据类型隐式转换为浮点数,以实现对输入非常友好且简单的查询:

      select
          cast('43861.875433912' - 2e as datetime) as ExcelToSql, -- even varchar works!
          cast(cast('2020-01-31 21:00:37.490' as datetime) + 2e as float) as SqlToExcel
      
      -- Results:
      -- ExcelToSql                          SqlToExcel
      -- 2020-01-31 21:00:37.490        43861.875433912
      

      【讨论】:

        【解决方案6】:

        发现这个主题非常有用,因此为它创建了一个快速 SQL UDF。

        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
        

        【讨论】:

        • 我使用了类似的东西,但我发现作为浮点数的输入参数要通用得多。
        【解决方案7】:

        我不得不把它提升到一个新的水平,因为我的 Excel 日期也有时间,所以我有这样的值:

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

        (另外,为了更复杂一点,我的十进制数值被保存为 NVARCHAR)

        我用来进行这种转换的 SQL 是:

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

        【讨论】:

          【解决方案8】:

          SSIS 解决方案

          DT_DATE 数据类型是使用 8 字节浮点数实现的。天数由整数增量表示,从 1899 年 12 月 30 日开始,午夜作为时间零。小时值表示为数字小数部分的绝对值。但是,一个浮点值不能代表所有的实数值;因此,可以在 DT_DATE 中显示的日期范围存在限制。 Read more

          从上面的描述你可以看到你可以在将这些值转换为8字节浮点数DT_R8后,将它们映射到DT_DATE列时隐式转换。

          使用派生列转换将此列转换为 8 字节浮点数:

          (DT_R8)[dateColumn]
          

          然后将其映射到DT_DATE

          或者施放两次:

          (DT_DATE)(DT_R8)[dateColumn]
          

          你可以在这里查看我的完整答案:

          【讨论】:

            【解决方案9】:

            除了@Nick.McDermaid 的回答,我想发布这个解决方案,它不仅可以转换日期,还可以转换小时、分钟和秒:

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

            例如

            • 42948.1232017-08-01 02:57:07.000
            • 42818.71666666672017-03-24 17:12:00.000

            【讨论】:

              【解决方案10】:

              如果您只需要在视图中显示日期,您可以这样做:

              如果数据量很大,CAST会比CONVERT快,还记得把excel日期减去(2):

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

              如果您需要更新列以显示日期,您可以通过联接(必要时自行联接)进行更新,或者简单地尝试以下操作:

              您可能不需要将 excel 日期转换为 INT,但由于我使用的表是 varchar,因此我必须先进行该操作。我也不想要“时间”元素,所以我需要删除该元素,最终将其转换为“日期”。

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

              如果您不确定要对此测试做什么,请重新测试!如果需要,请复制您的表格。您可以随时创建视图!

              【讨论】:

                【解决方案11】:

                Google BigQuery 解决方案

                标准 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
                 )
                

                【讨论】:

                • 对于登陆这里并为 BigQuery 寻找更简短解决方案的人,请尝试 SELECT DATETIME_ADD("1899-12-30",INTERVAL CAST(43909.91492 * 86400 AS INT64) SECOND)(另外,上面的答案似乎落后一秒钟;Excel 和我的代码都将该序列放在 @ 987654323@)
                【解决方案12】:

                在 postgresql 中,可以使用以下语法:

                SELECT ((DATE('1899-12-30') + INTERVAL '1 day' * FLOOR(38242.7711805556)) + (INTERVAL '1 sec' * (38242.7711805556 - FLOOR(38242.7711805556)) * 3600 * 24)) as date
                

                在本例中,38242.7711805556 以 excel 格式表示 2004-09-12 18:30:30

                【讨论】:

                  【解决方案13】:

                  对于那些希望在 excel 中执行此操作的人(除了格式化为日期字段),您可以使用文本函数 https://exceljet.net/excel-functions/excel-text-function 来执行此操作

                  A1 = 132134
                  =Text(A1,"MM-DD-YYYY") will result in a date
                  

                  【讨论】:

                    【解决方案14】:

                    这对我有用,因为有时该字段是用于获取时间部分的数字。

                    命令:

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2013-04-20
                      • 1970-01-01
                      • 2021-01-05
                      • 2020-07-04
                      • 2011-03-02
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多