According to MSDN,UserPrinciple
和ComputerPrinciple
类的查找方法(如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上,所以应该没有时区问题。
答案 0 :(得分:2)
MSDN文档准确无误,您只需要注意传入的.Kind
值的DateTime
属性。
如果您深入挖掘参考源或反汇编,您会发现最终传递的DateTime
值最终会传递给DateTime.ToFileTimeUtc
,Kind
会将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}}。 (它没有什么区别,除了它稍微更具可读性。)