2 Problems with a VBA Macro and Date Formating - excel

I have looked at other posts but cannot find anything that is similar enough to my problems. Any help will be appreciated.
I have a set of dates that come in everyday; the dates come in the following format: DD.MM.YYYY (I live in a country that has the day first). I need the data to change into DD/MM/YYYY. I then use these dates in a Vlookup as part of the data set that holds the information I wish to retrieve.
I need help with the following problems:
Problem # 1
When I use the macro and switch the "." with the "/", days 1 to 12 have been switched to the following format DD/MM/YYYY. However, the actual month and day have switched. Currently working in April so 01.04.2020 has been switched to 04/01/2020 (Reading as January fourth); 04/02/2020 (February second and so on....). How can I prevent this from happening so that everything stays in place and just the "." and the "/" change.
Problem #2
From day 13 and onwards the format looks right “13/04/2020”, however when I use it in the Vlookup, the formula will not bring any results back. In order for the Vlookup to work, I have to go to the cell that I just changed and press delete in front of the first digit, even though there is no space there; in order for the Vlookup to work.
Why does that happen? What can I do it so it work right after replacing the “.” and the “/”
Below is my code
Sub Dates()
Range(Range("G12"), Range("G12").End(xlDown)).Select
Selection.NumberFormat = "dd.mm.yyy"
Selection.Replace What:=".", Replacement:="/", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Selection.NumberFormat = "dd/mm/yyy"
End Sub

Try,
Sub test()
Dim vDB, rngDB As Range
Dim s As Variant
Dim i As Long
Set rngDB = Range("G12", Range("G12").End(xlDown))
vDB = rngDB
For i = 1 To UBound(vDB, 1)
s = Split(vDB(i, 1), ".")
vDB(i, 1) = DateSerial(s(2), s(1), s(0))
Next i
rngDB = vDB
rngDB.NumberFormatLocal = "dd/mm/yyyy"
End Sub
Error Image
Correct Image

Here is a solution for your code as is.
I strongly recommend reading and further understanding How to avoid Select in Excel VBA to improve your code and reduce risk of runtime errors.
If you add this code to the bottom of your existing procedure (as it is shown in your question) it will loop through each cell and re-format it to the correct date value.
Dim myCell As Variant
Dim myRange As Range
Set myRange = Selection
For Each myCell In myRange
myCell.Value = Format(CDate(myCell), "DD/MM/YYYY")
Next
You might find this link helpful also:
Better way to find last used row
If you refine your code taking into account the information in both links, you will end up avoiding .Select and Selection. entirely, and your target range/cell will be less ambiguous.
I'd reformat it as follows:
Note: I have written this on Sheet1 of a new workbook, you would need to change the Sheets("...") reference to match your sheet name.
Sub dates()
Dim myRange As Range
Dim LastRow As Long
Dim myCell As Range
With ThisWorkbook.Sheets("Sheet1")
LastRow = .Cells(.Rows.Count, 7).End(xlUp).Row
Set myRange = Range("G12:G" & LastRow)
For Each myCell In myRange
myCell.Value = Replace(myCell, ".", "/")
myCell.Value = Format(CDate(myCell), "DD/MM/YYYY")
Next myCell
End With
End Sub
Now it's a lot clearer where on our workbook we are making changes which helps improve readability for yourself and others (such as other users on SO) along with reduces ambiguity and risk of RunTime errors.

Thanks for the text to column advise this is what I did for it to work:
Sub Dates ()
Dim rg As Range
Set rg = Range("G12").CurrentRegion
rg.TextToColumns Destination:=Range("H2"), ConsecutiveDelimiter:=True, DataType:=xlDelimited, Other:=True, OtherChar:="."
lr = ActiveSheet.Cells(Rows.Count, "G").End(xlUp).Row
Range("K2").Formula = "=DATE(J2,I2,H2)"
Range("K2").AutoFill Range("K2:K" & lr)

Related

How to use Range with Variable in VBA [duplicate]

I want to select the formatted range of an Excel sheet.
To define the last and first row I use the following functions:
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
In the next step I want to select this area:
Formula should look like this:
Range(cells(1, 1), cells(lastRow, lastColumn).Select
However, this is not working. Maybe somebody has an idea what is wrong with it. Thanks a lot!
I recorded a macro with 'Relative References' and this is what I got :
Range("F10").Select
ActiveCell.Offset(0, 3).Range("A1:D11").Select
Heres what I thought : If the range selection is in quotes, VBA really wants a STRING and interprets the cells out of it so tried the following:
Dim MyRange as String
MyRange = "A1:D11"
Range(MyRange).Select
And it worked :) ie.. just create a string using your variables, make sure to dimension it as a STRING variables and Excel will read right off of it ;)
Following tested and found working :
Sub Macro04()
Dim Copyrange As String
Startrow = 1
Lastrow = 11
Copyrange = "A" & Startrow & ":D" & Lastrow
Range(Copyrange).Select
End Sub
I ran into something similar - I wanted to create a range based on some variables. Using the Worksheet.Cells did not work directly since I think the cell's values were passed to Range.
This did work though:
Range(Cells(1, 1).Address(), Cells(lastRow, lastColumn).Address()).Select
That took care of converting the cell's numerical location to what Range expects, which is the A1 format.
If you just want to select the used range, use
ActiveSheet.UsedRange.Select
If you want to select from A1 to the end of the used range, you can use the SpecialCells method like this
With ActiveSheet
.Range(.Cells(1, 1), .Cells.SpecialCells(xlCellTypeLastCell)).Select
End With
Sometimes Excel gets confused on what is the last cell. It's never a smaller range than the actual used range, but it can be bigger if some cells were deleted. To avoid that, you can use Find and the asterisk wildcard to find the real last cell.
Dim rLastCell As Range
With Sheet1
Set rLastCell = .Cells.Find("*", .Cells(1, 1), xlValues, xlPart, , xlPrevious)
.Range(.Cells(1, 1), rLastCell).Select
End With
Finally, make sure you're only selecting if you really need to. Most of what you need to do in Excel VBA you can do directly to the Range rather than selecting it first. Instead of
.Range(.Cells(1, 1), rLastCell).Select
Selection.Font.Bold = True
You can
.Range(.Cells(1,1), rLastCells).Font.Bold = True
You're missing a close parenthesis, I.E. you aren't closing Range().
Try this Range(cells(1, 1), cells(lastRow, lastColumn)).Select
But you should really look at the other answer from Dick Kusleika for possible alternatives that may serve you better. Specifically, ActiveSheet.UsedRange.Select which has the same end result as your code.
you are turning them into an address but Cells(#,#) uses integer inputs not address inputs so just use lastRow = ActiveSheet.UsedRange.Rows.count and lastColumn = ActiveSheet.UsedRange.Columns.Count
I tried using:
Range(cells(1, 1), cells(lastRow, lastColumn)).Select
where lastRow and lastColumn are integers, but received run-time error 1004. I'm using an older VB (6.5).
What did work was to use the following:
Range(Chr(64 + firstColumn) & firstRow & ":" & Chr(64 + lastColumn) & firstColumn).Select.

Excel macro - Selecting cell range with a using number from loop [duplicate]

I want to select the formatted range of an Excel sheet.
To define the last and first row I use the following functions:
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
lastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
In the next step I want to select this area:
Formula should look like this:
Range(cells(1, 1), cells(lastRow, lastColumn).Select
However, this is not working. Maybe somebody has an idea what is wrong with it. Thanks a lot!
I recorded a macro with 'Relative References' and this is what I got :
Range("F10").Select
ActiveCell.Offset(0, 3).Range("A1:D11").Select
Heres what I thought : If the range selection is in quotes, VBA really wants a STRING and interprets the cells out of it so tried the following:
Dim MyRange as String
MyRange = "A1:D11"
Range(MyRange).Select
And it worked :) ie.. just create a string using your variables, make sure to dimension it as a STRING variables and Excel will read right off of it ;)
Following tested and found working :
Sub Macro04()
Dim Copyrange As String
Startrow = 1
Lastrow = 11
Copyrange = "A" & Startrow & ":D" & Lastrow
Range(Copyrange).Select
End Sub
I ran into something similar - I wanted to create a range based on some variables. Using the Worksheet.Cells did not work directly since I think the cell's values were passed to Range.
This did work though:
Range(Cells(1, 1).Address(), Cells(lastRow, lastColumn).Address()).Select
That took care of converting the cell's numerical location to what Range expects, which is the A1 format.
If you just want to select the used range, use
ActiveSheet.UsedRange.Select
If you want to select from A1 to the end of the used range, you can use the SpecialCells method like this
With ActiveSheet
.Range(.Cells(1, 1), .Cells.SpecialCells(xlCellTypeLastCell)).Select
End With
Sometimes Excel gets confused on what is the last cell. It's never a smaller range than the actual used range, but it can be bigger if some cells were deleted. To avoid that, you can use Find and the asterisk wildcard to find the real last cell.
Dim rLastCell As Range
With Sheet1
Set rLastCell = .Cells.Find("*", .Cells(1, 1), xlValues, xlPart, , xlPrevious)
.Range(.Cells(1, 1), rLastCell).Select
End With
Finally, make sure you're only selecting if you really need to. Most of what you need to do in Excel VBA you can do directly to the Range rather than selecting it first. Instead of
.Range(.Cells(1, 1), rLastCell).Select
Selection.Font.Bold = True
You can
.Range(.Cells(1,1), rLastCells).Font.Bold = True
You're missing a close parenthesis, I.E. you aren't closing Range().
Try this Range(cells(1, 1), cells(lastRow, lastColumn)).Select
But you should really look at the other answer from Dick Kusleika for possible alternatives that may serve you better. Specifically, ActiveSheet.UsedRange.Select which has the same end result as your code.
you are turning them into an address but Cells(#,#) uses integer inputs not address inputs so just use lastRow = ActiveSheet.UsedRange.Rows.count and lastColumn = ActiveSheet.UsedRange.Columns.Count
I tried using:
Range(cells(1, 1), cells(lastRow, lastColumn)).Select
where lastRow and lastColumn are integers, but received run-time error 1004. I'm using an older VB (6.5).
What did work was to use the following:
Range(Chr(64 + firstColumn) & firstRow & ":" & Chr(64 + lastColumn) & firstColumn).Select.

How to replace all values in a column by a specific value in Excel VBA?

Suppose this is my initial excel sheet
I want to replace all the non-empty cells in column C with the string "Title" excluding the column header.
The output should be like this:
Thank you!
Try below sub.
Sub FillTitle()
Dim lrow As Long
Dim rng As Range
lrow = Cells(Rows.Count, "C").End(xlUp).Row 'Detect last data entry row in Column C.
For Each rng In Range("C2:C" & lrow)
If rng <> "" Then
rng = "Title"
End If
Next rng
End Sub
Range has Replace method:
Sub ReplaceAll()
With ActiveSheet
Application.Intersect(.UsedRange, .UsedRange.Offset(1), .Columns("C")).Replace What:="*", Replacement:="Tester"
' reset Find/Replace pattern to default for further use
.Cells.Find What:="", LookIn:=xlFormulas, SearchOrder:=xlRows, LookAt:=xlPart, MatchCase:=False
End With
End Sub
For small table, just run a for loop:
for row=2 to something_large
if cells(row,col)<>"" then cells(row,col)="title"
next row
for large table, your best bet is to record a macro: create a filter on the column, filter to nonblank, select all rows, then paste to them. Once you have the macro, modify for general use.
You can choose not use loop as well by using a simple code line like below which will perform the same action.
Range("C2:C" & Range("B" & Rows.Count).End(xlUp).Row).SpecialCells(xlCellTypeConstants).Value = "Title"

Converting AM/PM time stored as text in to military time

I have excel sheet report with several hundreds of lines and in one of the cells I have time value stored as AM/PM.
The problem is that cell values are as stored as a text values and I can’t change it as it is generated from the system as is.
I need to sort the sheet by time to be able to work on it, but problem is, for example 01:00 PM will come before 09:00 AM or 08:00 AM, etc.
Now I have some code to get around this:
Sub DepTime()
'12:00 AM
With Range("D1:D1000")
Set c = .Find("12:00 AM", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Activate
c.Value = "00:00"
Set c = .FindNext
If c Is Nothing Then
GoTo SearchTime2
End If
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
SearchTime2:
End With
'12:15 AM
With Range("d1:d1000")
Set c = .Find("12:15 AM", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Activate
c.Value = "00:15"
Set c = .FindNext
If c Is Nothing Then
GoTo SearchTime3
End If
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
SearchTime3:
... Code goes like this all the way to 11:45pm...
End With
End Sub
Code goes all the way to 11:45pm...
I spent hours doing this; it helps, but there must be abetter way of doing it... Also, i only have code for 15min intervals of time, but if I get a specific time like 1:13 PM, it does not help me... Is there a way to convert any given time from text to military time...
Any assistance would be super appreciated.
Change the format as #braX mentioned and then use .TextToColumns to format the entire range/column in one go. No loops required.
In below example, I am assuming the data is in Col A in Sheet1. Change as applicable.
With Sheet1
With .Columns(1)
.NumberFormat = "hh:mm"
.TextToColumns Destination:=Sheet1.Range("A1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True
End With
End With
BTW, you do not need VBA for this. You can do the same thing in a few mouse clicks as well as shown below.
So to go with what you saying you want to convert all these text's that look like time to real timevalues without the AM/PM formatting?
#SiddharthRout have given an easy example how to do so. Here is an alternative way:
You can loop through a range of cells in your column and use Timevalue with Format functions to re-arrange your data:
Sub Test1()
Dim rng As Range, lr As Long
With ThisWorkbook.Sheets("Sheet1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A1:A" & lr)
rng.NumberFormat = "HH:MM"
For Each cl In rng
cl.Value = Format(TimeValue(cl.Value), "HH:MM")
Next cl
End With
End Sub
You can achieve the same thing to do it in one go with the help of .Evaluate:
Sub Test2()
Dim rng As Range, lr As Long
With ThisWorkbook.Sheets("Sheet1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A1:A" & lr)
rng.NumberFormat = "HH:MM"
rng.Value = .Evaluate("=TEXT(TIMEVALUE(" & rng.Address & "), ""HH:MM"")")
End With
End Sub
I want to say big thank you to all of you for your time and suggestions, but unfortunately none is working for me. :(
All the methods mentioned above are doing needfull and add correct properties to the cells. So if I now click on any of the cells and manualy re-type, for example 1:30 PM - IT WILL INDEED CONVERT to 13:30, but none of the cells that already contain time information will change - they still remain as 1:30 PM (or whatever info they contain).
Not sure if I have to mention that I get the report in RTF file and I have my macro importing and formating everything to excell. I have everything else working, except fot the time column. I just can't get around it... :(
So here you can see the output of any of above methods.
As you can see if I manually click on cells and enter the time, it converts to military time exactly as I wanted. However, none of the cells already filled out are converting automatically.
Hope this function will help ....
Sub DepTime()
Dim cel As Object
Dim lr As Long: lr = ActiveSheet.Cells(Rows.Count, 3).End(xlUp).Row
For Each cel In Range("C1:C" & lr)
cel.Value = Format(CDate(cel.Value), "HH:mm")
Next
End Sub
Once more I want to thank everyone who posted a reply and took their time to help out. I finaly figure out why it wasn't working... Since iported from RTF, I had space at begining and end of time value which i haven't noticed... :(
Anways, this is my workig solution:
Sub DepTime()
Range("D1:D1000").Select
Dim A As Range
Set A = Selection
For Each cell In A
cell.Value = WorksheetFunction.Trim(cell)
Next
Columns("D:D").Select
Selection.NumberFormat = "hh:mm"
End Sub

VBA - Copy filtered data values from one workbook to another

I copy large amounts of filtered data (visible data and values only) from one workbook to another but the process is very slow. I would like to try bypassing the clipboard to see if that improves the speed but I keep getting the error Object does not support this property or method. Here is the code that is failing:
ActiveSheet.SpecialCells(xlCellTypeVisible).Copy _
Destination:=Windows("Some Report").Worksheets( _
"Some Sheet").Range("A1").Values
I've tried different variations but receive the same error.
What about just setting the cells.value equal to each other? This little snippet assumes you want to copy the cells into the same destination cell, so you'd have to adjust for that if that's not what you're doing.
Private Sub worksheet_selectionchange(ByVal Target As Range)
Dim lastRow As Integer
Dim lastCol As Integer
Dim wb1 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set wb1 = ThisWorkbook
Set ws1 = wb1.Sheets(1)
Set ws2 = wb1.Sheets(2)
lastRow = ws1.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lastCol = ws1.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Column
For i = 1 To lastRow: For j = 1 To lastCol
If ws1.Cells(i, j).Value > 5 And Not ws1.Cells(i, j).Hidden Then
ws2.Cells(i, j).Value = ws1.Cells(i, j).Value
End If
Next: Next
End Sub
Unfortunately without seeing much else of your code I can't prove much else, but this is the only alternative to copying and pasting that I know of.
I have done this without actually using the SpecialCells(xlCellTypeVisible) method and it copies and pastes perfectly. I first filter the data with an array, then I just use the Worksheets("Sheet1").Range("A1:" & last column & last row).Copy destination:=Worksheets("Sheet2").Range("E5") method and it works just fine on Office 2010. I did look into the SpecialCells(xlCellTypeVisible) method but it was never necessary.
Maybe if you put UsedRange.SpecialCells(xlCellTypeVisible).Copy it would work?

Resources