将 Excel 日期序列号转换为常规日期

问题描述 投票:0回答:15

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

示例:

  36464
  37104
  35412

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

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

我需要在 SSIS 或 SQL 中进行此转换。 如何才能实现这一目标?

sql sql-server t-sql ssis etl
15个回答
56
投票

在 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


18
投票

您可以将其转换为 SQL

SMALLDATETIME
:

CAST(36464 - 2 as SMALLDATETIME)

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


16
投票

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

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

9
投票

tldr:

select cast(@Input - 2e as datetime)

说明:

Excel 将日期时间存储为浮点数,表示自 20 世纪初以来经过的时间,SQL Server 可以以相同的方式轻松在 floats 和日期时间之间进行转换。 Excel 和 SQL Server 将此数字转换为日期时间之间的差异为 2 天(截至 1900 年 3 月 1 日,即)。使用文字

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
投票

这实际上对我有用

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

(日期中减去 1 天)

参考负面评论帖子


2
投票

SSIS解决方案

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

从上面的描述中您可以看到,在将这些值转换为 8 字节浮点数

DT_DATE
后,将它们映射到
DT_R8
列时,您可以隐式转换这些值。

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

(DT_R8)[dateColumn]

然后将其映射到

DT_DATE

或者施放两次:

(DT_DATE)(DT_R8)[dateColumn]

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


1
投票

发现这个主题非常有帮助,因此为其创建了一个快速 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

1
投票

我必须将其提升到一个新的水平,因为我的 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')
              )

1
投票

在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


0
投票

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

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

例如

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

0
投票

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

如果你的数据量很大,

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)

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


0
投票

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
 )

0
投票

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

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

0
投票

...老问题,但是这是我们在 SQL Server 中用于中等容量的函数(标量函数) - 如果您需要高性能,请不要使用函数(可以通过一些技巧将其编码为单行)但是为了清晰起见,对于少于 1,000,000 行的导入等,这是非常明显的。

如果需要,您还可以将返回类型更改为其他基于日期的类型。

CREATE FUNCTION dbo.FromExcelDateNum(
  -- Excel date number value
  @ExcelDateNum int
)
RETURNS DATETIME
AS
BEGIN
  RETURN CASE
    -- NULL -> NULL
    WHEN @ExcelDateNum IS NULL THEN NULL
    -- LESS THAN OR EQUAL TO 0 -> NULL
    WHEN @ExcelDateNum <= 0 THEN NULL
    -- Up to 1900-02-28
    WHEN @ExcelDateNum < 60 THEN DATEADD(DAY, @ExcelDateNum, '1899-12-31')
    -- Special case - a very old bug that Excel thinks
    -- 1900-02-29 is a real date but it's not:
    -- 1900 was not a leap year - leap years are all
    -- years divisible by 4 but not divisible by 100 unless
    -- also divisible by 1000, so:
    -- 2003 - no (not divisible by 4)
    -- 1984 - yes (divisible by 4)
    -- 1900 - no (divisible by 100 but not by 1000)
    -- 2000 - yes (divisible by 1000)
    WHEN @ExcelDateNum = 60 THEN NULL
    -- 1900-03-01 and later - offset from 1899-12-30 to compensate
    -- for Excel value being +1 too high due to including 1900-02-29
    ELSE DATEADD(DAY, @ExcelDateNum, '1899-12-30')
  END
END

-3
投票

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

命令:

 dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-31') 
© www.soinside.com 2019 - 2024. All rights reserved.