.NET DirectoryServices查找方法使用UTC还是本地时间?

时间:2013-10-25 21:42:21

标签: .net datetime active-directory

According to MSDNUserPrincipleComputerPrinciple类的查找方法(如FindByLogonTime和FindByBadPasswordAttempt)使用UTC时间来过滤结果。但是,测试显示这些方法似乎以本地时间作为输入,而生成的对象使用UTC作为其时间属性,需要转换为本地时间。

这是一个示例,它似乎正确地列出了自本地时间早上6点以来服务器上登录尝试失败的所有用户:

    static void Main()
    {
        var pc = new PrincipalContext(ContextType.Domain, dcServer);
        PrincipalSearchResult<UserPrincipal> uFailed = UserPrincipal.FindByBadPasswordAttempt(pc, DateTime.Now.Date.AddHours(6), MatchType.GreaterThan);
        string s = "";
        foreach (UserPrincipal u in uFailed)
        {
            s += u.SamAccountName + ": " + Convert.ToDateTime(u.LastBadPasswordAttempt).ToLocalTime().ToString() + "\r\n";
        }
        Console.Write(s);
        Console.Read();
    }

请注意LastBadPasswordAttempt属性的UTC转换,但不包括FindByBadPasswordAttempt过滤器。

我很担心将其投入生产而不知道我是否遗漏某些东西(可能)或者MSDN文档是错误的。代码运行在它查询的DC上,所以应该没有时区问题。

1 个答案:

答案 0 :(得分:2)

MSDN文档准确无误,您只需要注意传入的.Kind值的DateTime属性。

如果您深入挖掘参考源或反汇编,您会发现最终传递的DateTime值最终会传递给DateTime.ToFileTimeUtcKind会将DateTime.UtcNow转换为.Kind说明其行为。

因此,您可以根据DateTimeKind.Utc传递一个值DateTime.Now .Kind并且它会起作用,或者您可以像现在这样做并传递DateTimeKind.Local 1}}具有TimeZoneInfo DateTimeKind.Unspecified,并且在查询之前本地时间将转换为UTC。请确保您认识到这是运行代码的计算机的本地时间 。如果这个时区与您的用户不同,那么您可能需要使用Convert.ToDateTime来获得与其他当地时区相当的UTC时间。

如果由于某种原因你决定传递自己构建的日期,它可能会DateTime。对于此特定功能,将被视为UTC。对于所有日期/时间函数,这不一定都是正确的,所以要小心。

此外,在输出中,当您使用的值已经是ToString时,无需致电.ToLocalTime。就此而言,除非您打算传递格式说明符,否则您甚至不需要此代码中的TimeZoneInfo。同样,如果您的用户可能位于其他时区,请不要使用DateTime.Today,请使用DateTime.Now.Date上的其中一种方法进行转换。

另一个微小优化,如果您愿意,可以使用{{1}}代替{{1}}。 (它没有什么区别,除了它稍微更具可读性。)