首页 > 解决方案 > Outlook.Interop Items.Find() 似乎不匹配

问题描述

我想在我的网络中搜索我的 Outlook 日历和共享日历以查找约会,以检查不同日历中是否有空闲时间段。

获取我使用 Items.Restrict(string Filter) 预过滤的日历的所有约会项目以仅获取今天或更新的项目是没有问题的。我的搜索模式如下所示:

"[Start] >= '" + DateTime.Today.ToString("dd.MM.yyyy HH:mm") + "' AND [End] <= '" + DateTime.Parse("01.01.2019").ToString("dd.MM.yyyy HH:mm") + "'";

一切正常(时间格式 dd.MM.yyyy 与 dd/MM/yyyy 有问题,但已解决)。

拿到物品后,我会搜索它们以检查约会时间是否有空,这意味着:如果开始或结束时间与约会重叠,或者任何日历中的开始时间和结束时间之间是否有约会,那么,如果找到,则返回该约会,否则返回 null。

这是我的搜索模式({0} 是临时开始时间,{1} 是临时结束时间):

"(([Start] <= '{0}' AND '{0}' <= [End]) OR 
([Start] <= '{1}' AND '{1}' <= [End])) OR 
(('{0}' <= [Start] AND [Start] <= '{1}') OR 
('{0}' <= [End] AND [End] <= '{1}'))";

对于我的测试,我今天从 08:00 到 08:30 进行了预约,并在 15:18 开始搜索下一个预约。所以搜索应该返回 null 因为它不应该找到时间重叠,但它会返回早上的测试约会。

如果我将搜索字符串中的值替换为我的时间和找到的约会的时间 ({0} -> 15:18, {1} -> 16:18, [Start] -> 08:00, [End] -> 08:30)我得到了这个:

((04.09.2018 08:00:00 <= '04.09.2018 15:25:09' AND '04.09.2018 15:25:09' <= 04.09.2018 08:30:00) OR (04.09.2018 08:00:00 <= '04.09.2018 16:25:09' AND '04.09.2018 16:25:09' <= 04.09.2018 08:30:00)) 
OR (('04.09.2018 15:25:09' <= 04.09.2018 08:00:00 AND 04.09.2018 08:00:00 <= '04.09.2018 16:25:09') OR ('04.09.2018 15:25:09' <= 04.09.2018 08:30:00 AND 04.09.2018 08:30:00 <= '04.09.2018 16:25:09'))

检查逻辑语句:

//False OR False is False
(
    //False OR False is False
    (
        //True AND False is False
        (
            //Is True
            04.09.2018 08:00:00 <= '04.09.2018 15:25:09' 
            AND 
            //Is False
            '04.09.2018 15:25:09' <= 04.09.2018 08:30:00
        ) 
        OR 
        //True AND False is False
        (
            //Is True
            04.09.2018 08:00:00 <= '04.09.2018 16:25:09'
            AND 
            //Is False
            '04.09.2018 16:25:09' <= 04.09.2018 08:30:00
        )
    ) 
    OR
    //Fals OR Fals is False 
    (
        //False AND True is False
        (
            //Is Fale
            '04.09.2018 15:25:09' <= 04.09.2018 08:00:00 
            AND 
            //Is True
            04.09.2018 08:00:00 <= '04.09.2018 16:25:09'
        ) 
        OR 
        //False AND True is False
        (
            //Is False
            '04.09.2018 15:25:09' <= 04.09.2018 08:30:00 
            AND 
            //Is True
            04.09.2018 08:30:00 <= '04.09.2018 16:25:09'
        )
    )
)

我只是不明白为什么这个搜索模式为那个甚至不在检查时间附近的约会返回 True。

如果那天我没有其他约会,它会起作用(返回 null,而不是第二天的约会)。

我已经检查了时间格式的问题(dd.MM.yyyy vs. dd/MM/yyyy 等)所以我猜这不是行为的原因(如果我使用带有秒数的“/”,那么搜索模式从明天返回一个约会,如果我使用 '.' 与秒它返回今天的约会)。

我的搜索模式错了吗?我是否监督了某些事情,或者是在后台工作的时间格式不同?

有任何想法吗?谢谢。

编辑

会不会,这个过滤有问题?我复制粘贴了 Microsoft ( msdn )制作的示例。无论我做什么,Outlook.Items.count(Restrict() 之前和之后)始终为 2147483647。但是当我输出受限项目时,For-Each 运行 5 次。

当我阅读 MAPI 文件夹时,我使用“[Start] >= DateTime.Now.ToString("g")" 对项目进行预排序,对它们进行排序并查看第一个具有 Date >= Now 的项目,我限制这个受限带有另一个过滤器的项目,当我查看受限项目中的第一个项目时,我得到的日期是 5 年前。

所有项目 -> 受 [开始] 限制 > 现在 -> 受 [开始] 限制 >= 08:00 -> 结果:从 2013 年开始... -.-

标签: c#searchdesign-patternsoutlookfind

解决方案


所以因为 Items.Find() 函数似乎有问题,或者至少不能处理比​​“1 AND 1”更复杂的事情,所以我不得不写一个“小解决方法”(我不喜欢它,它似乎是如果有很多约会有点慢)来解决这个问题:

这是我从我的日历或共享日历中获取约会项目的功能(因为 .Find() 过滤器似乎在这里工作,所以我过滤了这些项目,这样我就不会得到旧的约会或来自遥远未来的约会):

Dictionary<DateTime, DateTime> Plunder = new Dictionary<DateTime, DateTime>();
int AppointLength = 60;    

private void GetCalendar(object username, bool Shared)
{
    Outlook.MAPIFolder oCalendar;
    Outlook.Application oApp = new Outlook.Application();
    Outlook.NameSpace oNS = oApp.GetNamespace("mapi");
    oNS.Logon(Missing.Value, Missing.Value, true, true);

    if (Shared)
    {
        Outlook.Recipient oRecip = oNS.CreateRecipient((string)username);
        oCalendar = oNS.GetSharedDefaultFolder(oRecip, Outlook.OlDefaultFolders.olFolderCalendar);
    }
    else
    {
        oCalendar = oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
    }

    Outlook.Items oItems = oCalendar.Items;
    oItems.IncludeRecurrences = true;
    oItems.Sort("[Start]");

    string strRestriction = "[Start] >= '" + DateTime.Today.ToString("g") + "' AND [End] <= '" + dtpEndDate.Value.ToString("g") + "'";

    Outlook.Items allNew = oItems.Restrict(strRestriction);

    allNew.Sort("[Start]");

    foreach (Outlook.AppointmentItem appt in allNew)
    {
        if (Plunder.ContainsKey(appt.Start))
        {
            if (Plunder[appt.Start] < appt.End)
            {
                Plunder[appt.Start] = appt.End;
            }
        }
        else
        {
            Plunder.Add(appt.Start, appt.End);
        }
    }
}

在我拥有所有日历中的所有约会项目后,我想在 Plunder-Dictionary 中搜索

private DateTime CheckForAppointment(DateTime now)
{
    DateTime then = now.AddMinutes(AppointLength);

    var AppointmentFound = Plunder.Select(i => i).Where(d => 
        ((d.Key < now && now < d.Value) 
        || (d.Key < then && then < d.Value)) 
        || ((now < d.Key && d.Key < then) 
        || (now < d.Value && d.Value < then)));

    if (AppointmentFound.Any())
    {
        now = CheckForAppointment(((KeyValuePair<DateTime, DateTime>)AppointmentFound.First()).Value);
    }

    return now;
}

取回下一个空闲时间跨度。

由于这个解决方案似乎有点慢,有没有人有更好、更快的想法?

编辑:

如果我记得上次触摸约会在 Plunder-Dictionary 中的位置,以便从该位置继续搜索,我可以让它更快。这应该有效,因为 Plunder 是按日期排序的。


推荐阅读