Formula to return date if cumulative amount meets criteria

jumbledore

Active Member
Joined
Jan 17, 2014
Messages
262
I have 2 columns for dates and amounts paid
I want a formula which will determine the date when the cumulative of the amounts just exceeds or equals a given value. So suppose I have the following:

Dates Amt
16-Jul-14 10000
1-Aug-14 4567
3-Aug-14 3000
Now suppose I have 14,000 as my "cut-off" amount. I want a formula which should return the date, 1-Aug-14 as the cumulative amount until 1-Aug is 14,567 which is just above the cutoff of 14,000. The formula should not return 3-Aug-14 even though it meets the criteria.
Thanks
 

Excel Facts

What does custom number format of ;;; mean?
Three semi-colons will hide the value in the cell. Although most people use white font instead.
what's that?

Sorry, it a User Defined Function, like this:

Code:
Function SumByDate(rng As Range, Limit As Long) As Date
Dim Arr() As Variant
Dim ArrSum As Double
Dim i As Long


    Arr = rng
    
    ' sort the range
    QuickSortArray Arr, , , 1
    
    For i = LBound(Arr) To UBound(Arr)
    ArrSum = ArrSum + Arr(i, 2)
    If ArrSum >= Limit Then SumByDate = Arr(i, 1): Exit For
    Next i
    
End Function
Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0)
    On Error Resume Next


    'Sort a 2-Dimensional array


    ' SampleUsage: sort arrData by the contents of column 3
    '
    '   QuickSortArray arrData, , , 3


    '
    'Posted by Jim Rech 10/20/98 Excel.Programming


    'Modifications, Nigel Heffernan:


    '       ' Escape failed comparison with empty variant
    '       ' Defensive coding: check inputs
    ' http://stackoverflow.com/questions/4873182/sorting-a-multidimensionnal-array-in-vba
    
    Dim i As Long
    Dim j As Long
    Dim varMid As Variant
    Dim arrRowTemp As Variant
    Dim lngColTemp As Long


    If IsEmpty(SortArray) Then
        Exit Sub
    End If
    If InStr(TypeName(SortArray), "()") < 1 Then  'IsArray() is somewhat broken: Look for brackets in the type name
        Exit Sub
    End If
    If lngMin = -1 Then
        lngMin = LBound(SortArray, 1)
    End If
    If lngMax = -1 Then
        lngMax = UBound(SortArray, 1)
    End If
    If lngMin >= lngMax Then    ' no sorting required
        Exit Sub
    End If


    i = lngMin
    j = lngMax


    varMid = Empty
    varMid = SortArray((lngMin + lngMax) \ 2, lngColumn)


    ' We  send 'Empty' and invalid data items to the end of the list:
    If IsObject(varMid) Then  ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a valid default member or property
        i = lngMax
        j = lngMin
    ElseIf IsEmpty(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf IsNull(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf varMid = "" Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) = vbError Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) > 17 Then
        i = lngMax
        j = lngMin
    End If


    While i <= j
        While SortArray(i, lngColumn) < varMid And i < lngMax
            i = i + 1
        Wend
        While varMid < SortArray(j, lngColumn) And j > lngMin
            j = j - 1
        Wend


        If i <= j Then
            ' Swap the rows
            ReDim arrRowTemp(LBound(SortArray, 2) To UBound(SortArray, 2))
            For lngColTemp = LBound(SortArray, 2) To UBound(SortArray, 2)
                arrRowTemp(lngColTemp) = SortArray(i, lngColTemp)
                SortArray(i, lngColTemp) = SortArray(j, lngColTemp)
                SortArray(j, lngColTemp) = arrRowTemp(lngColTemp)
            Next lngColTemp
            Erase arrRowTemp


            i = i + 1
            j = j - 1
        End If
    Wend


    If (lngMin < j) Then Call QuickSortArray(SortArray, lngMin, j, lngColumn)
    If (i < lngMax) Then Call QuickSortArray(SortArray, i, lngMax, lngColumn)


End Sub


Excel 2010
BCDE
201/08/201410002001
301/07/2014100001/08/2014
401/06/20141000
501/09/20141000
Sheet1
Cell Formulas
RangeFormula
E3=SumByDate(B2:C5,E2)
 
Upvote 0
I am sorry may be I shouldn't have used the word "cumulative" but is there any way to do this, though full points to your code.

yes sorting should solve the problem but if there is a way to use the code without sorting it would be more than fantastic. The problem with sorting is that if I forget to do it (even once) it could create a big problem for everyone. but thanks anyway

If you are after a smallest possible set of values that sums to a value > D1, then you could sort the data on (dollar) values and run the formula I already proposed. You need to look for code in VBA that does the required sorting whenever the data changes.
 
Last edited:
Upvote 0
Sorry, it a User Defined Function, like this:

The code is great but what if I wanted to make a slight modification like if I only wanted the amounts totaled for a particular name in column A. For eg.: find the cutoff date for name, Peter?
 
Upvote 0
The code is great but what if I wanted to make a slight modification like if I only wanted the amounts totaled for a particular name in column A. For eg.: find the cutoff date for name, Peter?

Do you have any other requirements before I make the changes?
 
Upvote 0

Excel 2010
BCDEF
401/08/2014Dave1000Dave
501/07/2014Dave10002000
601/06/2014Mary100001/08/2014
701/09/2014Steve1000
Sheet1
Cell Formulas
RangeFormula
F6=SumByDateIF(C4:C7,B4:B7,D4:D7,F5,F4)


Code:
Function SumByDateIF(NameRng As Range, DateRng As Range, AmountRng As Range, Limit As Long, MatchName As String) As Date
Dim Arr() As Variant
Dim ArrSum As Double
Dim rng As Range
Dim i As Long


Set rng = Union(NameRng, DateRng, AmountRng)


    Arr = rng
    
    ' sort the range
    QuickSortArray Arr, , , rng.Column - DateRng.Column + 1
    
    For i = LBound(Arr) To UBound(Arr)
    If Arr(i, NameRng.Column - rng.Column + 1) = MatchName Then
        ArrSum = ArrSum + Arr(i, AmountRng.Column - rng.Column + 1)
        If ArrSum >= Limit Then SumByDateIF = Arr(i, DateRng.Column - rng.Column + 1): Exit For
    End If
    Next i
    
End Function


Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0)
    On Error Resume Next




    'Sort a 2-Dimensional array




    ' SampleUsage: sort arrData by the contents of column 3
    '
    '   QuickSortArray arrData, , , 3




    '
    'Posted by Jim Rech 10/20/98 Excel.Programming




    'Modifications, Nigel Heffernan:




    '       ' Escape failed comparison with empty variant
    '       ' Defensive coding: check inputs
    ' http://stackoverflow.com/questions/4873182/sorting-a-multidimensionnal-array-in-vba
    
    Dim i As Long
    Dim j As Long
    Dim varMid As Variant
    Dim arrRowTemp As Variant
    Dim lngColTemp As Long




    If IsEmpty(SortArray) Then
        Exit Sub
    End If
    If InStr(TypeName(SortArray), "()") < 1 Then  'IsArray() is somewhat broken: Look for brackets in the type name
        Exit Sub
    End If
    If lngMin = -1 Then
        lngMin = LBound(SortArray, 1)
    End If
    If lngMax = -1 Then
        lngMax = UBound(SortArray, 1)
    End If
    If lngMin >= lngMax Then    ' no sorting required
        Exit Sub
    End If




    i = lngMin
    j = lngMax




    varMid = Empty
    varMid = SortArray((lngMin + lngMax) \ 2, lngColumn)




    ' We  send 'Empty' and invalid data items to the end of the list:
    If IsObject(varMid) Then  ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a valid default member or property
        i = lngMax
        j = lngMin
    ElseIf IsEmpty(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf IsNull(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf varMid = "" Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) = vbError Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) > 17 Then
        i = lngMax
        j = lngMin
    End If




    While i <= j
        While SortArray(i, lngColumn) < varMid And i < lngMax
            i = i + 1
        Wend
        While varMid < SortArray(j, lngColumn) And j > lngMin
            j = j - 1
        Wend




        If i <= j Then
            ' Swap the rows
            ReDim arrRowTemp(LBound(SortArray, 2) To UBound(SortArray, 2))
            For lngColTemp = LBound(SortArray, 2) To UBound(SortArray, 2)
                arrRowTemp(lngColTemp) = SortArray(i, lngColTemp)
                SortArray(i, lngColTemp) = SortArray(j, lngColTemp)
                SortArray(j, lngColTemp) = arrRowTemp(lngColTemp)
            Next lngColTemp
            Erase arrRowTemp




            i = i + 1
            j = j - 1
        End If
    Wend




    If (lngMin < j) Then Call QuickSortArray(SortArray, lngMin, j, lngColumn)
    If (i < lngMax) Then Call QuickSortArray(SortArray, i, lngMax, lngColumn)




End Sub
 
Upvote 0
for some reason I am getting the #VALUE! error. My dates are in the format 21-Jul-14. Could this be the problem?
 
Upvote 0

Forum statistics

Threads
1,215,891
Messages
6,127,606
Members
449,388
Latest member
macca_18380

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top