Start and end dates of recurrence pattern are one day off in PST

I am trying to create a daily recurring event, using the Java edition of the Email API. Everything looks correct when Ioading the resulting .PST in Outlook except for the start & end dates - they both appear as one day prior to the input start & end dates.

Example code:

  Calendar jcalendar = Calendar.getInstance(java.util.TimeZone.getDefault());
  jcalendar.set(2021, java.util.Calendar.MARCH, 1, 15, 30, 0)
  Date startDate = jcalendar.getTime()

  jcalendar.set(2021, java.util.Calendar.MARCH, 1, 16, 0, 0)
  Date endDate = jcalendar.getTime()

  MapiCalendar event = new MapiCalendar(location, summary, description, startDate, endDate)
      MapiCalendarDailyRecurrencePattern pattern = new MapiCalendarDailyRecurrencePattern()
      pattern.setPeriod(1)
      pattern.setStartDate(startDate)
      // recurrence.getUntil().getTime() is the input, returning: 5 March 2021, 15:30:00 UTC in millis
      pattern.setEndDate(new Date(recurrence.getUntil().getTime()))
      pattern.setEndType(MapiCalendarRecurrenceEndType.EndAfterDate)
      pattern.setPatternType(MapiCalendarRecurrencePatternType.Day)
      // pattern.setWeekStartDay(DayOfWeek.Monday) // NO EFFECT
      pattern.setDayOfWeek(DayOfWeek.Monday) // NO EFFECT

MapiCalendarEventRecurrence r = new MapiCalendarEventRecurrence()
r.setRecurrencePattern(pattern)
r.setClipStart(startDate)
r.setClipEndDate(pattern.getEndDate())
event.setRecurrence(r)

This results in an event that starts on February 28, 2021 at 15:30 and ends 30 minutes later, repeating each day through March 4, 2021. The number of occurrences is correct. But the start was supposed to be March 1 and the end should have been March 5.
Similarly, if I create another event beginning on a Thursday, it begins on Wednesday in Outlook. What do I need to change here?

@cdeangelis,
Thank you for the issue description. To my regret, we cannot use your code snippet that contains an unknown symbol: “recurrence”. Could you please share a comprehensive code snippet to investigate the problem? Please also specify the version of Aspose.Email you are using.

Thank you @Andrey_Potapov for your reply.

I will attempt to post a complete example. Note that I am converting from Scala to Java (because my application is written in Scala & invokes the Java Email API). So I may miss something - please use your skill to correct anything incorrect or incomplete.

  Calendar jcalendar = Calendar.getInstance(java.util.TimeZone.getDefault());
  jcalendar.set(2021, java.util.Calendar.MARCH, 1, 15, 30, 0);
  Date startDate = jcalendar.getTime();

  jcalendar.set(2021, java.util.Calendar.MARCH, 1, 16, 0, 0);
  Date endDate = jcalendar.getTime();

  MapiCalendar event = new MapiCalendar("location", "summary", "description", startDate, endDate);
  MapiCalendarDailyRecurrencePattern pattern = new MapiCalendarDailyRecurrencePattern();
  pattern.setPeriod(1);
  pattern.setStartDate(startDate);
  jcalendar.set(2021, java.util.Calendar.MARCH, 5, 15, 30, 0);
  Date untilDate = jcalendar.getTime();
  pattern.setEndDate(untilDate);
  pattern.setEndType(MapiCalendarRecurrenceEndType.EndAfterDate);
  pattern.setPatternType(MapiCalendarRecurrencePatternType.Day);
  // pattern.setWeekStartDay(DayOfWeek.Monday); // NO EFFECT
  pattern.setDayOfWeek(DayOfWeek.Monday); // NO EFFECT

  MapiCalendarEventRecurrence r = new MapiCalendarEventRecurrence();
  r.setRecurrencePattern(pattern);
  r.setClipStart(startDate);
  r.setClipEndDate(pattern.getEndDate());
  event.setRecurrence(r);

  // writing the PST happens elsewhere in our code, the rest is copied from another forum post.
  PersonalStorage pst = PersonalStorage.create("DailyPst.pst", FileFormatVersion.Unicode);
  FolderInfo fi = pst.createPredefinedFolder("CalPst", StandardIpmFolder.Appointments);
  fi.addMapiMessageItem(event);

@cdeangelis,
Thank you for the code snippet. I have logged the issue in our tracking system with ID EMAILJAVA-34827 for further investigation. You will be notified about any progress.

@Andrey_Potapov thank you for the follow up. I forgot to mention the Aspose.Email version ; it is 20.8-jdk16.jar

@cdeangelis,
Thank you for the additional information.

@Andrey_Potapov

I believe I have found the underlying reason for this problem. There is a property in the generated .PST from the Aspose.Email API called PidLidRecurring. Whenever I generate an event with a recurrence pattern, this property is being generated as FALSE according to several PST viewing tools.

According to the above MSFT spec, this flag must be generated as TRUE instead.

image.png (2.9 KB)

The Mac Outlook client happens to show a recurring event without the correct value, but the dates are incorrect as noted. Other viewers show different things, none of them are correct. So I conclude this is a bug in the Email API which needs to be fixed.

@cdeangelis,
Thank you for the additional information. Our developers will take it into account.

@cdeangelis,
Our developers have prepared a hotfix release to check the issue on your side. The issue was tested on Windows and MacOS Outlook versions.

@Andrey_Potapov
Thank you for the update. I have tested the hotfix and found it made no difference. It seems one of the PST viewer tools always reports that PidLidRecurring is FALSE while another one reflects this as TRUE, but does not identify the property by name, only by hexadecimal value (Goldfynch PST Viewer).

Nonetheless, I have determined the actual problem is that the Mac version of Outlook is buggy with respect to displaying recurring events from an imported .PST. The same problem can be seen with birthdates of Outlook Contacts exported via Aspose Email & imported via Outlook for MacOS - the dates are shifted backwards by 1 day.

Meanwhile, the dates of both items are correct in Outlook for Windows. So the fix may help for other platforms, but not in Microsoft’s Mac client.

My remaining issue is with the times - they always display as if they were in GMT instead of the intended time zone. This seems to be due to the need to specify standard/ daylight savings TZ rules for every time zone of interest… as documented in posts like this: How to set TimeZone in calendar
That is unfortunate considering Java already has defined time zones & their rules, and mechanisms to update the rules when needed. It would be terrific if Aspose.Email could replace its own TZ rule defining requirements with TimeZone, ZoneDateTime etc. from the Java 8 API. Duplicating this in Aspose.Email classes is burdensome & not easily maintainable if time zone transitions should change.

@cdeangelis,
Thank you for the additional information. I have sent your remarks to our development team. I will keep you informed about any progress on this issue.

@cdeangelis,
To further investigation, we need the next additional information:

  1. The PST sample generated on your end with hotfix release.
  2. Local time zone on the computer where the PST is generated.
  3. Local time zone on the computer where the PST is opened.

Also, the time zone can be set as follows:

String tzName = java.util.TimeZone.getDefault().getID();
event.setStartDateTimeZone(new MapiCalendarTimeZone(tzName));
event.setEndDateTimeZone(new MapiCalendarTimeZone(tzName));

@Andrey_Potapov
I tried the code snippet you included above, but it does not make any difference. I used the time zoneId ‘America/New_York’ instead of .getDefault() to get the desired time zone. Recurring events are still shown in GMT time instead of the desired time zone (on Windows, at least).

Local time zone where the PST is generated: Etc/UTC (UTC, +0000) (from timedatectl )
Local time zone where the PST is opened: UTC -05:00 (Eastern Time: US & Canada)

PST Sample: Dropbox - office365_exchange-export-1615316136318.pst - Simplify your life
This contains 2 recurring events:
1 daily event from 1.March - 5.March 2021, 5 occurrences
1 weekly event from 5.April - 12.April 2021, 2 occurrences
The times appear at 3:30 PM for the 1st event, and 3:00 PM for the 2nd event. I desire they appear as 10:30 AM & 10:00 AM.

Thank you again for your help.

@cdeangelis,
I have sent your information to our developers. I will keep you informed about any progress. Thank you for your patience.

@cdeangelis,
There are many versions of Outlook displaying PST files differently. Please try to add UTC time zone as below:

// Local time zone where the PST is generated should be UTC
Calendar jcalendar = Calendar.getInstance(java.util.TimeZone.getDefault());
jcalendar.set(2021, java.util.Calendar.MARCH, 1, 15, 30, 0);
Date startDate = jcalendar.getTime();

jcalendar.set(2021, java.util.Calendar.MARCH, 1, 16, 0, 0);
Date endDate = jcalendar.getTime();

MapiCalendar event = new MapiCalendar("location", "summary", "description", startDate, endDate);

// UTC time zone
MapiCalendarTimeZone utcTimeZone = new MapiCalendarTimeZone("UTC");
event.setStartDateTimeZone(utcTimeZone);
event.setEndDateTimeZone(utcTimeZone);

MapiCalendarDailyRecurrencePattern pattern = new MapiCalendarDailyRecurrencePattern();
pattern.setPeriod(1);
pattern.setStartDate(startDate);
jcalendar.set(2021, java.util.Calendar.MARCH, 5, 15, 30, 0);
Date untilDate = jcalendar.getTime();
pattern.setEndDate(untilDate);
pattern.setEndType(MapiCalendarRecurrenceEndType.EndAfterDate);
pattern.setPatternType(MapiCalendarRecurrencePatternType.Day);
// pattern.setWeekStartDay(DayOfWeek.Monday); // NO EFFECT
pattern.setDayOfWeek(DayOfWeek.Monday); // NO EFFECT

MapiCalendarEventRecurrence r = new MapiCalendarEventRecurrence();
r.setRecurrencePattern(pattern);
r.setClipStart(startDate);
r.setClipEnd(pattern.getEndDate());
//https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/pidlidappointmenttimezonedefinitionrecur-canonical-property
r.setAppointmentTimeZoneDefinitionRecur(utcTimeZone); // <---
r.setTimeZoneStruct(utcTimeZone); // <---
event.setRecurrence(r);

// writing the PST happens elsewhere in our code, the rest is copied from another forum post.
PersonalStorage pst = PersonalStorage.create("DailyPst.pst", FileFormatVersion.Unicode);
FolderInfo fi = pst.createPredefinedFolder("CalPst", StandardIpmFolder.Appointments);
pst.createPredefinedFolder("Inbox", StandardIpmFolder.Inbox); // for correct PST import
fi.addMapiMessageItem(event);
pst.dispose();

API Reference: MapiCalendarTimeZone class, MapiCalendarEventRecurrence class

@Andrey_Potapov,

I tried your recommendation of specifying UTC as the time zone in the example above. This works, except that I can see a recurring event time change once it crosses over a DST boundary.

For instance, a weekly event occurring Fridays in March at 12:00 PM EST will be shown that way in Outlook… until the DST rule goes into effect, and then the event appears at 1:00 pm. That makes sense as the developer who specified UTC as the time zone, but end users would not understand why the time appears to change for some events in a series – UTC is not even a concept most end users understand.

Since my application could receive events in any time zone as input - and I am able to detect those zones - I would really like the ability to use standard Java 8 classes to specify time zones in the Aspose API without having to translate their rules to the Aspose.Email object model.

Thank you again for your follow-up.

@cdeangelis,
I sent this information to our development team. We will investigate this case.

@cdeangelis,
Could you please share a PST file containing 2 recurring events? The file must be generated by Outlook so that it is imported correctly on Windows and MacOS.

@Andrey_Potapov Sorry, I am confused. We are using the Aspose API to generate PSTs on a Linux system. We do not use Outlook to generate the PST. Those PSTs are meant to be loaded by end users on a machine running Outlook, so some other machine besides the one generating the PST.

I will attach the latest example I have, which I believe contains 3 recurring events which were generated while specifying UTC using your latest suggestion.
office365_exchange-export-1615480506428.pst.zip (8.6 KB)

@cdeangelis,

I realized it. But could you please provide the PST file (containing 2 recurring events) created in Outlook on the user machine that is having the problem? It would help us to find out a specificity and a cause for the issue.