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