From 87853957eead51ca30b22030072d04dc27eaa078 Mon Sep 17 00:00:00 2001
From: Luis Kornblueh <luis.kornblueh@mpimet.mpg.de>
Date: Wed, 22 Apr 2020 15:50:29 +0200
Subject: [PATCH] Fix wrong first trigger in complex event handling

---
 src/mtime_eventHandling.c | 394 +++++++++++++++++++-------------------
 1 file changed, 198 insertions(+), 196 deletions(-)

diff --git a/src/mtime_eventHandling.c b/src/mtime_eventHandling.c
index 65aadde1..fe9e3899 100644
--- a/src/mtime_eventHandling.c
+++ b/src/mtime_eventHandling.c
@@ -41,7 +41,7 @@ static int64_t EVENTID = 0;
  *         A pointer to char. This string contains the name of event group.
  *
  * @return eg
- *         A pointer to a initialized event-Group. 
+ *         A pointer to a initialized event-Group.
  *
  */
 
@@ -188,10 +188,10 @@ getEventGroupRootEvent(struct _eventGroup* eg)
   /**
    * @brief Construct new event using strings.
    *
-   * To initialize an event, the event name and event interval must be specified. The reference date 
+   * To initialize an event, the event name and event interval must be specified. The reference date
    * (also known as the anchor-date), start date and event last date are optional. If first date is not
-   * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date 
-   * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent 
+   * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date
+   * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent
    * to Infinity.
    *
    * Notice that events trigger every _eventReferenceDT + Integral multiple of _eventInterval strictly in [_eventFirstDT,_eventLastDT].
@@ -204,7 +204,7 @@ getEventGroupRootEvent(struct _eventGroup* eg)
    *         This can be NULL in which case Anchor Date = First Date.
    *
    * @param  _eventFirstDT
-   *         A pointer to char. This string contains the Starting datetime (A) of the DateTime range [A-B] in which trigger is allowed. 
+   *         A pointer to char. This string contains the Starting datetime (A) of the DateTime range [A-B] in which trigger is allowed.
    *         Can be NULL.
    *
    * @param  _eventLastDT
@@ -219,16 +219,16 @@ getEventGroupRootEvent(struct _eventGroup* eg)
    *         A pointer to char. This string contains the timestep. This must be defined for every event.
    *
    * @return e
-   *         A pointer to an initialized event. 
+   *         A pointer to an initialized event.
    *
    */
 
 struct _event*
-newEvent(const char* _en, 
-	 const char* _eventReferenceDT, 
-	 const char* _eventFirstDT, 
-	 const char* _eventLastDT, 
-	 const char* _eventInterval, 
+newEvent(const char* _en,
+	 const char* _eventReferenceDT,
+	 const char* _eventFirstDT,
+	 const char* _eventLastDT,
+	 const char* _eventInterval,
 	 const char* _eventOffset)
 {
   if ((_en != NULL) &&  (_eventInterval != NULL) && getCalendarType())
@@ -253,7 +253,7 @@ newEvent(const char* _en,
 
   /* Last evaluation date */
   e->eventsLastEvaluationDateTime = NULL;
-  
+
   /* Start Date. */
   if (_eventFirstDT)
     e->eventFirstDateTime = newDateTime(_eventFirstDT);
@@ -284,7 +284,7 @@ newEvent(const char* _en,
   else
     {
       e->eventLastDateTime = NULL; // Logically equivalent to Inf.
-    } 
+    }
 
   /* _eventInterval must be defined. */
   e->eventInterval = newTimeDelta(_eventInterval);
@@ -295,12 +295,12 @@ newEvent(const char* _en,
       && e->eventInterval->hour == 0 && e->eventInterval->minute == 0 && e->eventInterval->second == 0 && e->eventInterval->ms == 0)
     {
       e->neverTriggerEvent   = true;
-      
+
       e->triggerCurrentEvent = false;
 
       e->nextEventIsFirst    = false;
       e->lastEventWasFinal   = false;
-      
+
       e->eventisFirstInDay   = false;
       e->eventisFirstInMonth = false;
       e->eventisFirstInYear  = false;
@@ -309,8 +309,8 @@ newEvent(const char* _en,
       e->eventisLastInYear   = false;
 
       /* Removed to prevent segfaults ... deallocateTimeDelta(e->eventInterval); */
-      
-      e->eventOffset = NULL;      
+
+      e->eventOffset = NULL;
       e->triggeredPreviousEventDateTime = NULL;
       e->triggerNextEventDateTime = NULL;
 
@@ -333,7 +333,7 @@ newEvent(const char* _en,
 
   e->triggerNextEventDateTime = newDateTime(initDummyDTString);
   /* triggerNextEventDateTime holds the DateTime when an event should be triggered subjectively (i.e assuming real time starts at -Inf and moves fwd.)
-     At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger. 
+     At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger.
      Events trigger at e->eventReferenceDateTime (+ e-> eventOffset ) + N * e->eventInterval where N is a positive, negative integer.
      Hence, first trigger happens at the nearest possible trigger >= e->eventFirstDateTime. */
   if (!getEventFirstTriggerDateTime(e->eventFirstDateTime, e->eventInterval, e->eventOffset, e->eventReferenceDateTime, e->triggerNextEventDateTime))
@@ -341,7 +341,7 @@ newEvent(const char* _en,
 
   /* Init the Flags. */
   e->neverTriggerEvent          = false;
-  
+
   e->triggerCurrentEvent 	= false;
 
   e->nextEventIsFirst 		= true;
@@ -391,10 +391,10 @@ newEvent(const char* _en,
   /**
    * @brief Construct new event using data-types.
    *
-   * To initialize an event, the event name and event interval must be specified. The reference date 
+   * To initialize an event, the event name and event interval must be specified. The reference date
    * (also known as the anchor-date), start date and event last date are optional. If first date is not
-   * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date 
-   * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent 
+   * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date
+   * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent
    * to Infinity.
    *
    * Notice that events trigger every _eventReferenceDT + Integral multiple of _eventInterval strictly in [_eventFirstDT,_eventLastDT].
@@ -402,7 +402,7 @@ newEvent(const char* _en,
    * @param  _en
    *         A pointer to char. This string contains the name of event.
    * @param  _eventReferenceDT
-   *         A pointer to struct _datetime. This pointer contains the First Reference date also called anchor date. 
+   *         A pointer to struct _datetime. This pointer contains the First Reference date also called anchor date.
    *         This can be NULL, but if defined acts as the true starting datetime overriding e->eventFirstDateTime.
    * @param  _eventFirstDT
    *         A pointer to struct _datetime. This pointer contains the Starting datetime. This must be defined for every Event.
@@ -412,16 +412,16 @@ newEvent(const char* _en,
    * @param  _eventInterval
    *         A pointer to struct _timedelta. This pointer contains the timestep. This must be defined for every event.
    * @return e
-   *         A pointer to an initialized event. 
+   *         A pointer to an initialized event.
    *
    */
 
 struct _event*
-newEventWithDataType(const char* _en, 
-			struct _datetime*  _eventReferenceDT, 
-			struct _datetime*  _eventFirstDT, 
-			struct _datetime*  _eventLastDT, 
-			struct _timedelta* _eventInterval, 
+newEventWithDataType(const char* _en,
+			struct _datetime*  _eventReferenceDT,
+			struct _datetime*  _eventFirstDT,
+			struct _datetime*  _eventLastDT,
+			struct _timedelta* _eventInterval,
 			struct _timedelta* _eventOffset)
 {
   if ((_en != NULL) &&  (_eventInterval != NULL) && getCalendarType())
@@ -475,12 +475,12 @@ newEventWithDataType(const char* _en,
       && _eventInterval->hour == 0 && _eventInterval->minute == 0 && _eventInterval->second == 0 && _eventInterval->ms == 0)
     {
       e->neverTriggerEvent   = true;
-      
+
       e->triggerCurrentEvent = false;
 
       e->nextEventIsFirst    = false;
       e->lastEventWasFinal   = false;
-      
+
       e->eventisFirstInDay   = false;
       e->eventisFirstInMonth = false;
       e->eventisFirstInYear  = false;
@@ -489,20 +489,20 @@ newEventWithDataType(const char* _en,
       e->eventisLastInYear   = false;
 
       /* Added to prevent segfaults ... */
-      e->eventInterval = constructAndCopyTimeDelta(_eventInterval);      
-      e->eventOffset = NULL;      
+      e->eventInterval = constructAndCopyTimeDelta(_eventInterval);
+      e->eventOffset = NULL;
       e->triggeredPreviousEventDateTime = NULL;
       e->triggerNextEventDateTime = NULL;
 
       return e;
     }
-  
+
   /* _eventInterval must be defined. */
   e->eventInterval = constructAndCopyTimeDelta(_eventInterval);
   if (e->eventInterval == NULL)
     goto cleanup_and_exit;
 
-  
+
   /* Event trigger offset. */
   if (_eventOffset)
     e->eventOffset = constructAndCopyTimeDelta(_eventOffset);
@@ -516,7 +516,7 @@ newEventWithDataType(const char* _en,
 
   e->triggerNextEventDateTime = newDateTime(initDummyDTString);
   /* triggerNextEventDateTime holds the DateTime when an event should be triggered subjectively (i.e assuming real time starts at -Inf and moves fwd.)
-     At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger. 
+     At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger.
      Events trigger at e->eventReferenceDateTime (+ e->eventOffset) + N*e->eventInterval where N is a positive, negative or zero integer.
      Hence, first trigger happens at the nearest possible trigger >= e->eventFirstDateTime. */
   if (!getEventFirstTriggerDateTime(e->eventFirstDateTime, e->eventInterval, e->eventOffset, e->eventReferenceDateTime, e->triggerNextEventDateTime))
@@ -614,10 +614,10 @@ struct _event*
 constructAndCopyEvent(struct _event* ev)
 {
   struct _event* ev_copy;
-  
+
   if ( ev != NULL )
     {
-      ev_copy = newEventWithDataType(ev->eventName, 
+      ev_copy = newEventWithDataType(ev->eventName,
                                      ev->eventReferenceDateTime,
                                      ev->eventFirstDateTime,
                                      ev->eventLastDateTime,
@@ -625,21 +625,21 @@ constructAndCopyEvent(struct _event* ev)
                                      ev->eventOffset);
 
       ev_copy->eventId = ev->eventId;
-      ev_copy->nextEventInGroup = ev->nextEventInGroup;      
-      
-      ev_copy->neverTriggerEvent =   ev->neverTriggerEvent;  
+      ev_copy->nextEventInGroup = ev->nextEventInGroup;
+
+      ev_copy->neverTriggerEvent =   ev->neverTriggerEvent;
       ev_copy->triggerCurrentEvent = ev->triggerCurrentEvent;
-                                                    
-      ev_copy->nextEventIsFirst =    ev->nextEventIsFirst;   
-      ev_copy->lastEventWasFinal =   ev->lastEventWasFinal;  
-                                                    
-                                                    
-      ev_copy->eventisFirstInDay =   ev->eventisFirstInDay;  
+
+      ev_copy->nextEventIsFirst =    ev->nextEventIsFirst;
+      ev_copy->lastEventWasFinal =   ev->lastEventWasFinal;
+
+
+      ev_copy->eventisFirstInDay =   ev->eventisFirstInDay;
       ev_copy->eventisFirstInMonth = ev->eventisFirstInMonth;
-      ev_copy->eventisFirstInYear =  ev->eventisFirstInYear; 
-      ev_copy->eventisLastInDay =    ev->eventisLastInDay;   
-      ev_copy->eventisLastInMonth =  ev->eventisLastInMonth; 
-      ev_copy->eventisLastInYear =   ev->eventisLastInYear;  
+      ev_copy->eventisFirstInYear =  ev->eventisFirstInYear;
+      ev_copy->eventisLastInDay =    ev->eventisLastInDay;
+      ev_copy->eventisLastInMonth =  ev->eventisLastInMonth;
+      ev_copy->eventisLastInYear =   ev->eventisLastInYear;
 
       ev_copy->triggeredPreviousEventDateTime = constructAndCopyDateTime(ev->triggeredPreviousEventDateTime);
       ev_copy->triggerNextEventDateTime = constructAndCopyDateTime(ev->triggerNextEventDateTime);
@@ -655,7 +655,7 @@ constructAndCopyEvent(struct _event* ev)
 
 /* INTERNAL FUNCTION. */
 //Get if trigger is true. Trigger true in [T-minus_slack,T+plus_slack].
-static 
+static
 compare_return_val
 isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNextEventDateTime, struct _timedelta* plus_slack, struct _timedelta* minus_slack)
 {
@@ -692,7 +692,7 @@ isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNext
       upper_val_flag = compareDatetime(current_dt,addTimeDeltaToDateTime(triggerNextEventDateTime,plus_slack_local,dt_upperbound));
       lower_val_flag = compareDatetime(current_dt,addTimeDeltaToDateTime(triggerNextEventDateTime,minus_slack_local,dt_lowerbound));
 
-      if ( 
+      if (
            (upper_val_flag == less_than || upper_val_flag == equal_to)
            &&
            (lower_val_flag == greater_than || lower_val_flag == equal_to)
@@ -717,7 +717,7 @@ isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNext
     {
       cmp_val_flag = compareDatetime(current_dt,triggerNextEventDateTime);
     }
-   
+
   deallocateTimeDelta(plus_slack_local);
   deallocateTimeDelta(minus_slack_local);
 
@@ -728,7 +728,7 @@ isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNext
 /**
  * @brief Check if this event is active by comparing event's trigger time with current_dt.
  *
- *        The current_dt must lie in event's trigger time 
+ *        The current_dt must lie in event's trigger time
  *        (subject to optional specified slack: [Trigger_time - minus_slack, Trigger_time + plus_slack]. Slacks can be NULL. Always inclusive.)
  *        The lib has no built-in clock but relies on isCurrentEventActive(.) being called (polled) from the application at fixed intervals.
  *
@@ -739,11 +739,11 @@ isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNext
  *         A pointer to struct _datetime. This is the 'current' datetime of the system.
  *
  * @param  plus_slack
- *         A pointer to struct _timedelta. Events are triggered between [actual_trigger_time, actual_trigger_time + plus_slack]. 
+ *         A pointer to struct _timedelta. Events are triggered between [actual_trigger_time, actual_trigger_time + plus_slack].
  * 	   Can be NULL; logically 0. Sign MUST be '+'
  *
  * @param  minus_slack
- *         A pointer to struct _timedelta. Events are triggered between [actual_trigger_time - minus_slack, actual_trigger_time]. 
+ *         A pointer to struct _timedelta. Events are triggered between [actual_trigger_time - minus_slack, actual_trigger_time].
  *         Can be NULL; logically 0. Sign MUST be '+'
  *
  * @return bool
@@ -753,16 +753,16 @@ isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNext
 bool
 isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct _timedelta* plus_slack, struct _timedelta* minus_slack)
 {
-  
+
   if ((event != NULL ) && (current_dt != NULL)) { // allowed slacks can be NULL.
-    
+
     if (event->neverTriggerEvent)
       {
         return false;
       }
 
     /* If Event has been triggered for a datetime and checked once again return that state */
-    
+
     if (event->eventsLastEvaluationDateTime != NULL)
       {
 	if (compareDatetime(current_dt, event->eventsLastEvaluationDateTime) == equal_to)
@@ -770,7 +770,7 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
 	    return true;
 	  }
       }
-    
+
     /* Reset flags. */
     event->triggerCurrentEvent        = false;
 
@@ -780,7 +780,7 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
     event->eventisLastInDay           = false;
     event->eventisLastInMonth         = false;
     event->eventisLastInYear          = false;
-   
+
     //++++++++ Events trigger [start-end]. Slack is ignored outside this range. ++++++++++//
     /* If current_dt is yet not in trigger range, Return on false. */
     if (compareDatetime(current_dt,event->eventFirstDateTime) == less_than)
@@ -791,12 +791,12 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
 	/* If current_dt > event->eventLastDateTime and the event has never triggered, event->lastEventWasFinal should stay false. */
 	if(!event->nextEventIsFirst)
 	  event->lastEventWasFinal = true;  //No further trigger possible.
-	
+
 	return false;
       }
 
 
-    /* In case the current_dt is ahead of event->triggerNextEventDateTime, we need to update the event->triggerNextEventDateTime 
+    /* In case the current_dt is ahead of event->triggerNextEventDateTime, we need to update the event->triggerNextEventDateTime
        to the next possible trigger time or else the events will never trigger. */
     if (isTriggerTimeInRange(current_dt, event->triggerNextEventDateTime, plus_slack, NULL) == greater_than)
       {
@@ -812,7 +812,7 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
     if( (!event->lastEventWasFinal) && (isTriggerTimeInRange(current_dt, event->triggerNextEventDateTime, plus_slack, minus_slack) == equal_to) )
       {
 	/* If current Datetime is equal to next trigger datetime, Event is active. */
-	
+
 	/* If the event being triggred is the first event to be triggered, it is all of FirstIn*  */
 	/* If previous triggered event had a different day/month/year, this event must be FirstIn* */
 	if( (event->nextEventIsFirst == true) || (iseventNextInNextDay(event) == true))
@@ -827,7 +827,7 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
 	  {
 	    event->eventisFirstInYear = true;
 	  }
-	
+
 	/* Set previous-triggered-datetime to now. */
 	replaceDatetime(current_dt, event->triggeredPreviousEventDateTime);
 
@@ -836,48 +836,48 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
 
 	/* Set the new next-trigger datetime. If eventLastDateTime is defined, then update should not happen
 	   if current_dt + eventInterval > eventLastDateTime */
-	if ( 
-            !( event->eventLastDateTime 
-               && 
-               ( 
-		( cmp_val_flag = isTriggerTimeInRange ( addTimeDeltaToDateTime(current_dt, event->eventInterval,tmp_dt), 
-							event->eventLastDateTime, 
+	if (
+            !( event->eventLastDateTime
+               &&
+               (
+		( cmp_val_flag = isTriggerTimeInRange ( addTimeDeltaToDateTime(current_dt, event->eventInterval,tmp_dt),
+							event->eventLastDateTime,
 							NULL,
 							minus_slack
 							)
-		  ) == greater_than 
+		  ) == greater_than
 		 )
 	       )
-	     ) 
+	     )
 	  {
 	    addTimeDeltaToDateTime(event->triggerNextEventDateTime,event->eventInterval,event->triggerNextEventDateTime);
 	  }
 	else
 	  event->lastEventWasFinal = true;
-	
+
 	deallocateDateTime(tmp_dt); // Cleanup.
-	
+
 	/* Set event.*/
-	event->triggerCurrentEvent = true;      
+	event->triggerCurrentEvent = true;
 
 
 	/* If the future event (not the current event being triggered) has a different day/month/year, current event must be LastIn*.
 	   Notice that triggerNextEventDateTime is now the FUTURE event after the update above. */
 	if (
-	    (	event->eventLastDateTime 
-		&& 
+	    (	event->eventLastDateTime
+		&&
 		(cmp_val_flag == greater_than)
-		) 
-	    || 
+		)
+	    ||
 	    (iseventNextInNextDay(event) == true)
 	    )
 	  {
 	    event->eventisLastInDay = true;
 	  }
-	
+
 	if(
-	   ( event->eventLastDateTime 
-	     && 
+	   ( event->eventLastDateTime
+	     &&
 	     (cmp_val_flag == greater_than)
 	     )
 	   ||
@@ -885,13 +885,13 @@ isCurrentEventActive(struct _event* event, struct _datetime* current_dt, struct
 	  {
 	    event->eventisLastInMonth = true;
 	  }
-	
+
 	if (
-	    ( event->eventLastDateTime 
-	      && 
+	    ( event->eventLastDateTime
+	      &&
 	      (cmp_val_flag == greater_than)
               )
-	    || 
+	    ||
 	    (iseventNextInNextYear(event) == true))
 	  {
 	    event->eventisLastInYear = true;
@@ -999,7 +999,7 @@ iseventNextInNextYear(struct _event* e)
 
       d_next->day = 1;
       d_next->month = 1;
-      
+
       d_prev->day = 1;
       d_prev->month = 1;
 
@@ -1048,7 +1048,7 @@ eventToString(struct _event* e, char* string)
           return string;
 	}
       else
-	{  
+	{
 	   //TODO.
 	   ;
 	}
@@ -1059,24 +1059,24 @@ eventToString(struct _event* e, char* string)
 }
 
 
-/* Calculate the first trigger time. First trigger is the nearest allowed trigger time >= start_dt. 
+/* Calculate the first trigger time. First trigger is the nearest allowed trigger time >= start_dt.
    Triggers are allowd only ref_dt + N * timestep where N can be positive, negative or 0. */
-static 
+static
 struct _datetime*
 getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* timestep, struct _timedelta* offset, struct _datetime* ref_dt, struct _datetime* first_trigger_dt)
 {
   if ((start_dt != NULL) && (timestep != NULL) && (ref_dt != NULL) && (first_trigger_dt != NULL) ) //offset can be NULL.
-    { 
+    {
 
       if (timestep->year != 0 && timestep->month == 0 && timestep->day == 0
           && timestep->hour == 0 && timestep->minute == 0 && timestep->second == 0 && timestep->ms == 0)
         {
           /* NOTE: years only is a trivial case. */
-          
+
           /* Get anchor. ref + offset is the real anchor. */
           struct _datetime *anchor = constructAndCopyDateTime(ref_dt);
-          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. 
-          
+          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place.
+
 	  if (compareDatetime(anchor, start_dt) == greater_than)
 	    {
 	      replaceDatetime(anchor, first_trigger_dt);
@@ -1086,19 +1086,19 @@ getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* time
 	      /* Determine difference between anchor and start year */
 	      int64_t differenceOfYears = start_dt->date.year - anchor->date.year; // result always >= 0.
 	      int64_t yearsToAdd = differenceOfYears % timestep->year;
-          
+
 	      /* We only need to update the year */
 	      replaceDatetime(anchor, first_trigger_dt);
 	      first_trigger_dt->date.year += yearsToAdd;
 	    }
-	      
+
           /* Cleanup. */
           deallocateDateTime(anchor);
 
           /* And return. */
           return first_trigger_dt;
         }
-      
+
       else if (timestep->year == 0 && timestep->month != 0 && timestep->day == 0
                && timestep->hour == 0 && timestep->minute == 0 && timestep->second == 0 && timestep->ms == 0)
         {
@@ -1106,7 +1106,7 @@ getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* time
 
           /* Get anchor. ref + offset is the real anchor. */
           struct _datetime *anchor = constructAndCopyDateTime(ref_dt);
-          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. 
+          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place.
 
 	  if (compareDatetime(anchor, start_dt) == greater_than)
 	    {
@@ -1125,223 +1125,225 @@ getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* time
 	      first_trigger_dt->date.year += yearsToAdd;
 	      first_trigger_dt->date.month += monthsToAdd;
 	    }
-	      
+
           /* Cleanup. */
           deallocateDateTime(anchor);
 
           /* And return. */
           return first_trigger_dt;
         }
-      
+
       else if (timestep->year == 0 && timestep->month == 0)
-        
+
         {
-          /* NOTE: This code is higly 'rigged', to a point where it might feel micromanaged.   
+          /* NOTE: This code is higly 'rigged', to a point where it might feel micromanaged.
              This is to speed-up the event-init process. Without the hack, the code
-             will be too slow and hence the ends justify the means. 
+             will be too slow and hence the ends justify the means.
           */
 
           struct _timedelta* timestep_bkw;
-          
+
           /* Get start date in julian. */
           struct _julianday* start_jd = newJulianDay(0, 0);
           start_jd = date2julian(start_dt, start_jd);
-          
-          
+
+
           /* Get timedelta in juliandelta. */
           struct _juliandelta* timestep_jd = newJulianDelta('+', 0, 0);
           timestep_jd = timeDeltaToJulianDelta(timestep, ref_dt, timestep_jd);
-          
-          
+
+
           /* For speed-up */
           struct _juliandelta* timestep_fastfwd_jd = newJulianDelta('+', 0, 0);
           struct _juliandelta* timestep_fastbkw_jd = newJulianDelta('+', 0, 0);
-          
-          
+
+
           /* Get anchor. ref + offset is the real anchor. */
           struct _datetime* anchor = constructAndCopyDateTime(ref_dt);
-          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. 
-          
+          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place.
+
           /* Get anchor in julian. */
           struct _julianday* anchor_jd = newJulianDay(0, 0);
           anchor_jd = date2julian(anchor, anchor_jd);
-          
+
           /* Optimization hack: Calculate an approx metric are_dates_too_far and speed up the jumps.  */
           int64_t are_dates_too_far = 0;
           if (timestep_jd->day)
-            are_dates_too_far = (start_jd->day - anchor_jd->day)/(timestep_jd->day); 
+            are_dates_too_far = (start_jd->day - anchor_jd->day)/(timestep_jd->day);
           else if (timestep_jd->ms)
             are_dates_too_far = (start_jd->day - anchor_jd->day)/((float)timestep_jd->ms/NO_OF_MS_IN_A_DAY);
           //else ... well, should never happen. If it does, the initialized value of zero persists.
-          
-          
+
+
           int lambda = 1; //speed-up const. Default is 1 or no speedup.
           if (are_dates_too_far>10 || are_dates_too_far<-10)
-            lambda = 100000; //speed up if start-date and anchor are 'too-far' away. 
-          
-          
+            lambda = 100000; //speed up if start-date and anchor are 'too-far' away.
+
+
           /* Fast-Fwd */
           timestep_fastfwd_jd->day = lambda*timestep_jd->day;
           timestep_fastfwd_jd->ms  = lambda*timestep_jd->ms;
-          
+
           while( timestep_fastfwd_jd->ms >= NO_OF_MS_IN_A_DAY )
             {
               timestep_fastfwd_jd->day++;
               timestep_fastfwd_jd->ms = timestep_fastfwd_jd->ms - NO_OF_MS_IN_A_DAY;
             }
-          
-          
+
+
           /* We need to Loop backwards: Create a timestep replica and change the sign to negative to travel-back-in-time. */
           timestep_bkw = constructAndCopyTimeDelta(timestep);
           timestep_bkw->sign = '-';
-          
+
           struct _juliandelta* timestep_bkw_jd = newJulianDelta('+', 0, 0);
           timeDeltaToJulianDelta(timestep_bkw, ref_dt, timestep_bkw_jd);
-          
+
           /* Fast-Bkwd */
           timestep_fastbkw_jd->day = lambda*timestep_bkw_jd->day;
           timestep_fastbkw_jd->ms  = lambda*timestep_bkw_jd->ms;
-          
+
           while( timestep_fastbkw_jd->ms <=  (-1)*(NO_OF_MS_IN_A_DAY) )
             {
               timestep_fastbkw_jd->day--;
               timestep_fastbkw_jd->ms = timestep_fastbkw_jd->ms + NO_OF_MS_IN_A_DAY;
             }
-          
-          
+
+
           switch (compareDatetime(start_dt,ref_dt))
-            { 
-            case greater_than: /* start_dt > ref_dt */      
-              
-              /* Jump very fast and reach the start date quickly. */
-              do
+            {
+            case greater_than: /* start_dt > ref_dt */
+
+              if (lambda != 1)
                 {
-                  anchor_jd->day = anchor_jd->day + timestep_fastfwd_jd->day;
-                  anchor_jd->ms  = anchor_jd->ms  + timestep_fastfwd_jd->ms;
-                  
-                  if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY)
+
+                  /* Jump very fast and reach the start date quickly. */
+                  do
                     {
-                      anchor_jd->day = anchor_jd->day + 1;
-                      anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY;
+                      anchor_jd->day = anchor_jd->day + timestep_fastfwd_jd->day;
+                      anchor_jd->ms  = anchor_jd->ms  + timestep_fastfwd_jd->ms;
+
+                      if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY)
+                        {
+                          anchor_jd->day = anchor_jd->day + 1;
+                          anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY;
+                        }
+
+                    } while ( !((anchor_jd->day > start_jd->day)  ||  (anchor_jd->day == start_jd->day && anchor_jd->ms > start_jd->ms)) );
+
+
+                  /* But I jumped one time too much. Move back */
+                  anchor_jd->day = anchor_jd->day - timestep_fastfwd_jd->day;
+                  anchor_jd->ms  = anchor_jd->ms  - timestep_fastfwd_jd->ms;
+
+                  if (anchor_jd->ms < 0)
+                    {
+                      anchor_jd->day = anchor_jd->day - 1;
+                      anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY;
                     }
-                  
-                } while ( !((anchor_jd->day > start_jd->day)  ||  (anchor_jd->day == start_jd->day && anchor_jd->ms > start_jd->ms)) );
-              
-              
-              /* But I jumped one time too much. Move back */
-              anchor_jd->day = anchor_jd->day - timestep_fastfwd_jd->day;
-              anchor_jd->ms  = anchor_jd->ms  - timestep_fastfwd_jd->ms;
-              
-              if (anchor_jd->ms < 0)
-                {
-                  anchor_jd->day = anchor_jd->day - 1;
-                  anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY;
                 }
-              
-              
-              
+
               /* I am close. Now determine the actual time. */
               do
                 {
                   anchor_jd->day = anchor_jd->day + timestep_jd->day;
                   anchor_jd->ms = anchor_jd->ms + timestep_jd->ms;
-                  
+
                   if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY)
                     {
                       anchor_jd->day = anchor_jd->day + 1;
                       anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY;
                     }
-                  
+
                 } while ( !((anchor_jd->day > start_jd->day)  ||  (anchor_jd->day == start_jd->day && anchor_jd->ms >= start_jd->ms)) );
-              
+
               /* anchor_jd is now the true event-trigger-time. Set it to anchor. */
               julian2date(anchor_jd,anchor);
-              
+
               break;
-              
+
             case equal_to: /* start_dt == ref_dt */
-              
+
               break;
-              
+
             case less_than: /* start_dt < ref_dt */
-             
-              
+
+
               /* Jump very fast bkwd and reach the start date quickly. */
               do
                 {
                   anchor_jd->day = anchor_jd->day + timestep_fastbkw_jd->day;
                   anchor_jd->ms = anchor_jd->ms + timestep_fastbkw_jd->ms;
-                  
+
                   if ( anchor_jd->ms < 0 )
                     {
                       anchor_jd->day = anchor_jd->day - 1;
                       anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY;
                     }
-                  
+
                 } while(! (anchor_jd->day < start_jd->day  ||  (anchor_jd->day == start_jd->day && anchor_jd->ms < start_jd->ms)) );
-              
-              
+
+
               /* I jumped one time too much. Move forward. */
               anchor_jd->day = anchor_jd->day + timestep_fastfwd_jd->day;
               anchor_jd->ms = anchor_jd->ms + timestep_fastfwd_jd->ms;
-              
+
               if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY)
                 {
                   anchor_jd->day = anchor_jd->day + 1;
                   anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY;
                 }
-              
-              
+
+
               /* I am close. Get the real time. */
               do
                 {
                   anchor_jd->day = anchor_jd->day + timestep_bkw_jd->day;
                   anchor_jd->ms = anchor_jd->ms + timestep_bkw_jd->ms;
-                  
+
                   if ( anchor_jd->ms < 0 )
                     {
                       anchor_jd->day = anchor_jd->day - 1;
                       anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY;
                     }
-                  
+
                 } while(! (anchor_jd->day < start_jd->day  ||  (anchor_jd->day == start_jd->day && anchor_jd->ms < start_jd->ms)) );
-              
-              
+
+
               /* I jumped one time too much. Move forward.  */
               anchor_jd->day = anchor_jd->day + timestep_jd->day;
               anchor_jd->ms = anchor_jd->ms + timestep_jd->ms;
-              
+
               if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY)
                 {
                   anchor_jd->day = anchor_jd->day + 1;
                   anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY;
                 }
-              
+
               /* anchor_jd now has the true trigger time. Copy it to anchor. */
               julian2date(anchor_jd,anchor);
-              
+
             default:
-              
+
               ; //Should never happen. Don't return NULL just yet as deallocateDateTime(anchor) still needs to be called.
-              
+
             }
-          
+
           /* Copy the contents to target. */
           replaceDatetime(anchor,first_trigger_dt);
-          
-          
+
+
           /* Cleanup. */
-          
+
           deallocateDateTime(anchor);
           deallocateJulianDay(start_jd);
           deallocateJulianDay(anchor_jd);
           deallocateJulianDelta(timestep_jd);
           deallocateTimeDelta(timestep_bkw);
           deallocateJulianDelta(timestep_bkw_jd);
-          
+
           deallocateJulianDelta(timestep_fastfwd_jd);
           deallocateJulianDelta(timestep_fastbkw_jd);
-          
+
           /* And return. */
           return first_trigger_dt;
         }
@@ -1351,20 +1353,20 @@ getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* time
 
           /* Get anchor. ref + offset is the real anchor. */
           struct _datetime *anchor = constructAndCopyDateTime(ref_dt);
-          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. 
+          addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place.
 
           while (compareDatetime(anchor, start_dt) == less_than)
             {
               addTimeDeltaToDateTime(anchor, timestep, anchor);
-            } 
+            }
           /* Copy the contents to target. */
           replaceDatetime(anchor,first_trigger_dt);
-          
+
           /* Cleanup. */
           deallocateDateTime(anchor);
 
           /* And return. */
-          return first_trigger_dt;          
+          return first_trigger_dt;
         }
     }
   else
@@ -1392,12 +1394,12 @@ getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* current_dt, st
 {
   if ((e != NULL) && (current_dt != NULL) && (dt_return != NULL))
     {
-       /* If last date is defined, check if current_dt is ahead of event->eventLastDateTime. 
+       /* If last date is defined, check if current_dt is ahead of event->eventLastDateTime.
           Return on NULL indicating no future trigger event scheduled.*/
       if (e->eventLastDateTime && (compareDatetime(current_dt,e->eventLastDateTime) == greater_than))
         return NULL;
 
-      /* This if should evaluate to false normally. The only occasion when it does not is if the 
+      /* This if should evaluate to false normally. The only occasion when it does not is if the
          current_dt > triggerNextEventDateTime and isCurrentEventActive(.) has never been called  */
       if (
            (e->nextEventIsFirst)
@@ -1409,14 +1411,14 @@ getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* current_dt, st
               // Get the first trigger time and return (WARNING: Do not update e->triggerNextEventDateTime here!).
               moduloTimeDeltaFromDateTime(e->triggerNextEventDateTime, e->eventInterval, current_dt, modulo_td);
               addTimeDeltaToDateTime(current_dt,modulo_td,dt_return);
-              // Cleanup. 
+              // Cleanup.
               deallocateTimeDelta(modulo_td);
               return dt_return;
         }
       // else ...
       dt_return = replaceDatetime(e->triggerNextEventDateTime, dt_return);
       return dt_return;
-    } 
+    }
   else
     return NULL;
 }
@@ -1441,7 +1443,7 @@ getTriggeredPreviousEventAtDateTime(struct _event* e, struct _datetime* dt_retur
     {
       /* No trigger ever happened? */
       if (e->nextEventIsFirst)
-        return NULL; 
+        return NULL;
 
       replaceDatetime(e->triggeredPreviousEventDateTime, dt_return);
       return dt_return;
@@ -1455,7 +1457,7 @@ struct _event*
 getNextEventInGroup(struct _event* e)
 {
   if (e != NULL)
-    return e->nextEventInGroup;   
+    return e->nextEventInGroup;
   else
     return NULL;
 }
-- 
GitLab