2

根据 MSDNUserPrinciple ,和类的查找方法(如 FindByLogonTime 和 FindByBadPasswordAttempt)ComputerPrinciple使用 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 上运行,所以应该没有时区问题。

4

1 回答 1

2

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

如果您深入研究参考源或反汇编,您会发现DateTime您传递的值最终会传递给DateTime.ToFileTimeUtc,这确实考虑了Kind它的行为。

因此,您可以传入一个基于 的值,DateTime.UtcNow该值具有 a并且它将起作用,或者您可以像当前所做的那样传递具有 a的值,并且本地时间将在查询之前转换为 UTC。只要确保您知道这是运行代码的计算机的本地时间。如果有可能这与您的用户不是同一时区,那么您可能需要使用来获取与其他本地时区等效的 UTC 时间。.KindDateTimeKind.UtcDateTime.Now.KindDateTimeKind.LocalTimeZoneInfo

如果出于某种原因您决定传入您自己构建的日期,它可能会有DateTimeKind.Unspecified. 对于此特定功能,它将被视为 UTC。这不一定适用于所有日期/时间函数,所以要小心。

此外,在输出中,Convert.ToDateTime当您使用的值已经是DateTime. 就此而言,您甚至不需要ToString在此代码中使用 ,除非您打算传递格式说明符。再说一次,如果您的用户可能在其他时区,请不要使用.ToLocalTime,而是使用其中一种方法TimeZoneInfo来进行转换。

另一种微小的优化,您可以根据需要DateTime.Today使用DateTime.Now.Date。(它没有什么区别,只是它更易读。)

于 2013-10-25T23:19:31.037 回答