Find closest Date to specific Date - excel

I have two Tables.
Table1 goes from A1:F10 and shows the machine assignment.
Table2 goes from G1:K10 and shows the storage for the machines.
With a button I want to simulate which storage should be used for which machine.
In column C stands the date when the machine has to be built. In Column I stands the date when the storage is ready to use.
For example: The first machine has to start on 08/15/2018. How can I check which date in Column I is the closest to 08/15/2018?
This is my code so far:
Private Sub CommandButton1_Click()
Dim lastrow as Long
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
for a = 1 to lastrow
If Cells(a, 1) = "Machine Name" And _ ' Find the specific machine
Cells(a, 4) = "" Then ' In this cell the serial number of the storage should be added
' Now check if Storage for this machine is ready to use.
For b = 1 to lastrow
If Cells(b, 8) = "123" And _ ' Serial Number of the Storage
Cells(b, 10) = "" Then ' In this Cell serial number of the machine should be added
' Here it should check which Date in Column I is the closest to the date in Column C
Cells(a, 4).Value = Cells(b, 8)
Cells(b, 10).Value = Cells(a, 2)
End If
Next b
End If
Next a
End Sub
I tried to change the code from Find closest date to current date in VBA.
In the picture you can see an example how the table looks:

you didn't specify where you want the closest date before start so i just added the date as a comment to the start date in column C.
Sub FindClosestBeforeDate()
Dim ws As Worksheet
Dim lLastReadyUsed As Long
Dim lLastStartUsed As Long
Dim dt As String
Dim temp As Variant
Set ws = Application.ThisWorkbook.ActiveSheet
lLastStartUsed = ws.Cells(Rows.Count, "C").End(xlUp).Row
lLastReadyUsed = ws.Cells(Rows.Count, "I").End(xlUp).Row
'Delete previous comments
For l = 2 To lLastStartUsed
If Not Range("c" & l).Comment Is Nothing Then
ws.Range("C" & l).Comment.Delete
End If
Next l
'add comments with closeste date before startdate
For l = 2 To lLastStartUsed
For i = 2 To lLastReadyUsed
If DateDiff("D", ws.Range("C" & l).value, ws.Range("I" & i).value) < 0 Then
If IsEmpty(temp) Then
temp = DateDiff("D", ws.Range("C" & 3).value, ws.Range("I" & i).value)
dt = ws.Range("I" & i).value
ElseIf temp < DateDiff("D", ws.Range("C" & 3).value, ws.Range("I" & i).value) Then
temp = DateDiff("D", ws.Range("C" & 3).value, ws.Range("I" & i).value)
dt = ws.Range("I" & i).value
End If
End If
Next i
temp = Empty
ws.Range("C" & l).AddComment dt
Next l
End Sub
Hope this helps you out

With your example, im assuming you want
Start = 15.06.2018, Ende = 14.03.2018
Start = 25.08.2018, Ende = 26.07.2018
Add this Function and call it like YourCell.Value = getClosestDateBefore(StartCell.Value, Range("I2:I9"))
Function getClosestDateBefore(d As Date, RefDateRange As Range) As Date
Dim i As Long, ref_date As Date, diff As Double, best_diff As Double
best_diff = -10000000
With RefDateRange
For i = 1 To .Cells.Count
ref_date = .Cells(i).Value2
diff = ref_date - d
If diff < 0 And diff > best_diff Then
best_diff = diff
getClosestDateBefore = ref_date
End If
Next i
End With
End Function

Related

VBA Excel Insert a row if condition

I have an Excel sheet (doc1) with 4 columns. In "A" I have people names. In "B","C" and "D", I have informations on the CV of each of these people. I would like to extract in another sheet (doc2) these informations in a specific format: For each CV information, I would like to insert a row with the name of the person in "A" and one information about his CV in "B". Basically if I have 3 informations about a person in doc1 (In B,C and D), I want to have 3 rows : In A1, A2 and A3 the name of the person, and in B1, B2 and B3 the person's infos.
I have a macro which does the exact opposite, it is basically doing a Vlookup which throws multiple results. Any idea on how to turn this around? Thanks!
Option Explicit
Sub GO()
Dim J As Long
Dim I As Integer
Dim K As Long
Dim Indice As Long
Dim Tablo
Dim Nb As Integer
Application.ScreenUpdating = False
ReDim Tablo(1 To Range("A" & Rows.Count).End(xlUp).Row - 2, 1 To 2)
Tablo(1, 1) = Range("A2")
Tablo(1, 2) = Range("B2")
Nb = 1
For J = 3 To Range("A" & Rows.Count).End(xlUp).Row
For K = 1 To UBound(Tablo)
If Range("A" & J) = Tablo(K, 1) Then
For I = 1 To UBound(Tablo, 2)
If Tablo(K, I) = "" Then
Tablo(K, I) = Range("B" & J)
Exit For
End If
Next I
If I > UBound(Tablo, 2) Then
ReDim Preserve Tablo(1 To UBound(Tablo), 1 To UBound(Tablo, 2) + 1)
Tablo(K, UBound(Tablo, 2)) = Range("B" & J)
End If
Exit For
ElseIf Tablo(K, 1) = "" Then
Nb = Nb + 1
Tablo(K, 1) = Range("A" & J)
Tablo(K, 2) = Range("B" & J)
Exit For
End If
Next K
Next J
With Sheets("doc2")
.Cells.ClearContents
.Range("A2").Resize(Nb, UBound(Tablo, 2)) = Tablo
.Range("A1") = "Name"
.Range("B1") = "C.V info 1"
.Range("B1").AutoFill .Range("B1").Resize(, UBound(Tablo, 2) - 1), xlFillSeries
End With
End Sub
try somethihng like this:
Function NeverCallAFunctionGO:
dim doc1 as worksheet, doc2 as worksheet
dim lRow as long
'set your doc1 and doc2 sheets
lRow = 1
For i = 1 to doc1.range("A1").end(xldown).row
doc2.range("A" & lRow).value = doc1.range("A" & i).value
doc2.range("B" & lRow).value = doc1.range("B" & i).value
doc2.range("B" & lRow+1).value = doc1.range("C" & i).value
doc2.rangE("B" & lRow+2).value = doc1.rangE("D" & i).value
lRow = lRow + 3
Next i

Count all rows that are within a date range

I'm attempting to count the number of rows in my sheet that meet 3 sets of criteria: the client name in column C matches my active row; the due date in column G; and column M is blank (indicating no previous submission was sent).
I can get this to work just fine with the following code:
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Broker Workflow")
Dim i As Long
Dim iVal As Long
Dim lastRow As Long: lastRow = ws.Range("C" & Rows.Count).End(xlUp).Row
Dim strClient As String: strClient = Cells(ActiveCell.Row, "C").Value
Dim strRenDate As String: strRenDate = Cells(ActiveCell.Row, "G").Value
Dim strNotSubmitted As String: strNotSubmitted = ""
Dim strCriteria As String: strCriteria = strClient & strRenDate & strNotSubmitted
iVal = 0
For i = 8 To lastRow
If ws.Range("C" & i).Value & ws.Range("G" & i).Value & ws.Range("M" & i).Value = strCriteria Then
iVal = iVal + 1
End If
Next i
Dim strCount As String: strCount = iVal
My problem is that now I want to extend this to count all rows with a due date that is within a range of my active row date +/- 7 days (14 day range). So if my due date is 07/06/2020 it will count the number of rows that match my client name in C, have blank cell in M and a date of anything between 01/06/2020-14/06/2020 in G.
You are making it more complicated than needed... can get rid of the four variables above, and simply test like this:
For i = 8 To lastRow
If ws.Range("C" & i).Value = Cells(ActiveCell.Row, "C").Value & _
ws.Range("M" & i).Value = "" & _
ws.Range("G" & i).Value >= DateAdd(Cells(-7, "d", ActiveCell.Row, "G").Value) & _
ws.Range("G" & i).Value <= DateAdd(Cells(7, "d", ActiveCell.Row, "G").Value) Then
iVal = iVal + 1
End If
Next i
[EDIT]
Sorry!
I have no idea what I wrote earlier.
I mixed up the parameters in DateAdd and used & instead of and
This works, tested:
For i = 8 To lastRow
If Cells(i, "C").Value = Cells(ActiveCell.Row, "C").Value And _
Cells(i, "M").Value = "" And _
Cells(i, "G").Value >= DateAdd("d", -7, Cells(ActiveCell.Row, "G").Value) And _
Cells(i, "G").Value <= DateAdd("d", 7, Cells(ActiveCell.Row, "G").Value) Then
iVal = iVal + 1
End If
Next i
It will also work with your ws.Range syntax, it was just simpler for me to test it like this with Cells
Please note that the current line also gets counted if it has an empty M column...

Using Year(Date) in IF statement but no output

I am trying to grab data from three columns in my workbook AK,AL and AM respectively. After getting the data I am doing 3 different comparisons which are stated in the code below.
Firstly, I am comparing the date in Column AL and Column AM. I am checking if Column AL is of year 2018 and Column AM is not of year 2018. If its true then It will insert text in Column L called "Routine". This is done cell by cell using a for loop as seen in the code.
Next, there is a check if Column AM is of year 2018 and Column AK is color coded to Yellow color. If it is true then text will be inserted in Column L called "New".
Lastly, there is a check if Column AM is of year 2018 and Column AK is not colored in Yellow. If it is true then text will be inserted in Column 'L' called "Major"
Else, The cell will be left blank without any data inserted.
PROBLEM: The code runs fine and there are no issues or errors. But I am not able to get the output I want. The code does not insert any text in the Column L
Dim j As Long
Dim lastrow As Long
Dim ws1 As Worksheet
Dim wbk As Workbook
Dim wb As Worksheet
Dim date1 As Date, date2 As Date
Set wbk = Application.Workbooks("MaxiTrak RV Service Report - Blank.xlsm")
Set ws1 = wbk.Worksheets("ML_PSV_SERVICE")
lastrow = ws1.range("AL" & Rows.Count).End(xlUp).Row
For j = 2 To lastrow
date1 = ws1.Cells(j, 38).Value
date2 = ws1.Cells(j, 39).Value
If Year(date1) = Year(Date) - 1 And Year(date2) <> Year(Date) - 1 Then
Cells(j, 12).Value = "Routine"
If Year(date2) = Year(Date) - 1 And Cells(j, 37).Interior.ColorIndex = 6 Then
Cells(j, 12).Value = "New"
If Year(date2) = Year(Date) - 1 And Cells(j, 37).Interior.ColorIndex <> 6 Then
Cells(j, 12).Value = "Major"
Else
Cells(j, 12).Value = ""
End If
End If
End If
Next j
Sample Output expected
Try code below, it's pretty simple and self-explanatory:
Sub Compare()
Dim lastRow As Long, i As Long
lastRow = Range("AK" & Rows.Count).End(xlUp).Row
For i = 1 To lastRow
If Year(Range("AM" & i)) <> 2018 Then
If Year(Range("AL" & i)) = 2018 Then Range("L" & i) = "Routine"
' column AM has year equal to 2018
ElseIf Range("AK" & i).Interior.ColorIndex = 6 Then
Range("L" & i) = "New"
Else
Range("L" & i) = "Major"
End If
Next
End Sub
In the following code that you supplied you have:
If Year(date2) = Year(Date) - 1 And Cells(j, 37).Interior.ColorIndex = 6 Then
Cells(j, 12).Value = "New"
If Year(date2) = Year(Date) - 1 And Cells(j, 37).Interior.ColorIndex <> 6 Then
Cells(j, 12).Value = "Major"
Else
Cells(j, 12).Value = ""
End If
End If
Where you get into the first if statement because cells(j,37).interior.colorindex = 6, but then, you do a check where cells(j,37).interior.colorindex <> 6.
The conflict here is that it will always set cells(j,12).value = "". Either your first cell reference is off or your second reference is off. Another possibility is that you need to change one of the colorindex values.
From your description, I believe you have too many if statements. You also have an if statement nested inside another if statement.
Dim j, lastrow As Long
Dim ws1, wb As Worksheet
Dim wbk As Workbook
Dim dateAL, dateAM As Date
Dim colorID As Variant
Set wbk = Application.Workbooks("MaxiTrak RV Service Report - Blank.xlsm")
Set ws1 = wbk.Worksheets("ML_PSV_SERVICE")
lastrow = ws1.Range("AL" & Rows.Count).End(xlUp).Row
currentyear = Year(Date)
For j = 2 To lastrow
dateAL = Year(ws1.Cells(j, 38).Value) ' column AL
dateAM = Year(ws1.Cells(j, 39).Value) ' column AM
colorID = ws1.Cells(j, 37).Interior.ColorIndex
If dateAL = currentyear - 1 And dateAM <> currentyear - 1 Then
Cells(j, 12).Value = "Routine"
Else
If dateAM = currentyear - 1 And colorID = 6 Then
Cells(j, 12).Value = "New"
Else
Cells(j, 12).Value = "Major"
End If
End If
Next j
Try the above code, but please review the code FIRST.

VBA Excel, loop through 2 columns if when same value then calculate value from another colum

Hay I have the following problem and need help:
I have this table
A-----------B----------C-----------Start date---End date
Phase1.1--Phase1----Analyst-----1/1/2018------1/3/2019
Phase1.1--Phase1----Analyst-----1/2/2018------1/4/2020
Phase1.1--Phase1----Analyst-----1/3/2018------1/5/2019
Phase1.1--Phase1----Manager-----1/2/2018------1/7/2019
Phase1.1--Phase1----Manager-----1/1/2018------1/5/2019
Phase1.1--Phase2----Analyst-----1/1/2018------1/3/2019
……..
I want to loop through this table and check if column B values are same (Duplicate) the move to column C and for the same values in column C calculate the min for column "Start date" and the max for column "End date".
then write the rows in new excel sheet
So that I have for each entry in column C one row with start and end date depending on column B.
Moreover column A is always same and should be copied and not change.
the result should be like that:
A-----B---------C-----------Start date------End date
Phase1.1---Phase1----Analyst----1/1/2018-----1/4/2020
Phase1.1---Phase1----Manager----1/1/2018-----1/7/2019
Phase1.1---Phase2----Analyst----1/1/2018-----1/3/2019
………..
this is how my real data looks like:
thanx for your support
Here is one way to do it via VBA.
Sub rowLoop()
Dim lRow As Long, lRow2 As Long
Dim ws1 As Worksheet, ws2 As Worksheet
Dim startDate As String, endDate As String
Set ws1 = Sheets("Data") 'set this to be the worksheet with data
Set ws2 = Sheets("Results") 'set this to the worksheet you want the results to go
lRow = ws1.Cells(Rows.Count, "A").End(xlUp).Row 'find last used row
ws2.Range("B2:C" & lRow).Value = ws1.Range("B2:C" & lRow).Value 'copy over Column B values
ws2.Range("$B$2:$C$" & lRow).RemoveDuplicates Columns:=Array(1, 2), Header:=xlNo 'remove duplicates
lRow2 = ws2.Cells(Rows.Count, "B").End(xlUp).Row 'find last used row
For i = 2 To lRow2 'loop through rows to determin start and end date
ws2.Range("A" & i).Value = i - 1
For j = 2 To lRow
If ws2.Range("B" & i).Value = ws1.Range("B" & j).Value And ws2.Range("C" & i).Value = ws1.Range("C" & j).Value Then
If startDate = "" Then
startDate = ws1.Range("D" & j).Value
Else
If ws1.Range("D" & j).Value < startDate Then
startDate = ws1.Range("D" & j).Value
End If
End If
If endDate = "" Then
endDate = ws1.Range("E" & j).Value
Else
If ws1.Range("E" & j).Value > endDate Then
endDate = ws1.Range("E" & j).Value
End If
End If
End If
Next j
ws2.Range("D" & i).Value = startDate
ws2.Range("E" & i).Value = endDate
startDate = ""
endDate = ""
Next i
End Sub

Copy and Insert Row Based on Cell Time Value

My main problem is that I am trying to add a row directly beneath another row based on the time value of that row. Here's an example of what I'm trying to do:
column F ========> new column F
2 1
2
2 1
2
1 1
1 1
2 1
2
To better explain, if the value in the first column F is a 2, that represents a time value that is greater than 0:59:00 and another row is added beneath it. If it is a 1, then it represents a time value that is equal to or less than 0:59:00and no row gets added.
I have multiple coding attempts at fixing this, and this first one is by someone more well-versed in VBA than I and includes some of his comments:
Public Sub ExpandRecords()
Dim i As Long, _
j As Long, _
LR As Long
'set variable types
LR = Range("A" & Rows.Count).End(xlUp).Row
'setting variable LR as number of rows with data
Application.ScreenUpdating = False
Columns("F:F").NumberFormat = "hh:mm:ss"
'sets number format in column b to text
For i = LR To 1 Step -1
'Executes following code from last row with data to row 1 working backwards
'If CLng(Left(Range("F" & i).Value, Len(Range("F" & i).Value) - 6)) > 0 Then
If CLng(Hour(Range("F" & i))) > 0 Then
'If the hour value in column F is greater than 1, then...
With Range("F" & i)
'starting with column F, loop through these statements...
'.Offset(1, 0).Resize(CLng(Left(Range("F" & i).Value, Len(Range("F" & i).Value) - 6)) - 1, 1).EntireRow.Insert Shift:=xlDown
.Offset(1, 0).Resize(CLng(Hour(Range("F" & i))).Value, Len(Range("F" & i).Value) - 1, 1).EntireRow.Insert Shift:=xlDown
'return the value of column F's hour value, change the range to insert the number of rows below based on hour value
'.Resize(CLng(Left(Range("F" & i).Value, Len(Range("F" & i).Value) - 6)), 1).EntireRow.Value = Range("A" & i).EntireRow.Value
.Resize(Hour(Range("F" & i)), 1).EntireRow.Value = Range("A" & i).EntireRow.Value
'Get value of row to be copied
'For j = 0 To CLng(Left(Range("F" & i).Value, Len(Range("F" & i).Value) - 6))
For j = 0 To Hour(Range("F" & i))
Range("H" & i).Offset(j - 1, 0).Value = Application.Text(j, "0")
Next j
End With
Else
Range("H" & i).Value = Application.Text(1, "0")
End If
Next i
Application.ScreenUpdating = True
End Sub
Here is a similar question from a previous user
Any help would be greatly appreciated.
Use this instead:
Public Sub ExpandRecords()
Dim i As Long, s As String
Const COL = "F"
For i = 1 To Cells(Rows.Count, COL).End(xlUp).Row
If Cells(i, COL) = 2 Then s = s & "," & Cells(i, COL).Address
Next
If Len(s) Then
Range(Mid$(s, 2)).EntireRow.Insert
For i = 1 To Cells(Rows.Count, COL).End(xlUp).Row
If Cells(i, COL) = vbNullString Then Cells(i, COL) = 1
Next
End If
End Sub

Resources