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
Related
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"
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)
I'm creating a VBA application with some forms. When the data is inserted into the Table, Column A calculates a value with a formula. After that I need to copy the resulting value (like paste special, values only) into the adjacent Row
I just need to know how to select the last row everytime. I have tried with ActiveCell, Find, Range etc. but none are working
Selection.Copy
ActiveCell.Offset(0, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Try this:
Selection.Copy
ActiveSheet.Cells(Rows.Count, ActiveCell.Column).End(xlUp).PasteSpecial Paste:=xlPasteValues
From a programming point of view, it's much better to define variables rather than using Selection, .select, or ActiveCell, etc... This code will place the cell you are looking for into the variable r, assuming the first header row (A1) is not empty. If you don't want to make any assumptions about the first or last row, see the last answer on this page. In the code below, this would mean replacing Set r = r.End(xlDown) with Set r = sh.Range("A:A").Find("*", Range("A1"), SearchDirection:=xlPrevious)
Option Explicit
Sub test()
Dim sh As Worksheet, r As Range
Set sh = ThisWorkbook.Worksheets("Sheet1")
Set r = sh.Range("A1")
Set r = r.End(xlDown)
r.Select 'remove after code has been tested and you know it works
End Sub
If you have more questions, just ask. There's a lot of help available to help you program in the proper way here on StackOverflow.
Thanks all,
I fixed it with help of both
LastValue = Range("Table1[Opportunity no.]").End(xlDown).Value
Set ws = Worksheets("Datos")
iRow = ws.Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row
With ws
.Cells(iRow, 2).Value = LastValue
End With
I have been trying t0 find the row count of a particular column using vba,
I have found that it can be done by using two methods, all three of which involve range ( I pretty much found this by a simple google search and then editing what I found to suit my needs)
However I feel that it would suit me better if I understood what each of them did and how they were different from each other
The two codes I used are as follows :
i = Application.CountA(Range("A:A"))
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Could anyone please explain me how these two work and what is the difference between the two? Also, if you know any other way that's efficient, it would be helpful if you do share it here.
i = Application.CountA(Range("A:A"))
This returns the count of all the cells in column A that contain a value. They do not have to be in consecutive cells.
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
This goes to the very last cell at the bottom of column A then does the equivalent of pressing the End key and then the up arrow key. This will return the row index of last cell in the column that contains a value.
Using Find is superior
Unlike xlUp caters for hidden cells (but not filtered out cells)
Avoids false reporting for blank or the far less likely full column. See here
Find method
Sub GetLastA()
Dim rng1 As Range
Set rng1 = Columns("A:A").Find("*", [a1], xlFormulas)
If Not rng1 Is Nothing Then
MsgBox "last row is " & rng1.Row
Else
MsgBox "no used cells found", vbCritical
End If
End Sub
Sub row_cownt()
Dim R As Double
Dim C As Double
R = Cells.Find(What:="*", LookIn:=xlValues, SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
C = Cells.Find(What:="*", After:=[A1], SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column
MsgBox "Row =" & R
MsgBox "Column =" & C
End Sub
I am trying to find if a certain date is in a range of dates.
This is the range of dates:
01/01/2013
11/02/2013
29/03/2013
20/05/2013
01/07/2013
05/08/2013
02/09/2013
14/10/2013
11/11/2013
25/12/2013
26/12/2013
Here is the VBA code:
' Format Holiday Rows '
With ConfigData.Range("B8:B18")
Set holidays = .Find(s1.Cells(row_count, 1))
If Not holidays Is Nothing Then
MsgBox s1.Cells(row_count, 1)
End If
End With
In the above code, the first MsgBox that pops up reads "11/01/2013". This makes absolutely no sense, as that value is not in the range.
Note: ConfigData.Range("B8:B18") refers to the range of dates shown above.
ALSO: This code is within a for loop that increments the value of s1.Cells(row_count, 1). Starting at 01/01/2013 until 31/12/2013
If you just want to confirm a calendar day in your series is within the holiday list, then you could even use vlookup:
Dim strFound As String
On Error Resume Next
strFound = Application.Vlookup(s1.Cells(row_count, 1), .Range("B8:B18"), 1, 0)
If IsError(strFound) Then
MsgBox "Not Found"
Else
'-- Found
End If
On Error GoTo 0
The following code works for me:
Sub thing()
Dim cell As Range, _
holidays As Range
For Each cell In Range("D1:D365")
With Range("A1:A11")
Set holidays = .Find(cell.Value, LookIn:=xlValues, lookat:=xlWhole)
If Not holidays Is Nothing Then
Debug.Print cell.Value
End If
End With
Next cell
End Sub
If this doesn't work, I'd suggest it's likely you have a cell formatting issue. Select one of your date cells. Go to the immediate window (Alt+F11, then Ctrl+G from Excel), type ? Selection.Value2 and press enter. Does that return a numeric value (~41000)?
Alternatively, you could reenter the dates in a completely new sheet (enter the first couple manually and drag down, do not copy and paste as formatting will be copied also) and try again. This should at least remove odd formatting as a potential issue.
It is important to note that excel uses american date formatting. ie mm/dd/yyyy and it can therefore be a little tricky to get the .Find() function to work properly. Make sure your variables are formated properly in order for excel to hopefully give you what you're looking for:
Dim strdate As String
Dim aCell As Range
strdate = ActiveSheet.Cells(1,1)
strdate = Format(strdate, "Short Date")
On Error Resume Next
Set aCell = Cells.Find(What:=CDate(strdate), After:=Range("A1"), LookIn:=xlFormulas , LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False)
If rCell Is Nothing Then
MsgBox("Date cannot be found. Try Again")
End If
End Sub
Of course there are a lot of annoying things that can happen with the date formatting, but this is assuming the dates you're looking for ar in the "Short Date" format.
'To find a cell elsewhere in a worksheet with the same specific date as a reference cell:
'First copy all dates to cells immediately to their left.
'Format the copied cells as "General"
'Run this code - then use the dateRow and DateCol variables (eg in vlookup)
'Works in Excel 2013 (The "General" column must not be hidden - Hide by formatting in background colour)
Dim dateVal
Dim DateRow
Dim DateCol
dateVal = Range("j8").Value 'must be in general format
Cells.Find(What:=dateVal, After:=ActiveCell, LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, SearchFormat:=False).Activate
DateRow = ActiveCell.Row
DateCol = ActiveCell.Column
MsgBox (DateRow & " " & DateCol)
End Sub