From 893f29af6df9001c1c41aea41b60cc5c2495f319 Mon Sep 17 00:00:00 2001
From: Florian Prill <florian.prill@dwd.de>
Date: Mon, 15 Apr 2019 18:07:10 +0200
Subject: [PATCH] several workarounds in mtime (division of timedelta, events).

---
 include/mtime_timedelta.h |  3 ++-
 src/libmtime.f90          |  5 ++--
 src/mtime_c_bindings.f90  |  8 +++---
 src/mtime_t_event.inc     |  8 +++---
 src/mtime_t_timedelta.inc | 55 ++++++++++++---------------------------
 src/mtime_timedelta.c     | 33 ++++++++++++++---------
 6 files changed, 52 insertions(+), 60 deletions(-)

diff --git a/include/mtime_timedelta.h b/include/mtime_timedelta.h
index 23d47466..72a90165 100644
--- a/include/mtime_timedelta.h
+++ b/include/mtime_timedelta.h
@@ -86,7 +86,8 @@ struct _timedelta*
 julianDeltaToTimeDelta(struct _juliandelta* jd, struct _datetime *dt, struct _timedelta* td_return);
 
 struct _divisionquotienttimespan*
-divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _divisionquotienttimespan* quo_ret);
+divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _datetime* base_dt, 
+struct _divisionquotienttimespan* quo_ret);
 
 struct _divisionquotienttimespan*
 divideTwoDatetimeDiffsInSeconds(struct _datetime* dt1_dividend, struct _datetime* dt2_dividend,struct _datetime* dt1_divisor, struct _datetime* dt2_divisor, int64_t * denominator_ret,  struct _divisionquotienttimespan* quo_ret);
diff --git a/src/libmtime.f90 b/src/libmtime.f90
index 614f774b..6e9df0ec 100644
--- a/src/libmtime.f90
+++ b/src/libmtime.f90
@@ -1741,14 +1741,15 @@ contains
   !! @param[out]  quotient
   !!         A pointer to type divisionquotienttimespan
   !!
-  subroutine divideTimeDeltaInSeconds(dividend, divisor, quotient, errna)!OK-UNTESTED.
+  SUBROUTINE divideTimeDeltaInSeconds(dividend, divisor, base_dt, quotient, errna)!OK-UNTESTED.
     type(timedelta), target, intent(in) :: dividend
     type(timedelta), target, intent(in) :: divisor
+    TYPE(datetime),  TARGET, INTENT(in) :: base_dt
     type(divisionquotienttimespan), target, intent(out) :: quotient
     INTEGER, INTENT(out), optional :: errna
     type(c_ptr) :: dummy_ptr
     IF (PRESENT(errna)) errna = 0 ! FIXME: no_error
-    dummy_ptr = my_dividetimedeltainseconds(c_loc(dividend), c_loc(divisor), c_loc(quotient))
+    dummy_ptr = my_dividetimedeltainseconds(c_loc(dividend), c_loc(divisor), c_loc(base_dt), c_loc(quotient))
     IF (PRESENT(errna) .AND. .NOT. c_associated(dummy_ptr)) THEN
       errna = errna + 2  ! increment error number by 2, see below for an explanation.
     ENDIF
diff --git a/src/mtime_c_bindings.f90 b/src/mtime_c_bindings.f90
index 420054e0..6f3da716 100644
--- a/src/mtime_c_bindings.f90
+++ b/src/mtime_c_bindings.f90
@@ -510,15 +510,17 @@ module mtime_c_bindings
       type(c_ptr), value :: jd
     end function my_timedeltatojuliandelta
     !
-    function my_divideTimeDeltaInSeconds(dividend, divisor, quotient) result(ret_quotient) bind(c,name='divideTimeDeltaInSeconds')
+    FUNCTION my_divideTimeDeltaInSeconds(dividend, divisor, base_dt, quotient) &
+RESULT(ret_quotient) BIND(c,name='divideTimeDeltaInSeconds') 
       import :: c_ptr
-      type(c_ptr) :: ret_quotient
+      type(c_ptr) :: ret_quotient 
       type(c_ptr), value :: dividend
       type(c_ptr), value :: divisor
+      type(c_ptr), value :: base_dt
       type(c_ptr), value :: quotient
     end function my_divideTimeDeltaInSeconds
     !
-    function my_divideDatetimeDifferenceInSeconds(dt1, dt2, divisor, quotient) result(ret_quotient) &
+    FUNCTION my_divideDatetimeDifferenceInSeconds(dt1, dt2, divisor, quotient) RESULT(ret_quotient) &
          &                                                                     bind(c,name='divideDatetimeDifferenceInSeconds')
       import :: c_ptr
       type(c_ptr) :: ret_quotient
diff --git a/src/mtime_t_event.inc b/src/mtime_t_event.inc
index 9c9fed5d..d9a99867 100644
--- a/src/mtime_t_event.inc
+++ b/src/mtime_t_event.inc
@@ -140,13 +140,13 @@
     CLASS (t_eventGroup) :: this
     TYPE(t_event), TARGET :: event_to_add
     IF (.NOT. ASSOCIATED(this%last_event_in_group)) THEN
-      this%first_event_in_group => event_to_add
+      allocate(this%first_event_in_group, source=event_to_add)
+      this%last_event_in_group => this%first_event_in_group
       NULLIFY(this%first_event_in_group%nextEventInGroup)
     ELSE
-      this%last_event_in_group%nextEventInGroup => event_to_add
-      NULLIFY(event_to_add%nextEventInGroup)
+      allocate(this%last_event_in_group%nextEventInGroup, source=event_to_add)
+      this%last_event_in_group => this%last_event_in_group%nextEventInGroup
     ENDIF
-    this%last_event_in_group => event_to_add
   END SUBROUTINE t_eventGroup_addToGroup
 
   FUNCTION t_eventGroup_getGroupId(this) RESULT(group_id)
diff --git a/src/mtime_t_timedelta.inc b/src/mtime_t_timedelta.inc
index 53f0d544..7189e031 100644
--- a/src/mtime_t_timedelta.inc
+++ b/src/mtime_t_timedelta.inc
@@ -154,7 +154,9 @@
     TYPE(timedelta), POINTER             :: td_tmp
     TYPE(c_ptr) :: c_pointer, dummy_ptr, c_ptr_result
 
-    dummy_ptr = my_elementwisescalarmultiplytimedelta(c_loc(this%td), int(lambda, c_int64_t), c_loc(scaled_td%td))
+    ! cast into real since in mtime int implementation scalar
+    ! multiplication can not give a value in excess of 24 hours
+    dummy_ptr = my_elementwisescalarmultiplytimedeltadp(c_loc(this%td), real(lambda, c_double), c_loc(scaled_td%td))
     IF (.NOT. c_associated(dummy_ptr)) THEN
       CALL handle_errno(0*100+2, __FILE__, __LINE__)
       scaled_td%td%sign = '!'
@@ -216,47 +218,24 @@
   END FUNCTION t_timedelta_toString
 
   FUNCTION t_timedelta_divideInSecondsBy (this, divisor, referenceDateTime) RESULT(quotient)
-    CLASS(t_timedelta), INTENT(in)           :: this
-    TYPE(t_timedelta),  INTENT(in)           :: divisor
-    TYPE(t_datetime),   INTENT(IN), OPTIONAL :: referenceDateTime
-    TYPE(divisionquotienttimespan)           :: quotient
-    TYPE(timedelta),                POINTER  :: tmp_dividend
-    TYPE(timedelta),                POINTER  :: tmp_divisor
-    TYPE(datetime),                 POINTER  :: tmp_ref, tmp_dt
-    TYPE(t_datetime)                         :: dt_tmp
-    INTEGER                                  :: errno
-
-    tmp_dividend => newtimedelta(this%td, errno)
-    CALL handle_errno(errno, __FILE__, __LINE__)
-    tmp_divisor => newtimedelta(divisor%td, errno)
-    CALL handle_errno(errno, __FILE__, __LINE__)
-    IF (PRESENT(referenceDateTime)) THEN
-      tmp_ref => newDateTime(referenceDateTime%dt, errno)
-      CALL handle_errno(errno, __FILE__, __LINE__)
-    ENDIF
+    CLASS(t_timedelta), INTENT(in), target      :: this
+    TYPE(t_timedelta),  INTENT(in), target      :: divisor
+    TYPE(t_datetime),   INTENT(IN), target	:: referenceDateTime
+    TYPE(divisionquotienttimespan), target	:: quotient
+    TYPE(t_datetime), target                    :: dt_tmp
+    type(c_ptr)					:: dummy_ptr
 
-    CALL divideTimeDeltaInSeconds(tmp_dividend, tmp_divisor, quotient, errno)
+    dummy_ptr = my_divideTimeDeltaInSeconds(c_loc(this%td), c_loc(divisor%td), &
+                      & c_loc(referenceDateTime%dt), c_loc(quotient))
 
-    IF (errno /= no_error) THEN
-      IF (.NOT. PRESENT(referenceDateTime)) THEN
-        CALL handle_errno(errno, __FILE__, __LINE__)
-      ELSE
+    IF (.NOT. c_associated(dummy_ptr)) THEN
         dt_tmp = referenceDateTime + this
-        tmp_dt => newDateTime(dt_tmp%dt, errno)
-        CALL handle_errno(errno, __FILE__, __LINE__)
-        CALL divideDatetimeDifferenceInSeconds(tmp_dt, tmp_ref, &
-             &                                tmp_divisor, quotient, errno)
-        CALL handle_errno(errno, __FILE__, __LINE__)
-
-        CALL deallocateDatetime(tmp_dt)
-      ENDIF
-    END IF
+	dummy_ptr = my_dividedatetimedifferenceinseconds(c_loc(dt_tmp%dt),    &
+          &	                    c_loc(referenceDateTime%dt), &
+          &			    c_loc(divisor%td), c_loc(quotient))
 
-    CALL deallocatetimedelta(tmp_dividend)
-    CALL deallocatetimedelta(tmp_divisor)
-    IF (PRESENT(referenceDateTime)) THEN
-      CALL deallocateDatetime(tmp_ref)
-    ENDIF
+        CALL handle_errno(.not. c_associated(dummy_ptr), general_arithmetic_error, __FILE__, __LINE__)
+    END IF
   END FUNCTION t_timedelta_divideInSecondsBy
 
   FUNCTION t_timedelta_toSeconds (this, td) RESULT(seconds)
diff --git a/src/mtime_timedelta.c b/src/mtime_timedelta.c
index 9448228b..558bcd8f 100644
--- a/src/mtime_timedelta.c
+++ b/src/mtime_timedelta.c
@@ -1172,26 +1172,35 @@ else
 /*! \endcond */
 
 
+// WE REALLY NEED SOMETHING BETTER HERE!
 struct _divisionquotienttimespan*
-divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _divisionquotienttimespan* quo_ret)
+divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _datetime* base_dt, struct _divisionquotienttimespan* quo_ret)
 {
   if ((dividend != NULL) && (divisor != NULL) && (quo_ret != NULL))
     {
-      if ((dividend->year == 0) && (dividend->month == 0) &&  (divisor->year == 0) && (divisor->month == 0))
+      if ((dividend->year == 0) && (divisor->year == 0) && (divisor->month == 0))
         {
-          intmax_t numerator   = (intmax_t) (((int64_t) dividend->day * 86400 + 
-                                                        dividend->hour * 3600 + 
-                                                        dividend->minute * 60 + 
-                                                        dividend->second) * 1000 + 
-                                                        dividend->ms);
+
+	  struct _juliandelta* jd = newJulianDelta('+', 0, 0);
+	  if ( jd == NULL )
+	    return 0;
+	  jd = timeDeltaToJulianDelta(dividend, base_dt, jd);
+	  if ( jd == NULL )
+	    {
+	      deallocateJulianDelta(jd);
+	      return 0;
+	    }
+
+	  intmax_t numerator   = (intmax_t) (((int64_t) jd->day * NO_OF_MS_IN_A_DAY + jd->ms));
           intmax_t denominator = (intmax_t) (((int64_t) divisor->day * 86400 + 
-                                                        divisor->hour * 3600 + 
-                                                        divisor->minute * 60 + 
-                                                        divisor->second ) * 1000 + 
-                                                        divisor->ms);
+					      divisor->hour * 3600 + 
+					      divisor->minute * 60 + 
+					      divisor->second ) * 1000 + 
+					     divisor->ms);
 
+	  deallocateJulianDelta(jd);
           if (denominator == 0) /* Division by zero is illegal. */
-            return NULL;
+	     return NULL;
 
           imaxdiv_t div = imaxdiv(numerator, denominator);
            
-- 
GitLab