You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSIS中AD部分日期时间属性显示为System.__ComObject的解决咨询

解决SSIS中AD日期属性转换为DT_DATE的问题

我之前也碰到过一模一样的问题!AD里的日期属性其实分两类:像whenChanged、whenCreated这类是直接存储为标准可识别的datetime格式,但badPasswordTime、lastLogon这些属于FileTime(文件时间戳)——本质是从1601年1月1日开始计算的100纳秒计数,ADO.NET源读取时会把这些值包装成System.__ComObject,而OpenQuery会直接返回这个计数的数值形式。下面给你几个靠谱的解决方法:

方法1:用SSIS脚本组件做转换(最灵活,推荐)

如果你的数据流是用ADO.NET源读取AD数据,添加一个**脚本组件(转换类型)**来处理这些特殊日期属性:

  1. 把需要转换的AD日期属性(比如badPasswordTime、lastLogon)选入脚本组件的输入列
  2. 添加对应名称的输出列,数据类型设为DT_DATE
  3. 打开脚本编辑器,在Input0_ProcessInputRow方法里写转换逻辑(C#示例):
    public override void Input0_ProcessInputRow(Input0Buffer Row)
    {
        // 处理badPasswordTime
        if (!Row.badPasswordTime_IsNull)
        {
            // 将Com对象转为FileTime长整数
            long fileTime = (long)Row.badPasswordTime;
            // AD的FileTime是UTC时间,用FromFileTimeUtc避免时区偏差
            DateTime utcDateTime = DateTime.FromFileTimeUtc(fileTime);
            // 按需转本地时间或直接用UTC,赋值给输出列
            Row.badPasswordTime_DT = utcDateTime.ToLocalTime();
        }
        else
        {
            Row.badPasswordTime_DT_IsNull = true;
        }
    
        // 同理处理lastLogon
        if (!Row.lastLogon_IsNull)
        {
            long fileTime = (long)Row.lastLogon;
            DateTime utcDateTime = DateTime.FromFileTimeUtc(fileTime);
            Row.lastLogon_DT = utcDateTime.ToLocalTime();
        }
        else
        {
            Row.lastLogon_DT_IsNull = true;
        }
    }
    
    这里要注意:一定要先判断属性是否为空,否则会抛出空引用异常;另外AD的FileTime是UTC时间,转成本地时间还是保留UTC,根据你的业务需求来。

方法2:用OpenQuery在T-SQL里提前转换

如果是通过Linked Server+OpenQuery读取AD数据,可以直接在SQL查询里把FileTime转成datetime,这样SSIS读取时就是标准日期格式了:

SELECT 
    whenChanged,
    whenCreated,
    -- 转换badPasswordTime:FileTime转成SQL datetime
    CASE 
        WHEN badPasswordTime IS NOT NULL 
        THEN DATEADD(SECOND, (badPasswordTime / 10000000) - 11644473600, '1970-01-01') 
        ELSE NULL 
    END AS badPasswordTime,
    -- 转换lastLogon
    CASE 
        WHEN lastLogon IS NOT NULL 
        THEN DATEADD(SECOND, (lastLogon / 10000000) - 11644473600, '1970-01-01') 
        ELSE NULL 
    END AS lastLogon
FROM OPENQUERY(ADSI, 'SELECT whenChanged, whenCreated, badPasswordTime, lastLogon FROM ''LDAP://DC=yourdomain,DC=com'' WHERE objectClass=''user''')

公式解释:AD的FileTime是1601年1月1日起的100纳秒数,先除以10000000转成秒数,再减去1601到1970之间的总秒数(11644473600),最后用DATEADD转成SQL datetime。

方法3:在ADO.NET脚本源里直接处理

如果是用脚本源(而非现成的ADO.NET源)读取AD数据,可以在获取属性时直接转换:

// 假设你用DirectorySearcher查询AD
DirectorySearcher searcher = new DirectorySearcher("LDAP://DC=yourdomain,DC=com", 
    "objectClass=user", 
    new string[] { "whenChanged", "whenCreated", "badPasswordTime", "lastLogon" });

foreach (SearchResult result in searcher.FindAll())
{
    // 处理常规日期
    DateTime whenChanged = DateTime.Parse(result.Properties["whenChanged"][0].ToString());
    
    // 处理FileTime属性
    DateTime? badPasswordTime = null;
    if (result.Properties.Contains("badPasswordTime") && result.Properties["badPasswordTime"][0] != null)
    {
        long fileTime = (long)result.Properties["badPasswordTime"][0];
        badPasswordTime = DateTime.FromFileTimeUtc(fileTime);
    }

    // 将数据添加到输出行...
}

额外注意事项

  • lastLogon vs lastLogonTimestamp:lastLogon是每个域控制器独立存储的,不会同步;如果要获取用户最新的登录时间,建议用lastLogonTimestamp(这个属性会在域控制器间同步,同样是FileTime格式,转换方法一样)
  • 空值处理:AD里很多日期属性可能为空(比如从未修改过密码的用户,badPasswordTime就是空),一定要先判断再转换,避免报错
  • 时区一致性:统一用UTC时间或者转换为本地时间,不要混合,避免数据混乱

内容的提问来源于stack exchange,提问作者azulu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:41:58