Retrieve current Outlook appointment - c#

I need the current appointment. If no current appointment then the next or even previous appointment.
I figure to use Restrict to limit the set of appointments, and then choose either the first or last appointment depending on the restrict argument (e.g. Restrict to appointments ending after current time, or appointments starting before current time).
I'm having trouble with the string filter needed as argument.
A simple VB example (code stump):
myStart = Format(Date, "mm/dd/yyyy hh:mm AMPM")
strRestriction = "[Start] <= '" & myStart & "'"
'Restrict the Items collection
Set oResItems = oItems.Restrict(strRestriction)
'Sort
oResItems.Sort "[Start]"
I am attempting to do the same in C#.
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Get the NameSpace and Logon information.
// Outlook.NameSpace oNS = (Outlook.NameSpace)oApp.GetNamespace("mapi");
Outlook.NameSpace oNS = oApp.GetNamespace("mapi");
//Log on by using a dialog box to choose the profile.
oNS.Logon(Missing.Value, Missing.Value, true, true);
// Get the Calendar folder.
Outlook.MAPIFolder oCalendar = oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
// Get the Items (Appointments) collection from the Calendar folder.
oItems = oCalendar.Items;
oItems.IncludeRecurrences = true;
// THIS IS THE PROBLEM AREA
String filter = "[Start] <= '" + DateTime.Now.ToString("MM/dd/yyyy hh:mm AMPM") + "'";
Outlook.Items restrictedItems = oItems.Restrict(filter);
// Take the last item on the list - should be current or next appointment
restrictedItems.Sort("[Start]");
Outlook.AppointmentItem oAppt = restrictedItems.GetLast();
// Done. Log off.
oNS.Logoff();
I imagine since the filter is a string, the date format needs to be yyyy/mm/dd HH:mm:ss? I can't find any documentation on how to manipulate the [Start], like parsing it to a date or something.
Depending on the date format, I will either get the wrong appointment, or will be unable to use GetLast due to the filter excluding all appointments.
I've seen examples, but either they loop through the appointments (too inefficient), or the date formats look like they can't be trusted to return the correct appointment (For example https://social.msdn.microsoft.com/Forums/vstudio/en-US/c6a8bd21-6534-43be-b23e-1068651da92e/retrieve-appointment-items-from-outlook-2007-calendar-restrict?forum=vsto, which seems to have the date hardcoded instead if using DateTime.Now.)
UPDATE: I'm currently looping through like shown below. Any suggestions for more efficient code?
DateTime currentTime = DateTime.Now;
foreach (Outlook.AppointmentItem item in oItems)
{
if (item.Start <= currentTime && item.End.Subtract(new TimeSpan(0, 10, 0)) > currentTime)
{
appointmentArrayList.Add(item);
}
}

This is your issue:
DateTime.Now.ToString("MM/dd/yyyy hh:mm AMPM")
What I think you're going for is:
DateTime.Now.ToString("MM/dd/yyyy hh:mm tt", CultureInfo.InvariantCulture)

By following the information found here, I was able to get it to work using "yyyy-MM-dd HH:mm" as the format string for the toString call.
Hope this helps.

This code works to show Outlook appointments from today onwards:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DemoAppointmentsInRange();
}
private void DemoAppointmentsInRange()
{
Application a = new Application();
Microsoft.Office.Interop.Outlook.Folder calFolder = a.Session.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderCalendar) as Microsoft.Office.Interop.Outlook.Folder;
DateTime start = DateTime.Now;
DateTime end = start.AddDays(5);
Microsoft.Office.Interop.Outlook.Items rangeAppts = GetAppointmentsInRange(calFolder, start, end);
if (rangeAppts != null)
{
foreach (Microsoft.Office.Interop.Outlook.AppointmentItem appt in rangeAppts)
{
Response.Write("Subject: " + appt.Subject + " "+" Start: "+appt.Start.ToString()+" "+"End:"+appt.End.ToString()+"<br/>");
}
}
}
private Microsoft.Office.Interop.Outlook.Items GetAppointmentsInRange(
Microsoft.Office.Interop.Outlook.Folder folder, DateTime startTime, DateTime endTime)
{
string filter = "[Start] >= '"+ startTime.ToString("g")+ "' AND [End] <= '" + endTime.ToString("g") + "'";
//Response.Write(filter);
try
{
Microsoft.Office.Interop.Outlook.Items calItems = folder.Items;
calItems.IncludeRecurrences = true;
calItems.Sort("[Start]", Type.Missing);
Microsoft.Office.Interop.Outlook.Items restrictItems = calItems.Restrict(filter);
if (restrictItems.Count > 0)
{
return restrictItems;
}
else
{
return null;
}
}
catch
{
return null;
}
}
}

I couldn't figure out DateTime format, but I found this article:
https://learn.microsoft.com/en-us/office/vba/outlook/how-to/search-and-filter/filtering
Then I realized that they have a concept called "DASL Queries", reading furthermore I found this related to filtering with DateTime:
https://learn.microsoft.com/en-us/office/vba/outlook/how-to/search-and-filter/filtering-items-using-a-date-time-comparison
And I've decided to get all today's AppointmentItem(s) this way:
public enum MacroName
{
today,
tomorrow,
yesterday,
next7days,
last7days,
nextweek,
thisweek,
lastweek,
nextmonth,
thismonth,
lastmonth
}
private Outlook.Items GetAppointmentsWithMacro(Outlook.Folder folder, MacroName macro)
{
string strFilter = "#SQL=%" + macro.ToString() + "(\"urn:schemas:calendar:dtstart\")%";
try
{
Outlook.Items calItems = folder.Items;
calItems.IncludeRecurrences = true;
calItems.Sort("[Start]", Type.Missing);
Outlook.Items restrictItems = calItems.Restrict(strFilter);
if (restrictItems.Count > 0)
{
return restrictItems;
}
else
{
return null;
}
}
catch { return null; }
}
I want to be safest as possible because it seems that filtering by DateTime is related to local DateTime settings. By using the "today" macro I was able for the first time to extract the correct information from Outlook appointments store

Related

'String was not recognized as a valid DateTime'- How do I solve this error regarding combinations of values?

I have created a Visual Studio application using ASP.NET and WPF connected to a MSSQL database/server for keeping track of how long someone takes on some other desktop application. There is a page where the user can enter information of what app they accessed, what sort of app it is, and when they accessed and closed it, and I am having trouble with inputting the DateTime values into my database. As per the DateTime format, I have tried to combine a date from a DatePicker with a time from textboxes in the form (both values are in the DateTime format, but I take their separate components and combine them).
The error I got (from debugging using the VS debugger) is: "String was not recognized as a valid DateTime", at:
combinedStart = DateTime.ParseExact(startString, "dd/MM/yyyy hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture);
..and the next line too.
For further information, I combine the values from textboxes (to get the hour and minute values), ComboBoxes (for 'AM' or 'PM'), and DatePickers (for the dates). The expected result is the inputting of the DateTime values in the exact same format as in the above line of code. Could someone suggest something to solve this problem? Please consider that I am new to C# and WPF in general, along with posting questions in StackOverflow.
The full C# code is below:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Data.SqlClient;
using TimeOrganiser.Properties;
namespace TimeOrganiser
{
/// <summary>
/// Interaction logic for Window2.xaml
/// </summary>
public partial class Window2 : Window
{
String startDate;
String endDate;
String startString;
String endString;
DateTime combinedStart;
DateTime combinedEnd;
double DurationHrs;
public Window2()
{
InitializeComponent();
}
//...
private void btnAdd_Entry(object sender, RoutedEventArgs e)
{
String cnString = Properties.Settings.Default.connectionString;
SqlConnection sqlCon = new SqlConnection(cnString);
ComboBoxItem selectedItem = (ComboBoxItem)cbxAppType.SelectedItem;
String selectedText = selectedItem.Content.ToString();
ComboBoxItem selectedItem2 = (ComboBoxItem)cbxAMPM.SelectedItem;
String selectedText2 = selectedItem2.Content.ToString();
ComboBoxItem selectedItem3 = (ComboBoxItem)cbxEndAMPM.SelectedItem;
String selectedText3 = selectedItem3.Content.ToString();
startString = startDate + " " + txtStartTimeHr.Text + ":" + txtStartTimeMin.Text + ":" + "00 " + selectedText2;
endString = endDate + " " + txtEndTimeHr.Text + ":" + txtEndTimeMin.Text + ":" + "00 " + selectedText3;
combinedStart = DateTime.ParseExact(startString, "dd/MM/yyyy hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture);
combinedEnd = DateTime.ParseExact(endString, "dd/MM/yyyy hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture);
//combinedStart = DateTime.Parse(startString, System.Globalization.CultureInfo.InvariantCulture);
//combinedEnd = DateTime.Parse(endString, System.Globalization.CultureInfo.InvariantCulture);
//combinedStart = new DateTime();
DurationHrs = (combinedEnd - combinedStart).TotalHours;
try
{
String sqlGetPassQuery = "INSERT INTO ApplicationInfo (AppName, " +
"StartDate, EndDate, DurationHrs, Productivity, Entertainment, Social, Browsing) " +
"Values (#AppName, #StartDate, #EndDate, #DurationHrs, ";
//...other unrelated code
sqlCmd.ExecuteScalar();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
sqlCon.Close();
}
}
private void StartDate_Changed(object sender, SelectionChangedEventArgs e)
{
if (clnStartDate.SelectedDate.HasValue)
{
startDate = clnStartDate.SelectedDate.Value.Date.ToShortDateString();
}
}
private void EndDate_Changed(object sender, SelectionChangedEventArgs e)
{
if (clnEndDate.SelectedDate.HasValue)
{
endDate = clnEndDate.SelectedDate.Value.Date.ToShortDateString();
}
}
}
}
I was able to solve the problem, thanks to #Ahmed Alayat's suggestion. The solution to this was:
combinedStart = DateTime.Parse(startString);
combinedEnd = DateTime.Parse(endString);

Acess meetings of a specific calendar EWS (C#)

I am building an application that accesses meetings from Exchange. I'm using the code provided by Microsoft in their EWS documentation. The issue is I need to access a specific calendar. Say, I create 2 calendars apart from the default one. When I access meetings using this code, I only get meetings from the default calendar. I want to access meetings from a specific calendar. How can I do this?
Thanks for the help.
// Initialize values for the start and end times, and the number of appointments to retrieve.
DateTime startDate = DateTime.Now;
DateTime endDate = startDate.AddDays(30);
const int NUM_APPTS = 5;
// Initialize the calendar folder object with only the folder ID.
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, new PropertySet());
// Set the start and end time and number of appointments to retrieve.
CalendarView cView = new CalendarView(startDate, endDate, NUM_APPTS);
// Limit the properties returned to the appointment's subject, start time, and end time.
cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End);
// Retrieve a collection of appointments by using the calendar view.
FindItemsResults<Appointment> appointments = calendar.FindAppointments(cView);
Console.WriteLine("\nThe first " + NUM_APPTS + " appointments on your calendar from " + startDate.Date.ToShortDateString() +
" to " + endDate.Date.ToShortDateString() + " are: \n");
foreach (Appointment a in appointments)
{
Console.Write("Subject: " + a.Subject.ToString() + " ");
Console.Write("Start: " + a.Start.ToString() + " ");
Console.Write("End: " + a.End.ToString());
Console.WriteLine();
}
I think your problem is that you are using WellKnownFolderName.Calendar:
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, new PropertySet());
Instead you should use the FolderId of the calendar you have created. To get the id of the folder (calendar) you can use the code similar to this (found in answer: https://stackoverflow.com/a/24133821/1037864)
ExtendedPropertyDefinition PR_Folder_Path = new ExtendedPropertyDefinition(26293, MapiPropertyType.String);
PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
psPropSet.Add(PR_Folder_Path);
FolderId rfRootFolderid = new FolderId(WellKnownFolderName.Root, mbMailboxname);
FolderView fvFolderView = new FolderView(1000);
fvFolderView.Traversal = FolderTraversal.Deep;
fvFolderView.PropertySet = psPropSet;
SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(FolderSchema.FolderClass, "IPF.Appointment");
FindFoldersResults ffoldres = service.FindFolders(rfRootFolderid, sfSearchFilter, fvFolderView);
if (ffoldres.Folders.Count > 0) {
foreach (Folder fld in ffoldres.Folders) {
Console.WriteLine(fld.Id.ToString() + " " + fld.DisplayName);
}
}
Take the value from fld.Id and use instead of WellKnownFolderName.Calendar.
(I don't have an Exchange server available right now to try this out but I hope you get the idea and that my code i correct.)

Exchange EWS Api - Get calendar appointment by category

I am currently developing an app which checks one or more users calendars for appointments/meetings under a specific category.
Being new to working with EWS, i have been trying to find a solution as to get a Calendar item (appointment or meeting) by Category or determine if an appointment has a specific category. I currently have the following code so far (exService = ExchangeService object):
foreach (Appointment a in exService.FindItems(WellKnownFolderName.Calendar, new ItemView(int.MaxValue)))
{
//Need to check if appointment has category f.x.: "SMS"
}
Does anybody know a way to acheive this?
Thanks
When your querying Appointments you want to use FindAppointments and a calender-view rather then using FindItems this will ensure that any recurring appointments are expanded eg see https://msdn.microsoft.com/en-us/library/office/dn495614(v=exchg.150).aspx
to use categories all you need to do is something like
DateTime startDate = DateTime.Now;
DateTime endDate = startDate.AddDays(60);
const int NUM_APPTS = 1000;
// Initialize the calendar folder object with only the folder ID.
CalendarFolder calendar = CalendarFolder.Bind(service, WellKnownFolderName.Calendar, new PropertySet());
// Set the start and end time and number of appointments to retrieve.
CalendarView cView = new CalendarView(startDate, endDate, NUM_APPTS);
// Limit the properties returned to the appointment's subject, start time, and end time.
cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End,AppointmentSchema.Categories);
// Retrieve a collection of appointments by using the calendar view.
FindItemsResults<Appointment> appointments = calendar.FindAppointments(cView);
Console.WriteLine("\nThe first " + NUM_APPTS + " appointments on your calendar from " + startDate.Date.ToShortDateString() +
" to " + endDate.Date.ToShortDateString() + " are: \n");
foreach (Appointment a in appointments)
{
if (a.Categories.Contains("Green"))
{
Console.Write("Subject: " + a.Subject.ToString() + " ");
Console.Write("Start: " + a.Start.ToString() + " ");
Console.Write("End: " + a.End.ToString());
}
Console.WriteLine();
}

C# Outlook Add-On: Check Calendars Availability

I am working on an add-in for Outlook using C# and I want to be able to check the availability of calendars (mine and others'). I tried using GetSharedDefaultFolder() but it only worked with those who specifically gave me permission, even though all calendars in my company can be viewed by others (we can see the subject and times of appointments). Is there anyway I can get these information? Thanks.
EDIT: I want to emphasize that my problem is with GetSharedDefaultFolder() rather than GetDefaultFolder() (i.e. viewing others' calendars.) Also, I only need to be able to check others' calendars availability, as opposed to having full access to the calendar.
Do not access the folder directly - use Recipient.FreeBusy or AddressEntry.GetFreeBusy
Try This>>
public void GetAllCalendarItems()
{
Microsoft.Office.Interop.Outlook.Application oApp = null;
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = null;
Microsoft.Office.Interop.Outlook.MAPIFolder CalendarFolder = null;
Microsoft.Office.Interop.Outlook.Items outlookCalendarItems = null;
oApp = new Microsoft.Office.Interop.Outlook.Application();
mapiNamespace = oApp.GetNamespace("MAPI"); ;
CalendarFolder = mapiNamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderCalendar); outlookCalendarItems = CalendarFolder.Items;
outlookCalendarItems.IncludeRecurrences = true;
foreach (Microsoft.Office.Interop.Outlook.AppointmentItem item in outlookCalendarItems)
{
if (item.IsRecurring)
{
Microsoft.Office.Interop.Outlook.RecurrencePattern rp = item.GetRecurrencePattern();
DateTime first = new DateTime(2008, 8, 31, item.Start.Hour, item.Start.Minute, 0);
DateTime last = new DateTime(2008, 10, 1);
Microsoft.Office.Interop.Outlook.AppointmentItem recur = null;
for (DateTime cur = first; cur <= last; cur = cur.AddDays(1))
{
try
{
recur = rp.GetOccurrence(cur);
MessageBox.Show(recur.Subject + " -> " + cur.ToLongDateString());
}
catch
{ }
}
}
else
{
MessageBox.Show(item.Subject + " -> " + item.Start.ToLongDateString());
}
}
}
Seems problem similar to this>
http://www.add-in-express.com/forum/read.php?FID=5&TID=8953
So follow discussion on this link. It might helpful to you.

Is there a better way to filter mails based on date?

Well I have run into a problem.
I am using the MS outlook API using C # to generate a few excel based reports from the emails that I receive.
Now initially when I started this, it was OK as the number emails were a little less in the folder. Now after a few days, the number has gone into thousands.
Application app = null;
_NameSpace ns = null;
MailItem item = null;
MAPIFolder inboxFolder = null;
MAPIFolder subFolder = null;
DateTime MyDateTime;
MyDateTime = new DateTime();
MyDateTime = DateTime.ParseExact(dateFilter, "yyyy-MM-dd HH:mm tt", null);
try
{
app = new Application();
ns = app.GetNamespace("MAPI");
ns.Logon(null, null, false, false);
inboxFolder = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
subFolder = inboxFolder.Folders["Alerts"];
for (int i = 1; i <= subFolder.Items.Count; i++)
{
item = (Microsoft.Office.Interop.Outlook.MailItem)subFolder.Items[i];
string subject = item.Subject;
DateTime sent = item.SentOn;
if (item.SentOn > MyDateTime && item.SentOn < MyDateTime.AddDays(1))
{//Do some logging
}}
Now the issue with the above code is that it starts searching from the last email received. This is causing it to increase the time it takes to reach the "filter".
I need suggestions to improve my code, if any.
Thanks for reading me out.
Before your loop, get a collection of items from subFolder filtered by the Restrict method.
You can use your date ranges in the filter string that you use (I've not written it here since I'm not in a position to test it and don't want to mislead you - a search should give plenty of examples). Then just loop/iterate over the resulting collection which should then contain just the items you need.
Microsoft.Office.Interop.Outlook.Items restrictedItems = subFolder.Items.Restrict("*filter*");
for (int i = 1; i <= restrictedItems.Count; i++)...
This is how I filter Outlook appointments.
For mails you need .olFolderInbox instead of .olFolderCalendar.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook._items.restrict?view=outlook-pia
Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
NameSpace mapiNamespace = oApp.GetNamespace("MAPI");
MAPIFolder calendarFolder = mapiNamespace.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
DateTime filterDate = DateTime.Now;
string filterDateString = filterDate.Day + "/" + filterDate.Month + "/" + filterDate.Year + " 1:00am";
string filter = "[CreationTime] > '" + string.Format(filterDateString, "ddddd h:nn AMPM") + "'";
Items outlookCalendarItems = calendarFolder.Items.Restrict(filter);
foreach (AppointmentItem item in outlookCalendarItems)
{
// Here I write to our database
}

Categories

Resources