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数据,添加一个**脚本组件(转换类型)**来处理这些特殊日期属性:
- 把需要转换的AD日期属性(比如
badPasswordTime、lastLogon)选入脚本组件的输入列 - 添加对应名称的输出列,数据类型设为
DT_DATE - 打开脚本编辑器,在
Input0_ProcessInputRow方法里写转换逻辑(C#示例):
这里要注意:一定要先判断属性是否为空,否则会抛出空引用异常;另外AD的FileTime是UTC时间,转成本地时间还是保留UTC,根据你的业务需求来。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; } }
方法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
相关产品推荐
相关产品推荐

