complicated way of dividing data

bertusavius

Board Regular
Joined
Feb 28, 2008
Messages
82
I have a table with a list of events that have ID, two time-values and two 'trip values'.



ID
Timestart
Timestop
tripstart
tripstop
25
6:55
7:55
259010
259030
25
7:06
7:55
259011
259030
25
7:11
7:57
259013
259030
25
7:17
7:57
259014
259030
25
7:23
7:57
259015
259030
25
7:27
7:59
259017
259031
25
7:29
7:58
259017
259031
25
7:40
7:59
259025
259031
25
8:11
8:21
259038
259043
25
8:41
9:07
259049
259063
25
8:48
9:16
259054
259064
78
13:24
13:34
259116
259122
78
13:40
14:14
259122
259134
78
13:45
14:22
259124
259136
78
13:54
14:22
259127
259136
78
14:03
14:23
259130
259136
78
14:35
14:58
259144
259148
78
14:36
14:58
259144
259148
78
14:43
15:06
259145
259150
78
14:52
15:38
259146
259162
78
15:19
15:42
259155
259163
78
15:27
15:47
259157
259164
78
15:54
16:02
259165
259167

<TBODY>
</TBODY>

<TBODY>
</TBODY>


To make things less abstract:
The trip-value is the value of a trip meter in a car in kilometers.
So the top record actualy says:
car nr 25 had an event that started at 06:55 at trip value 259010 and this event stopped at 07:55 coinciding with trip value 259030
You could say this is a list of events with corresponding accumulating properties, so wether the timeID starts or stops doesnt really matter. All the matters is that a certain time corresponds with a certain trip value.




Now wat I'd like is to create a measure that transforms and divides this information like this:



ID
binID
distance travelled
25
0700-0800
(value in kms)
25
0800-0900
(value in kms)
25
0900-1000
(value in kms)
78
0700-0800
(value in kms)
78
0800-0900
(value in kms)
78
0900-1000
(value in kms)

<TBODY>
</TBODY>

<TBODY>
</TBODY>



<TBODY>
</TBODY>
I have a table to relate to which contains binID, binstart and binstop
I also have a table for dates
Is it even worth contemplating to solve this in Powerpivot, because it seems quite daunting to me atm.



<TBODY>
</TBODY>
 
In the Control Panel "Region and Language" settings, what do you have set for "Format" ?
 
Upvote 0

Excel Facts

Back into an answer in Excel
Use Data, What-If Analysis, Goal Seek to find the correct input cell value to reach a desired result
format.jpg
 
Upvote 0
As soon as I expand the dataset, I'm affraid I'm getting an error in this part of the code:
ws.Cells(RowNo, 4) = rec(I - 1).mile - StartMiles

<tbody>
</tbody>

Can you confirm that with this ie example:

DatumTX startTX stopChWP_WAGEN_NUMMERINS_KILOMETERSTANDUIT_KILOMETERSTAND
3-4-20126:146:23521343168300168306
3-4-20126:096:16521343168298168301
3-4-20127:318:23535725483682483705
3-4-20128:208:23535725483704483705
3-4-20127:318:23535725483682483705
3-4-20127:318:23535725483682483705
3-4-20126:418:23535725483660483705
3-4-20126:577:26521343168311168327
3-4-20127:077:34521343168313168330
3-4-20127:027:14521343168312168316
3-4-20128:058:26521343168345168353
3-4-20128:408:40535725483715483716
3-4-20129:019:25535725483732483753
3-4-20129:289:45521343168373168388
3-4-201210:0010:07521343168393168396
3-4-201210:2510:46521343168404168411
3-4-201210:3510:49521343168408168411
3-4-201210:4010:58521343168408168414
3-4-201211:3411:51521343168424168431
3-4-201211:3511:51521343168424168431
3-4-201211:4211:56521343168427168433
3-4-201211:1511:46521343168418168429
3-4-201211:0611:29521343168416168423
3-4-201211:5712:32535725483771483789
3-4-201211:5712:26535725483771483786
3-4-201211:5712:28535725483771483787
3-4-201213:2213:40521343168456168463
3-4-201213:2313:31521343168456168458
3-4-201212:5613:22535725483799483829
3-4-201214:2914:57535725483829483862
3-4-201212:5513:25521343168448168456
3-4-201213:5014:06521343168465168468
3-4-201213:5814:13521343168466168470
3-4-201214:3414:43521343168475168478
3-4-201214:2314:56521343168472168481
3-4-201214:3115:02521343168474168484
3-4-201214:3315:02521343168475168484
3-4-201215:5316:02521343168498168504
3-4-201215:3516:04521343168493168505
3-4-2012521343
3-4-201215:2115:24521343168489168490
3-4-201215:3015:50535725483872483880

<tbody>
</tbody>
 
Upvote 0
You must be using some all code. The Current code does not have the line you listed your previous post (#23).

In any event, the code reads in the Dates as "String" (and transforms it to a "Variant") rather than "Dates" so I am not sure why it is not providing the information of the second (results) sheet properly...


In any event, I have made a change to the code to expressly change the the Date from a "variant" to a Date

Code:
Option Explicit
Const DateCol As Integer = 1
Const StartTimeCol As Integer = 2
Const EndTimeCol As Integer = 3
Const DriverCol As Integer = 4
Const CarNoCol As Integer = 5
Const StartMileCol As Integer = 6
Const EndMileCol As Integer = 7
Type typHourRec
    Used As Boolean
    
    MinMin As Long
    MaxMin As Long
    
    MinMile As Long
    MaxMile As Long
End Type
Type typRec
    Key As String
    HrDetail(24) As typHourRec
End Type
Sub Process()
    Dim ws As Worksheet
    Dim Rec() As typRec
    Dim Key As String
    Dim KeyIdx As Integer
    
    Dim RowNo As Long
    Dim LastRow As Long
    
    Dim I As Long
    
    ReDim Rec(0)
    
    Set ws = ThisWorkbook.Worksheets(1)
    LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    For RowNo = 2 To LastRow
        Key = Trim(ws.Cells(RowNo, DateCol)) & "~" & Trim(ws.Cells(RowNo, DriverCol)) & "~" & Trim(ws.Cells(RowNo, CarNoCol))
        KeyIdx = FindKeyIdx(Key, Rec)
        Debug.Print KeyIdx
        If Len(Trim(ws.Cells(RowNo, StartTimeCol))) > 1 Then
            Call UpdateRec(Rec(KeyIdx).HrDetail, StartTimeCol, StartMileCol, ws, RowNo)
            Call UpdateRec(Rec(KeyIdx).HrDetail, EndTimeCol, EndMileCol, ws, RowNo)
        End If
    Next RowNo
    MsgBox "Complete", vbInformation
    Call OutputAll(Rec)
    
End Sub
Function OutputAll(Rec() As typRec)
    Dim ws As Worksheet
    Dim RowNo  As Integer
    Dim KeyIdx As Integer
    
    Dim v As Variant
    Dim I As Integer
    
    Set ws = ThisWorkbook.Worksheets(2)
    ws.Cells.ClearContents
    RowNo = 1
    
    ws.Cells(RowNo, 1) = "Date"
    ws.Cells(RowNo, 2) = "Driver"
    ws.Cells(RowNo, 3) = "Car"
    ws.Cells(RowNo, 4) = "Bucket"
    ws.Cells(RowNo, 5) = "Kms"
    
    For KeyIdx = 1 To UBound(Rec)
        Call OutputData(ws, Rec(KeyIdx).HrDetail, Rec(KeyIdx).Key)
    Next KeyIdx
End Function
Function OutputData(ws As Worksheet, HrDetail() As typHourRec, Key As String)
    Dim I As Integer
    Dim RowNo As Long
    
    Dim v As Variant
    Dim J As Integer
    
    Dim ElapsedMin   As Long
    Dim ElapsedMiles   As Long
    
    Dim Perc As Single
    Dim tempMin As Integer
    Dim tempMiles As Long
    
    RowNo = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row + 1
    
    For I = 2 To UBound(HrDetail)
        
        If HrDetail(I).Used Then
            v = Split(Key, "~")
            If UBound(v) >= 2 Then
                ws.Cells(RowNo, 1) = CDate(v(0))
                ws.Cells(RowNo, 2) = v(1)
                ws.Cells(RowNo, 3) = v(2)
            End If
            'ElapsedMiles = 0
            ElapsedMiles = HrDetail(I).MaxMile - HrDetail(I).MinMile
            
            '***** Determine Offset Adj for the Start of the Hour
            If HrDetail(I - 1).Used Then
                tempMin = (60 - HrDetail(I - 1).MaxMin) + HrDetail(I).MinMin
                tempMiles = HrDetail(I).MinMile - HrDetail(I - 1).MaxMile
                Perc = HrDetail(I).MinMin / tempMin
                ElapsedMiles = ElapsedMiles + (tempMiles * Perc)
            End If
            
            '***** Determine Offset Ady for the Top of the Hour
            If (I < 24) Then
                If HrDetail(I + 1).Used Then
                    tempMin = (60 - HrDetail(I).MaxMin) + HrDetail(I + 1).MinMin
                    tempMiles = HrDetail(I + 1).MinMile - HrDetail(I).MaxMile
                    Perc = (60 - HrDetail(I).MaxMin) / tempMin
                    ElapsedMiles = ElapsedMiles + (tempMiles * Perc)
                End If
            End If
            
            'ws.Cells(RowNo, 1) = Dt
            'ws.Cells(RowNo, 2) = CarNo
            ws.Cells(RowNo, 4) = I & ":00" & " ~ " & (I + 1) & ":00"
            ws.Cells(RowNo, 5) = ElapsedMiles
            RowNo = RowNo + 1
        End If
        
    Next I
            
End Function
Function UpdateRec(HrDetail() As typHourRec, ByVal TimeColNo As Long, ByVal MileColNo As Long, ws As Worksheet, RowNo As Long)
    Dim TempTime As Date
    Dim Idx As Long
    
    TempTime = CDate(ws.Cells(RowNo, TimeColNo))
    Idx = Hour(TempTime)
    
    Select Case HrDetail(Idx).Used
        Case False
            HrDetail(Idx).MaxMin = Minute(ws.Cells(RowNo, TimeColNo))
            HrDetail(Idx).MinMin = Minute(ws.Cells(RowNo, TimeColNo))
            HrDetail(Idx).MaxMile = Val(ws.Cells(RowNo, MileColNo))
            HrDetail(Idx).MinMile = Val(ws.Cells(RowNo, MileColNo))
            HrDetail(Idx).Used = True
        Case True
            HrDetail(Idx).MaxMile = UpdateMax(HrDetail(Idx).MaxMile, Val(ws.Cells(RowNo, MileColNo)))
            HrDetail(Idx).MaxMin = UpdateMax(HrDetail(Idx).MaxMin, Minute(ws.Cells(RowNo, TimeColNo)))
            HrDetail(Idx).MinMile = UpdateMin(HrDetail(Idx).MinMile, Val(ws.Cells(RowNo, MileColNo)))
            HrDetail(Idx).MinMin = UpdateMin(HrDetail(Idx).MinMin, Minute(ws.Cells(RowNo, TimeColNo)))
    End Select
End Function
Function FindKeyIdx(ByVal Key As String, Rec() As typRec) As Integer
    Dim I As Integer
    
    For I = 1 To UBound(Rec)
        If Key = Rec(I).Key Then
            FindKeyIdx = I
            Exit Function
        End If
    Next I
    
    ReDim Preserve Rec(I)
    Rec(I).Key = Key
    
    'ReDim Rec(I).HrDetail(0)
    
    FindKeyIdx = I
End Function
Function UpdateMin(arrVal As Long, wsVal As Long) As Long
    If wsVal < arrVal Then
        UpdateMin = wsVal
    Else
        UpdateMin = arrVal
    End If
End Function
Function UpdateMax(arrVal As Long, wsVal As Long)
    If wsVal > arrVal Then
        UpdateMax = wsVal
    Else
        UpdateMax = arrVal
    End If
End Function
 
Upvote 0
Amazing how flawless and fast this script works.
It just ran through 20K lines in mere seconds.



Please do say so if you feel I'm over-asking here, but observing the output, I realize there is still another dimension to his problem.

If you process for instance this data:

DatumTX startTX stopChWP_WAGEN_NUMMERINS_KILOMETERSTANDUIT_KILOMETERSTAND
12-3-201216:30:0023:45:0052071227350227500
12-3-201216:36:0017:39:0052071227354227379
12-3-201216:36:0017:35:0052071227354227378
12-3-201216:53:0017:15:0052071227356227367
12-3-201216:59:0017:29:0052071227357227376
12-3-201217:57:0018:18:0052071227386227394
12-3-201218:11:0018:30:0052071227391227400
12-3-201218:21:0018:33:0052071227394227400
12-3-201218:39:0018:50:0052071227401227404
12-3-201218:43:0019:30:0052071227402227422
12-3-201219:00:0019:35:0052071227408227425
12-3-201219:11:0019:36:0052071227415227425
12-3-201219:20:0019:49:0052071227418227433
12-3-201221:29:0021:37:0052071227440227442
12-3-201221:51:0022:14:0052071227449227459
12-3-201222:01:0022:19:0052071227453227460
12-3-201223:20:0023:38:0052071227473227492

<tbody>
</tbody>

You will see that between 20:00 and 21:00 hour, no event was started or stopped.
This results of course in the fact that the code doesnt generate a time-bucket for 20:00-21:00.
However in this time-spam, 7 kilometers were travelled.

Can the code be modified even further to provide for this problem?
I realise this might result in an exponential growth in the amount of lines generated.
Also which driver ID should be associated?
Many other questions will certanly arise as well.


Perhaps something else would be helpful.
I happen to have another table which contains start and stop events of shifts, with associated time and mileage values.
These shifts encompass, contain, so to say, all the events which are in my original data. So within a shift, things happen a certain time and mileage values.

I have added such a line of data in the above example. (top line)
You see this line has the earliest start-time and the latest stop-time, as well as the lowest and the highest mileage value.


So the above in one sentence:
Do you think it might also be possible to let the script recognise the fact that (in the above example) it should also create the 20:00-21:00 line?
 
Upvote 0
Yes,

The data usually consists of many days, say a month.

Also shifts might run after midnight and events can also start before midnight and end after midnight.

Pretty complicated.
 
Upvote 0
If I look at the original data, You have one column for a Date and two columns for Times (One for Start Time and another for End Time) How do you represent a Event that start before mid night and ends the next day?

Here is some code that display the 4 miles incured during the 20:00 to 21:00 bin. The end result is still 150 miles

Code:
Option Explicit
Const DateCol As Integer = 1
Const StartTimeCol As Integer = 2
Const EndTimeCol As Integer = 3
Const DriverCol As Integer = 4
Const CarNoCol As Integer = 5
Const StartMileCol As Integer = 6
Const EndMileCol As Integer = 7
Type typDt_MilesRec
    Dt As Date
    Miles As Long
End Type
Type typMstRec
    Key As String
    DT_Miles() As typDt_MilesRec
End Type
Sub Process()
    Dim ws As Worksheet
    Dim ws3 As Worksheet
    
    Dim MstRec() As typMstRec
    Dim RowNo As Long
    Dim LastRow As Long
    
    Dim I As Long
    Dim Key As String
    Dim KeyIdx As Integer
    
    ReDim MstRec(0)
    
    Set ws = ThisWorkbook.Worksheets(1)
    LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    For RowNo = 2 To LastRow
        If Len(Trim(ws.Cells(RowNo, StartTimeCol))) > 1 Then
            Key = Trim(ws.Cells(RowNo, DateCol)) & "~" & Trim(ws.Cells(RowNo, DriverCol)) & "~" & Trim(ws.Cells(RowNo, CarNoCol))
            KeyIdx = FindKeyIdx(Key, MstRec)
            
            I = UBound(MstRec(KeyIdx).DT_Miles) + 1
            ReDim Preserve MstRec(KeyIdx).DT_Miles(I)
            
            MstRec(KeyIdx).DT_Miles(I).Miles = Val(ws.Cells(RowNo, StartMileCol))
            MstRec(KeyIdx).DT_Miles(I).Dt = ws.Cells(RowNo, StartTimeCol)
            Call InsertRec(MstRec, KeyIdx)
            
            I = UBound(MstRec(KeyIdx).DT_Miles) + 1
            ReDim Preserve MstRec(KeyIdx).DT_Miles(I)
            
            MstRec(KeyIdx).DT_Miles(I).Miles = Val(ws.Cells(RowNo, EndMileCol))
            MstRec(KeyIdx).DT_Miles(I).Dt = ws.Cells(RowNo, EndTimeCol)
            Call InsertRec(MstRec, KeyIdx)
        End If
    Next RowNo
    
    Call OutputAll(MstRec)
    
    MsgBox "Complete", vbInformation
End Sub
Function InsertRec(Rec() As typMstRec, IDX As Integer)
    Dim I As Long
    Dim xRec As typDt_MilesRec
    Dim MaxIdx As Integer
    
    MaxIdx = UBound(Rec(IDX).DT_Miles)
    
    '*****  This function sorts the last record into the correct location
    For I = MaxIdx - 1 To 1 Step -1
        If Rec(IDX).DT_Miles(I).Dt > Rec(IDX).DT_Miles(I + 1).Dt Then
            xRec = Rec(IDX).DT_Miles(I + 1)
            Rec(IDX).DT_Miles(I + 1) = Rec(IDX).DT_Miles(I)
            Rec(IDX).DT_Miles(I) = xRec
        Else
            Exit Function
        End If
    Next I
End Function
Function OutputAll(MstRec() As typMstRec)
    Dim ws As Worksheet
    Dim RowNo  As Integer
    Dim KeyIdx As Integer
    
    Dim v As Variant
    Dim I As Integer
    
    Set ws = ThisWorkbook.Worksheets(2)
    ws.Cells.ClearContents
    RowNo = 1
    
    ws.Cells(RowNo, 1) = "Datum"
    ws.Cells(RowNo, 2) = "Ch"
    ws.Cells(RowNo, 3) = "WP_Wagen"
    ws.Cells(RowNo, 4) = "Hr"
    ws.Cells(RowNo, 5) = "Km"
    
    For KeyIdx = 1 To UBound(MstRec)
        Call OutputData(ws, MstRec(KeyIdx), MstRec(KeyIdx).Key)
        Debug.Print MstRec(KeyIdx).Key
    Next KeyIdx
End Function
Function OutputData(ws As Worksheet, MstRec As typMstRec, Key As String)
    Dim I As Integer
    Dim RowNo As Long
    
    Dim v As Variant
    Dim J As Integer
    
    Dim Perc As Single
    Dim tempMins As Integer
    Dim tempMiles As Long
    
    Dim ElapsedMins As Integer
    Dim ElapsedMiles As Long
    
    Dim StartTime As Date
    Dim EndTime As Date
    
    Dim BinIdx As Integer
    Dim StartHr As Integer
    Dim EndHr As Integer
    Dim HourDiff As Integer
    
    Dim MilesInHr(24) As Long
    
    RowNo = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row + 1
    
    For I = 2 To UBound(MstRec.DT_Miles)
        StartTime = MstRec.DT_Miles(I - 1).Dt
        EndTime = MstRec.DT_Miles(I).Dt
        ElapsedMiles = MstRec.DT_Miles(I).Miles - MstRec.DT_Miles(I - 1).Miles
        
        If ElapsedMiles > 0 Then
            ElapsedMins = DateDiff("n", MstRec.DT_Miles(I - 1).Dt, MstRec.DT_Miles(I).Dt)
            StartHr = Hour(MstRec.DT_Miles(I - 1).Dt)
            EndHr = Hour(MstRec.DT_Miles(I).Dt)
            HourDiff = EndHr - StartHr
            
            Select Case HourDiff
                Case 0
                    MilesInHr(StartHr) = MilesInHr(StartHr) + ElapsedMiles
                Case Else
                    '***** Determine fractional time for 1st hour
                    BinIdx = Hour(StartTime)
                    tempMins = DateDiff("n", StartTime, CDate(BinIdx + 1 & ":00:00"))
                    Perc = tempMins / ElapsedMins
                    MilesInHr(BinIdx) = MilesInHr(BinIdx) + (ElapsedMiles * Perc)
                
                    Perc = 60 / ElapsedMins
                    For BinIdx = Hour(StartTime) + 1 To Hour(EndTime) - 1
                        MilesInHr(BinIdx) = MilesInHr(BinIdx) + (ElapsedMiles * Perc)
                    Next BinIdx
                    
                    '***** Determine fractional time for Last hour
                    BinIdx = Hour(EndTime)
                    tempMins = DateDiff("n", CDate(BinIdx & ":00:00"), EndTime)
                    Perc = tempMins / ElapsedMins
                    MilesInHr(BinIdx) = MilesInHr(BinIdx) + (ElapsedMiles * Perc)
            End Select
        End If
    Next I
       
    v = Split(Key, "~")
    For I = 1 To 24
        If MilesInHr(I) > 0 Then
            ws.Cells(RowNo, 1) = CDate(v(0))
            ws.Cells(RowNo, 2) = v(1)
            ws.Cells(RowNo, 3) = v(2)
            ws.Cells(RowNo, 4) = I & ":00" & " ~ " & (I + 1) & ":00"
            ws.Cells(RowNo, "E") = MilesInHr(I)
            RowNo = RowNo + 1
        End If
    Next I
    
End Function
Function FindKeyIdx(ByVal Key As String, Rec() As typMstRec) As Integer
    Dim I As Integer
    
    For I = 1 To UBound(Rec)
        If Key = Rec(I).Key Then
            FindKeyIdx = I
            Exit Function
        End If
    Next I
    
    ReDim Preserve Rec(I)
    Rec(I).Key = Key
    
    ReDim Preserve Rec(I).DT_Miles(0)
    
    FindKeyIdx = I
End Function
 
Upvote 0
This is utterly briliant:
I will have to run some more data through the code, but so far the output is even more accurate then I would have hoped.


The date column is linked to the start time.
So if an event crosses midnight. The data associated with the stop time should be date+1.

A solution I used earlier in non vba approaches:
The rest of the data of the larger model works with time buckets that exceed midnight. So things that happen between 2400 and 0100 are in a bucket called '2400-2500'. Also the bucket 2500-2600 exists.
After that the next one is 0200-0300. Events that cross 2600 hour are extremely rare.

So in the PowerPivot model, I'll be relating the output to this "bucket-table":

0200-0300
0300-0400
0400-0500
0500-0600
0600-0700
0700-0800
0800-0900
0900-1000
1000-1100
1100-1200
1200-1300
1300-1400
1400-1500
1500-1600
1600-1700
1700-1800
1800-1900
1900-2000
2000-2100
2100-2200
2200-2300
2300-2400
2400-2500
2500-2600

<tbody>
</tbody>
 
Upvote 0
Ok... Here is some improvement to the last version

If the Endtime < Starttime on the Source sheet, the application will assume that the endtime is the folloiwng day (Date listed in Col 1 + 1)

The Code will handle Date Transition correctly because it does all calulation of the combination of Date & Time rather than time alone.

All Dates and Times must be valid

Depending of the number of miles, there cound be some rounding errors becouse we are using whole (integer) rather than fractional numbers. Depending on you data, it may make since to fo with fractional miles
Let me know how this works for you
:)


Code:
Option Explicit
Const DateCol As Integer = 1
Const StartTimeCol As Integer = 2
Const EndTimeCol As Integer = 3
Const DriverCol As Integer = 4
Const CarNoCol As Integer = 5
Const StartMileCol As Integer = 6
Const EndMileCol As Integer = 7
Type typDt_MilesRec
    Dt As Date
    Miles As Long
End Type
Type typMstRec
    Key As String
    DT_Miles() As typDt_MilesRec
End Type
Type typBin
    Dt_Hr As Date
    Miles As Long
End Type
Sub Process()
    Dim ws As Worksheet
    Dim ws3 As Worksheet
    
    Dim MstRec() As typMstRec
    Dim RowNo As Long
    Dim LastRow As Long
    
    Dim I As Long
    Dim Key As String
    Dim KeyIdx As Integer
    
    Dim tempStartTime As Date
    
    ReDim MstRec(0)
    
    Set ws = ThisWorkbook.Worksheets(1)
    LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    For RowNo = 2 To LastRow
        If Len(Trim(ws.Cells(RowNo, StartTimeCol))) > 1 Then
            Key = Trim(ws.Cells(RowNo, DriverCol)) & "~" & Trim(ws.Cells(RowNo, CarNoCol))
            KeyIdx = FindKeyIdx(Key, MstRec)
            
            I = UBound(MstRec(KeyIdx).DT_Miles) + 1
            ReDim Preserve MstRec(KeyIdx).DT_Miles(I)
            
            MstRec(KeyIdx).DT_Miles(I).Miles = Val(ws.Cells(RowNo, StartMileCol))
            MstRec(KeyIdx).DT_Miles(I).Dt = CDate(ws.Cells(RowNo, DateCol) & " " & CDate(ws.Cells(RowNo, StartTimeCol)))
            tempStartTime = MstRec(KeyIdx).DT_Miles(I).Dt
            Call InsertRec(MstRec, KeyIdx)
            
            I = UBound(MstRec(KeyIdx).DT_Miles) + 1
            ReDim Preserve MstRec(KeyIdx).DT_Miles(I)
            
            MstRec(KeyIdx).DT_Miles(I).Miles = Val(ws.Cells(RowNo, EndMileCol))
            MstRec(KeyIdx).DT_Miles(I).Dt = CDate(ws.Cells(RowNo, DateCol) & " " & CDate(ws.Cells(RowNo, EndTimeCol)))
            If tempStartTime > MstRec(KeyIdx).DT_Miles(I).Dt Then
                MstRec(KeyIdx).DT_Miles(I).Dt = DateAdd("D", 1, MstRec(KeyIdx).DT_Miles(I).Dt)
            End If
            Call InsertRec(MstRec, KeyIdx)
        End If
    Next RowNo
    
    Call OutputAll(MstRec)
    
    MsgBox "Complete", vbInformation
End Sub
Function InsertRec(Rec() As typMstRec, IDX As Integer)
    Dim I As Long
    Dim xRec As typDt_MilesRec
    Dim MaxIdx As Integer
    
    MaxIdx = UBound(Rec(IDX).DT_Miles)
    
    '*****  This function sorts the last record into the correct location
    For I = MaxIdx - 1 To 1 Step -1
        If Rec(IDX).DT_Miles(I).Dt > Rec(IDX).DT_Miles(I + 1).Dt Then
            xRec = Rec(IDX).DT_Miles(I + 1)
            Rec(IDX).DT_Miles(I + 1) = Rec(IDX).DT_Miles(I)
            Rec(IDX).DT_Miles(I) = xRec
        Else
            Exit Function
        End If
    Next I
End Function
Function OutputAll(MstRec() As typMstRec)
    Dim ws As Worksheet
    Dim RowNo  As Integer
    Dim KeyIdx As Integer
    
    Dim v As Variant
    Dim I As Integer
    
    Set ws = ThisWorkbook.Worksheets(2)
    ws.Cells.ClearContents
    RowNo = 1
    
    ws.Cells(RowNo, 1) = "Datum"
    ws.Cells(RowNo, 2) = "Ch"
    ws.Cells(RowNo, 3) = "WP_Wagen"
    ws.Cells(RowNo, 4) = "Hr"
    ws.Cells(RowNo, 5) = "Km"
    
    For KeyIdx = 1 To UBound(MstRec)
        Call OutputData(ws, MstRec(KeyIdx), MstRec(KeyIdx).Key)
        Debug.Print MstRec(KeyIdx).Key
    Next KeyIdx
End Function
Function OutputData(ws As Worksheet, MstRec As typMstRec, Key As String)
    Dim I As Integer
    Dim RowNo As Long
    
    Dim v As Variant
    Dim J As Integer
    
    Dim Perc As Single
    Dim tempMins As Integer
    Dim tempMiles As Long
    
    Dim ElapsedMins As Integer
    Dim ElapsedMiles As Long
    
    Dim StartTime As Date
    Dim EndTime As Date
    
    Dim BinIdx As Integer
    Dim StartHr As Integer
    Dim EndHr As Integer
    Dim HourDiff As Integer
    
    Dim tempTime As Date
    
    Dim arrBin() As typBin
    ReDim arrBin(0)
    
    RowNo = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row + 1
    
    For I = 2 To UBound(MstRec.DT_Miles)
        StartTime = MstRec.DT_Miles(I - 1).Dt
        EndTime = MstRec.DT_Miles(I).Dt
        ElapsedMiles = MstRec.DT_Miles(I).Miles - MstRec.DT_Miles(I - 1).Miles
        
        If ElapsedMiles > 0 Then
            ElapsedMins = DateDiff("n", MstRec.DT_Miles(I - 1).Dt, MstRec.DT_Miles(I).Dt)
            HourDiff = DateDiff("h", StartTime, EndTime)
            Select Case HourDiff
                Case 0
                    BinIdx = FindBin_DT_HR(StartTime, arrBin)
                    arrBin(BinIdx).Miles = arrBin(BinIdx).Miles + ElapsedMiles
                Case Else
                    '***** Determine fractional time for 1st hour
                    BinIdx = FindBin_DT_HR(StartTime, arrBin)
                    tempTime = CDate(Format(StartTime, "MM/DD/YY HH:00:00"))
                    tempMins = DateDiff("n", StartTime, DateAdd("h", 1, tempTime))
                    Perc = tempMins / ElapsedMins
                    arrBin(BinIdx).Miles = arrBin(BinIdx).Miles + (ElapsedMiles * Perc)
                    'Determine Full hour mileage between Start and End Time
                    Perc = 60 / ElapsedMins
                    tempTime = DateAdd("h", 1, StartTime)
                    Do While Hour(tempTime) < Hour(EndTime)
                        BinIdx = FindBin_DT_HR(tempTime, arrBin)
                        arrBin(BinIdx).Miles = arrBin(BinIdx).Miles + (ElapsedMiles * Perc)
                        tempTime = DateAdd("h", 1, tempTime)
                    Loop
                    
                    '***** Determine fractional time for Last hour
                    BinIdx = FindBin_DT_HR(EndTime, arrBin)
                    tempTime = CDate(Format(EndTime, "MM/DD/YY HH:00:00"))
                    tempMins = DateDiff("n", tempTime, EndTime)
                    Perc = tempMins / ElapsedMins
                    arrBin(BinIdx).Miles = arrBin(BinIdx).Miles + (ElapsedMiles * Perc)
            End Select
        End If
    Next I
       
    v = Split(Key, "~")
    For I = 1 To UBound(arrBin)
        ws.Cells(RowNo, 1) = CDate(Format(arrBin(I).Dt_Hr, "MM/DD/YY"))
        If UBound(v) >= 1 Then
            ws.Cells(RowNo, 2) = v(0)
            ws.Cells(RowNo, 3) = v(1)
        End If
        ws.Cells(RowNo, 4) = Format(arrBin(I).Dt_Hr, "HH:MM") & " ~ " & Format(arrBin(I).Dt_Hr, "HH:59")
        ws.Cells(RowNo, "E") = arrBin(I).Miles
        RowNo = RowNo + 1
    Next I
    
End Function
Function FindBin_DT_HR(ByVal Dt As Date, Rec() As typBin) As Integer
    Dim I As Integer
    Dim tempDT As Date
    
    tempDT = Format(Dt, "MM/DD/YY HH:00:00")
    
    For I = 1 To UBound(Rec)
        If tempDT = Rec(I).Dt_Hr Then
            FindBin_DT_HR = I
            Exit Function
        End If
    Next I
    
    ReDim Preserve Rec(I)
    Rec(I).Dt_Hr = tempDT
    
    FindBin_DT_HR = I
End Function
Function FindKeyIdx(ByVal Key As String, Rec() As typMstRec) As Integer
    Dim I As Integer
    
    For I = 1 To UBound(Rec)
        If Key = Rec(I).Key Then
            FindKeyIdx = I
            Exit Function
        End If
    Next I
    
    ReDim Preserve Rec(I)
    Rec(I).Key = Key
    
    ReDim Preserve Rec(I).DT_Miles(0)
    
    FindKeyIdx = I
End Function
 
Last edited:
Upvote 0

Forum statistics

Threads
1,215,940
Messages
6,127,780
Members
449,406
Latest member
Pavesib

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