Finding a text string yyyymm based on current year and month - excel

I need to locate all cells within column L starting from Row 10 containing yyyymm+2 (202009).
In other words, I'm looking for cells containing all dates belonging to the month 2 months in advance of the current month. Valid values would be 20200901 up until 20200930 accordingly as of July 2020.
The Column L contains values in text format such as 20201120, 20210102, etc. All the values are dates in Column L formatted as text as 'yyyymmdd'.
I'm trying to use the code below, but it is quite clearly wrong, since +2 won't show the correct year or month if the year changes.
Dim strSearchText As String
Dim y As Integer
Dim m As Integer
m = DatePart("mm", Date) + 2
y = DatePart("yyyy", Date)
strSearchText = y & m
Dim rngSearchArea As Range
Set rngSearchArea = ws.Range(Range("L10"), ws.Range("L" & ws.Range("L:L").Cells.Count).End(xlUp))
Any ideas how to solve this?

Maybe you are just looking for something like that?
String containing today + 2 months in the yyyydd format:
str = Format(DateAdd("m", 2, Now()), "yyyymm")

Please test the next code. Since you did not answer my above question, it will return the range of processed dates in the column N:N, starting from the tenth row:
Sub GetDateTwoMonthMore()
Dim sh As Worksheet, arr As Variant, arrF As Variant, lastRow As Long
Dim El As Variant, k As Long, currMonth As Long
Set sh = ActiveSheet 'use here your sheet
lastRow = sh.Range("L" & Rows.count).End(xlUp).row
currMonth = CLng(Month(Date)) 'the current month reference
arr = sh.Range("L10:L" & lastRow).Value 'load the range to be processed in an array
ReDim arrF(1 To UBound(arr, 1)) 'Redim the final array at the initial dimension of all the range rows
For Each El In arr
If CLng(Mid(El, 5, 2)) = currMonth + 2 Then
'If CLng(Month(El)) = currMonth + 2 Then 'if your cells are date formatted...
k = k + 1: arrF(k) = El 'fill the final array with the appropriate dates
End If
Next
ReDim Preserve arrF(k) 'Keep only the non empty array elements
'Drop the array content in the columnn N:N, at once:
sh.Range("N10").Resize(UBound(arrF)).Value = WorksheetFunction.Transpose(arrF)
End Sub
If your L:L range is Date formatted, you must only comment/delete the line
If CLng(Mid(El, 5, 2)) = currMonth + 2 Then
and un-comment the next one...

Rather than converting and finding the current date into text, it is more accurate to convert the data of cells based on the current date to date data to compare.
Sub testDate()
Dim y As Integer, y1 As String
Dim m As Integer, m1 As String, d1 As String
Dim sDate As Date, eDate As Date
Dim TargetDay As Date
Dim rngDB As Range, rng As Range
Dim Ws As Worksheet
Set Ws = ActiveSheet
y = Year(Date)
m = Month(Date)
sDate = DateSerial(y, m + 2, 1)
eDate = DateSerial(y, m + 3, 0) 'Last day
With Ws
Set rngDB = .Range(Range("L10"), .Range("L" & Rows.Count).End(xlUp))
End With
For Each rng In rngDB
y1 = Left(rng, 4)
m1 = Mid(rng, 5, 2)
d1 = Right(rng, 2)
TargetDay = DateSerial(y1, m1, d1)
If TargetDay >= sDate And TargetDay <= eDate Then
Debug.Print rng.Address(0, 0, xlA1)
End If
Next rng
End Sub

Related

Validate the date column whether it is in MMDDYY format or not

In an Excel sheet, one column is with date and we need to validate all the values in that column and check whether they are in MMDDYY format or not. If not, we need to highlight that specific cell with a colour.
Sub effectivedate()
Dim a As Integer
With ThisWorkbook.Sheets("sheet2")
For a = 2 To .Range("e" & Rows.Count).End(xlUp).Row
k = .Range("e" & a)
p = Len(k)
If Application.WorksheetFunction.Count(k) = 1 And p <> 6 Then
.Range("e" & a).Interior.ColorIndex = 6
End If
Next
End With
End Sub
Please, test the next code. It creates the appropriate date from existing Date or String and color the cells keeping text with a length different from 6:
Sub MakeDateMMDDYY()
Dim ws As Worksheet, a As Long, lastR As Long
Dim txtD As String, arr, arrFin, rngCol As Range, colLett As String
colLett = "F" 'the column letter where to be returned the processing result
'if the code returns what you need, you can replade F with E
Set ws = ThisWorkbook.Sheets("sheet2")
lastR = ws.Range("E" & rows.count).End(xlUp).row
arr = ws.Range("E2:E" & lastR).value 'place the range in an array for faster iteration
ReDim arrFin(1 To UBound(arr), 1 To 1) 'redim the array to receive the processing result
For a = 1 To UBound(arr)
txtD = ws.Range("E" & a + 1).text 'place the cell text in a string variable
If Len(txtD) = 6 Then
'create a date from the string and place it in the final array:
arrFin(a, 1) = DateSerial(CLng(Right(txtD, 2)) + 2000, CLng(left(txtD, 2)), CLng(Mid(txtD, 3, 2))): 'Stop
Else
arrFin(a, 1) = txtD 'place the string in the final array
If rngCol Is Nothing Then
Set rngCol = ws.Range(colLett & a + 1) 'first time create the range to be colored
Else
Set rngCol = Union(rngCol, ws.Range(colLett & a + 1)) 'then, use a Union for the next cells to be colored
End If
End If
Next
With ws.Range(colLett & 2).Resize(UBound(arrFin), 1) 'format the range and drop the final array result
.NumberFormat = "MMDDYY"
.value = arrFin
End With
If Not rngCol Is Nothing Then rngCol.Interior.ColorIndex = 6 'color the range keeping the cells to be colored
End Sub

Increment date column by VBA excel

if i have a column in excel in following format:
"dd/mm/yyyy hh:mm:ss" and i want to increase the hour value by 1.
I add 1/24 to that cell and is done.
my problem is that files where i need this correction have around 15000 rows and operation is taking around 2 minutes.
the code i use is:
Set rngSel = .Range("A2:A10000")
For Each cell In rngSel
cell.Value = cell.Value + dif / 24
Next cell
is it possible somehow to do it faster?
You could try:
Option Explicit
Sub test()
Dim arr As Variant
Dim Initial_DateTime As Date
Dim i As Long
With ThisWorkbook.Worksheets("Sheet1")
arr = .Range("A2:A10000")
For i = LBound(arr) To UBound(arr)
Initial_DateTime = arr(i, 1)
arr(i, 1) = DateAdd("h", 1, Initial_DateTime)
Next i
.Range("A2:A1000").Value = arr
End With
End Sub
As mentioned in the comments, it is much quicker to load the range into a matrix and handle the incrementation of the dates in memory. I have built upon your code for the following example.
Sub IncrementDateColumnByVBA()
Dim rngSel As Range
Dim DateArray() As Variant
Dim i As Long
Dim dif As Byte
dif = 1
Set rngSel = ActiveSheet.Range("A2:A10")
'Write range to a matrix
DateArray = rngSel.Value
'Loop matrix
For i = LBound(DateArray) To UBound(DateArray)
DateArray(i, 1) = DateArray(i, 1) + dif / 24
Next i
'Write matrix to worksheet
rngSel.Value = DateArray
End Sub

VBA for Extracting Data Between 2 Dates From Different Product Sheets to Main sheet

I'm trying to Extract Products Sales From Different Sheets depends on DATES( Between Two Dates), In the mainsheet, I have Two Columns : A for Dates; B for Sales Numbers. I'm new to VBA and trying to write code from learnt Youtube Videos, So far I can be able retrieve Only Column A values i.e, Only Dates, But I could not get the Sales values along with the Dates. I'm writing the Code Down here, Could you please check it once and let me know where and what exactly the mistake arise, your Suggestion Could helpful to me. Thank you in Advance. :)
Private Sub CommandButton1_Click()
Dim sh As Worksheet, Psh As String, x As Date, y As Date
Sheet8.Columns("A").NumberFormat = "m/d/yyyy"
Psh = Me.Shproducts ' Shproducts is Command Button Name
Set sh = Worksheets(Psh)
x = CDate(Me.TextBox1) ' Start Date
y = CDate(Me.TextBox2) ' End Date
Dim i As Long, Myrange As Range, Lastrow As Long
For i = 3 To sh.Range("F" & Rows.Count).End(xlUp).Row
If sh.Cells(i, 1) >= x And sh.Cells(i, 1) <= y Then
Sheet8.Range("A1000").End(xlUp).Offset(1, 0) = sh.Cells(i, 1)
Sheet8.Range("B1000").End(xlUp).Offset(1, 0) = sh.Cells(i, 2)
End If
Next i
End Sub
i haven't tested it, but you might want to do something like this. so this is based on your code:
Private Sub CommandButton1_Click()
Dim sh As Worksheet, Psh As String, x As Date, y As Date
Dim i As Long, Myrange As Range, Lastrow As Long
Dim destinationRange As Range, c As Range, sourceRange As Range
Dim counter As Long
Dim currentDate As Date, currentSales As Double
Sheet8.Columns("A").NumberFormat = "m/d/yyyy"
Psh = Me.Shproducts ' Shproducts is Command Button Name
Set sh = Worksheets(Psh)
x = CDate(Me.TextBox1) ' Start Date
y = CDate(Me.TextBox2) ' End Date
Set destinationRange = Sheet8.Range("A100000").End(xlUp).Offset(1, 0)
Set sourceRange = Range(sh.Range("F3"), sh.Range("F3").End(xlDown))
For Each c In sourceRange
currentDate = c.Value
currentSales = c.Offset(0, 1).Value
If currentDate >= x And currentDate <= y Then
destinationRange.Offset(counter, 0).Value = currentDate
destinationRange.Offset(counter, 1).Value = currentSales
counter = counter + 1
End If
Next i
End Sub

How to use VBA to copy data from one sheet to another if it fulfill three different conditions?

I wanted to copy data that fulfil a few criteria from one sheet to another using VBA.
My goal:
Copy Cell in column E, F and G in Sheet FP to column R, S and T in Sheet MUOR if it meets my conditions.
My conditions:
(1) Cell in Column D & Cell in Column P (in Sheet MUOR) must meet the condition in Column I of Sheet FP.
(2) If Cell in Column D is empty, skip to next Cell in Column D.
(3) Column R, S or T must be empty before pasting it. If not empty, move to the next cell that meets the condition. (Do not replace or duplicate the data)
Other information: Max Batch No (Column D) per day is 3;
Issue Facing:
My current VBA code doesn't recognise my conditions. It totally ignored my Day 1 data, and it duplicated all the Day 2 data.
Please refer to the attached images.
Sheet MUOR
Sheet FP
My expected Result
Sample Data here
My current code as below:
Sub LinkData()
Dim y As Long
Dim x As Long
Dim z As Long
Dim lr As Long
Dim arr As Variant
Dim FP As Worksheet
Dim MUOR As Worksheet
Set FP = ThisWorkbook.Sheets("FP")
Set MUOR = ThisWorkbook.Sheets("MUOR")
With FP
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
arr = .Range("A1:I" & lr).Value
End With
With MUOR
For y = 11 To 363
For z = y - 1 To y + 8
For x = LBound(arr) To UBound(arr)
If Cells(11 + y, 4) <> "" And Cells(11 + y, 4) & Cells(10 + z, 16) = arr(x, 9) And IsEmpty(Cells(10 + z, 18)) Then
.Cells(10 + z, 18) = arr(x, 5)
.Cells(10 + z, 19) = arr(x, 8)
.Cells(10 + z, 20) = arr(x, 7)
Else
End If
Next x
Next z
Next y
End With
End Sub
Any VBA expert please help me.
Much appreciated!
I think code below should give expected output, but not totally sure, since the workbook uploaded/shared seems to differ from the screenshots in the question.
Option Explicit
Private Sub LinkData()
Dim arrayFromFPSheet() As Variant
arrayFromFPSheet = GetSourceArray()
Dim MUOR As Worksheet
Set MUOR = ThisWorkbook.Worksheets("MUOR")
Dim rangesToLoopThrough As Range
Set rangesToLoopThrough = GetDestinationAreas(MUOR)
With MUOR
Dim area As Range
For Each area In rangesToLoopThrough.Areas
Debug.Assert area.Rows.CountLarge > 1 And area.Rows.CountLarge < 20
Dim areaFirstRowIndex As Long
areaFirstRowIndex = area.Rows(1).Row
Dim areaLastRowIndex As Long
areaLastRowIndex = area.Rows(area.Rows.Count).Row
Dim readRowIndex As Long
For readRowIndex = areaFirstRowIndex To areaLastRowIndex
If Not IsCellEmpty(.Cells(readRowIndex, "D")) Then
Dim batchNumber As String
batchNumber = CStr(.Cells(readRowIndex, "D"))
Dim writeRowIndex As Long
For writeRowIndex = areaFirstRowIndex To areaLastRowIndex
If IsCellEmpty(.Cells(writeRowIndex, "R")) And IsCellEmpty(.Cells(writeRowIndex, "S")) And IsCellEmpty(.Cells(writeRowIndex, "T")) Then
Dim Grade As String
Grade = CStr(.Cells(writeRowIndex, "P"))
Dim batchNumberAndGrade As String
batchNumberAndGrade = batchNumber & Grade
Dim n As Variant
n = Application.CountIfs(.Range("P" & areaFirstRowIndex, "P" & writeRowIndex), Grade, .Range("R" & areaFirstRowIndex, "R" & writeRowIndex), batchNumber) + 1
Debug.Assert IsNumeric(n)
Dim sourceRowIndex As Long
sourceRowIndex = GetRowIndexOfNthMatch(n, arrayFromFPSheet, batchNumberAndGrade, 9)
If sourceRowIndex > 0 Then
.Cells(writeRowIndex, "R") = arrayFromFPSheet(sourceRowIndex, 5)
.Cells(writeRowIndex, "S") = arrayFromFPSheet(sourceRowIndex, 8)
.Cells(writeRowIndex, "T") = arrayFromFPSheet(sourceRowIndex, 7)
End If
End If
Next writeRowIndex
End If
Next readRowIndex
Next area
End With
End Sub
Private Function GetDestinationAreas(ByVal someSheet As Worksheet) As Range
' Crudely clusters/groups destination sheet into areas (which
' should be date-specific, although this function will not check/verify
' output).
Const START_ROW_INDEX As Long = 10
Dim outputRange As Range
Set outputRange = someSheet.Range("C" & START_ROW_INDEX, "C" & someSheet.Rows.Count)
On Error Resume Next
Set outputRange = outputRange.SpecialCells(xlCellTypeConstants) ' Will raise error if no constants found.
On Error GoTo 0
Debug.Assert Not (outputRange Is Nothing)
Set GetDestinationAreas = outputRange
End Function
Private Function GetSourceArray() As Variant
With ThisWorkbook.Worksheets("FP")
Dim lastRow As Long
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Dim outputArray() As Variant
outputArray = .Range("A1:I" & lastRow).Value
End With
GetSourceArray = outputArray
End Function
Private Function IsCellEmpty(ByVal someCell As Range) As Boolean
' https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/isempty-function
' "IsEmpty only returns meaningful information for variants."
' So using below function instead.
IsCellEmpty = Len(CStr(someCell.Value)) = 0
End Function
Private Function GetRowIndexOfNthMatch(ByVal n As Long, ByRef someArray() As Variant, ByVal someText As String, ByVal targetColumn As Long) As Long
' Returns a 1-based row index of the nth occurrence of text value
' in target column of array or 0 if unsuccessful.
Debug.Assert n > 0
Dim rowIndex As Long
For rowIndex = LBound(someArray, 1) To UBound(someArray, 1)
If someArray(rowIndex, targetColumn) = someText Then
Dim matchCount As Long
matchCount = matchCount + 1
If matchCount = n Then
GetRowIndexOfNthMatch = rowIndex
Exit Function
End If
End If
Next rowIndex
End Function
Thanks for all the information you provided in the question. It makes it easier to answer.

Inserting VBA formula into a defined Range

I'm looping through a table (Sheet4) in a worksheet and inserting an empty column between each original column. In the new, empty columns, I want to insert a VLookup function.
I has successfully inserted the columns and I have successfully held the proper range (proper number of rows too) in a variable called FormulaRange.
I'm having problems with the VLookup. I don't know if it's the way I'm storing my variables or if I need to have a paste function after my Vlookup. Can someone take a look and give me a hand?
*note - I stored FormulaRange as String becuase As Range wouldn't let me pass my code into the variable. As a result I can't use the FormulaRange.Formula Method.
If I were to manually input the VLookup I would write it as =VLOOKUP(B1,RosettaStone_Employees!$A$1:$B$5,2,FALSE) and then copy down the range.
Sub InsertColumnsAndFormulasUntilEndOfProductivityTable()
Dim ActivityRange As Range
Dim UserName As String
Dim FormulaRange As String
Dim i As Integer
Dim x As Long
Dim y As Long
Dim Startrow As String
Dim Lastrow As String
Sheet6.Activate
Set ActivityRange = Range("A1", Range("B1").End(xlDown))
Sheet4.Activate
Range("A1").Select
y = Sheet4.Cells(Rows.Count, 1).End(xlUp).Row - 1
x = (Sheet4.Cells(1, Columns.Count).End(xlToLeft).Column) * 2
For i = 1 + 2 To x Step 2
Columns(i).EntireColumn.Insert
Startrow = 2
Lastrow = y
UserName = Cells(1, i - 1)
FormulaRange = Cells(Startrow, i).Address & ":" & Cells(Lastrow + 1, i).Address
FormulaRange = "=VLookup(UserName, ActivityRange, 2, False)"
Next
End Sub
Thanks
Jonathan
I changed your code a little to get rid of the sheet activates. Also I changed a few things to ranges and included with blocks.
This is untested:
Sub InsertColumnsAndFormulasUntilEndOfProductivityTable()
Dim ActivityRange As Range
Dim UserName As String
Dim FormulaRange As Range
Dim i As Long
Dim x As Long
Dim y As Long
Dim Startrow As Long
Dim Lastrow As Long
With Sheet6
Set ActivityRange = .Range("A1", .Range("B1").End(xlDown))
End With
With Sheet4
y = .Cells(.Rows.Count, 1).End(xlUp).Row - 1
x = (.Cells(1, .Columns.Count).End(xlToLeft).Column) * 2
For i = 1 + 2 To x Step 2
.Columns(i).EntireColumn.Insert
Startrow = 2
Lastrow = y
UserName = .Cells(1, i - 1)
Set FormulaRange = .Range(.Cells(Startrow, i), .Cells(Lastrow + 1, i))
FormulaRange.FormulaR1C1 = "=VLookup(R1C[-1],'" & ActivityRange.Parent.Name & "'!" & ActivityRange.Address(1, 1, xlR1C1) & ", 2, False)"
'If you do not want dynamic formulas and just want the value
'then comment out the above and use the below.
'FormulaRange.Value = Application.Vlookup(UserName,ActivityRange,2,False)
Next
End With
End Sub
The R1C1 is a relative nomenclature. When it fills the formulas into the columns it will return the cell relative to the one into which the formula will be filled.
For example, above I use R1C[-1]. This says get the first row of the column directly to the left. So if the formula was being entered into B2 it would return A$1.
The [] denotes the relative address. Without the [] eg R1C1 it would indicate an absolute address and would return $A$1. So R1C1:R4C2 would return a range of $A$1:$B$4.

Resources