private void _Timer_Elapsed(object sender, ElapsedEventArgs e) { bool continueNext = true; try { var now = e.SignalTime; _Timer.Stop(); var doAlarm = false; long seconds; DateTime start, alarmDate; var changeZone = _Schedule.TimeZone != TimeZoneInfo.Local; switch (_Schedule.Type) { case ScheduleType.Once: alarmDate = changeZone ? TimeZoneInfo.ConvertTime(_Schedule.AlarmDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.AlarmDate; if (alarmDate.IsDateEqual(now)) { doAlarm = true; continueNext = false; } break; case ScheduleType.After: start = _Schedule.StartFrom == ScheduleStart.ExactTime ? (changeZone ? TimeZoneInfo.ConvertTime(_Schedule.StartDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.StartDate) : PNStatic.StartTime; PNStatic.NormalizeStartDate(ref start); seconds = (now - start).Ticks / TimeSpan.TicksPerSecond; if (seconds == _Schedule.AlarmAfter.TotalSeconds) { doAlarm = true; continueNext = false; } break; case ScheduleType.RepeatEvery: if (_Schedule.LastRun == DateTime.MinValue) { start = _Schedule.StartFrom == ScheduleStart.ExactTime ? (changeZone ? TimeZoneInfo.ConvertTime(_Schedule.StartDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.StartDate) : PNStatic.StartTime; } else { start = _Schedule.LastRun; } PNStatic.NormalizeStartDate(ref start); seconds = (now - start).Ticks / TimeSpan.TicksPerSecond; if (seconds == _Schedule.AlarmAfter.TotalSeconds || (seconds > 0 && seconds % _Schedule.AlarmAfter.TotalSeconds == 0)) { doAlarm = true; } break; case ScheduleType.EveryDay: alarmDate = changeZone ? TimeZoneInfo.ConvertTime(_Schedule.AlarmDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.AlarmDate; if (alarmDate.IsTimeEqual(now) && (_Schedule.LastRun == DateTime.MinValue || _Schedule.LastRun <= now.AddDays(-1))) { doAlarm = true; } break; case ScheduleType.Weekly: alarmDate = changeZone ? TimeZoneInfo.ConvertTime(_Schedule.AlarmDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.AlarmDate; if (alarmDate.IsTimeEqual(now)) { if (_Schedule.Weekdays.Contains(now.DayOfWeek) && (_Schedule.LastRun == DateTime.MinValue || _Schedule.LastRun <= now.AddDays(-1))) { doAlarm = true; } } break; case ScheduleType.MonthlyExact: alarmDate = changeZone ? TimeZoneInfo.ConvertTime(_Schedule.AlarmDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.AlarmDate; if (alarmDate.Day == now.Day) { if (alarmDate.IsTimeEqual(now)) { if (_Schedule.LastRun == DateTime.MinValue || _Schedule.LastRun.Month < now.Month || _Schedule.LastRun.Year < now.Year) { doAlarm = true; } } } break; case ScheduleType.MonthlyDayOfWeek: if (now.DayOfWeek == _Schedule.MonthDay.WeekDay) { alarmDate = changeZone ? TimeZoneInfo.ConvertTime(_Schedule.AlarmDate, TimeZoneInfo.Local, _Schedule.TimeZone) : _Schedule.AlarmDate; if (alarmDate.IsTimeEqual(now)) { bool isLast = false; int ordinal = PNStatic.WeekdayOrdinal(now, _Schedule.MonthDay.WeekDay, ref isLast); if (_Schedule.MonthDay.OrdinalNumber == DayOrdinal.Last) { if (isLast) { if (_Schedule.LastRun == DateTime.MinValue || _Schedule.LastRun.Month < now.Month || _Schedule.LastRun.Year < now.Year) { doAlarm = true; } } } else { if ((int)_Schedule.MonthDay.OrdinalNumber == ordinal) { if (_Schedule.LastRun == DateTime.MinValue || _Schedule.LastRun.Month < now.Month || _Schedule.LastRun.Year < now.Year) { doAlarm = true; } } } } } break; case ScheduleType.MultipleAlerts: foreach (var ma in _Schedule.MultiAlerts.Where(a => !a.Raised)) { alarmDate = changeZone ? TimeZoneInfo.ConvertTime(ma.Date, TimeZoneInfo.Local, _Schedule.TimeZone) : ma.Date; if (!alarmDate.IsDateEqual(now)) continue; ma.Checked = true; doAlarm = true; break; } break; } if (doAlarm) { if (!PNStatic.FormMain.Dispatcher.CheckAccess()) { _ElapsedDelegate d = _Timer_Elapsed; PNStatic.FormMain.Dispatcher.Invoke(d, sender, e); } else { bool save = false; switch (_Schedule.Type) { case ScheduleType.EveryDay: case ScheduleType.RepeatEvery: case ScheduleType.Weekly: case ScheduleType.MonthlyExact: case ScheduleType.MonthlyDayOfWeek: _Schedule.LastRun = now; save = true; break; case ScheduleType.MultipleAlerts: var ma = _Schedule.MultiAlerts.FirstOrDefault(a => a.Checked); if (ma != null) { ma.Checked = false; ma.Raised = true; } save = true; break; } PNStatic.FormMain.ApplyDoAlarm(this); if (save) { PNNotesOperations.SaveNoteSchedule(this); } if (!continueNext) { PNNotesOperations.DeleteNoteSchedule(this); } } } } catch (Exception ex) { PNStatic.LogException(ex); } finally { if (continueNext) { _Timer.Start(); } } }