How to remove the last charactor and replace `:` by `.` - vba

I have two columns M and U containing employee time record in an Excel sheet but the time format is wrong it is something like 08:13a. I want it look like 08.13 in order to use subtraction formula like =U2-M2 to get the difference. so I want to replace : by . and get ride of the last character using Excel VBA.

if 8:13a is really 8 hours, 13 minutes, then running:
Sub TimeFixer()
For Each r In Selection
ary = Split(Mid(r.Text, 1, Len(r.Text) - 1), ":")
r.Value = TimeSerial(ary(0), ary(1), 0)
r.NumberFormat = "hh:mm:ss"
Next r
End Sub
will produce a time you can use numerically.
EDIT#1:
Formula:
=TIMEVALUE(LEFT(A1,LEN(A1)-1))
for example:
Or in the code replace Selection with something like Range("A1:A100")There are many ways to skin this cat.

Related

Perform IF function in VBA

I use an =IF function
=IF(RIGHT(A1;1)="-";"-"&LEFT(A1;LEN(A1)-1);A1)*1
to shift a minus sign from the end of the cell to the beginning but I'd like to use it in a macro so it is performed on the same column (or the same selection)...
1) Use the the For Each.... loop construct to loop through each cell in a range.
2) If you are wanting to convert "numbers" of the 123- to -123 to a proper number and not text, use the Val command to convert a string to a number.
Note however that if you if you have cell with something like "ABC-", this will become -ABC which VBA then attempts to convert to a number ...and produces zero as a result
Sub MoveMinus()
Dim c As Range
For Each c In Intersect(Selection, Selection.Worksheet.UsedRange)
If (Right(c, 1) = "-") Then
c = Val("-" & Left(c, Len(c) - 1)) 'Val to make the result numeric
End If
Next
End Sub

Select everything to the right of a specific character and delete it from column

My column S needs to only contain one word, however, on import it usually has about three words separated by commas. I would like to only keep the first word in the cell.
For example, my S1 column has something like "x, y, z" and I would like to make S1 only say x. So basically, I am trying to remove everything to the right of the first comma in the cell. I have tried to use Replace, but that isn't working. Is there a simpler way to do this?
My (failing) macro right now:
For i = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
If Cells(i, 19) = "," Then Columns("S:i").Select
Selection.Replace What:=Trim(Right(ActiveCell.Value, 25), InStr(ActiveCell.Value, ",") - 1), Replacement:=""
Next
What you are looking for is a Split function.
It works like this:
Dim str As String: str = "x, y, z"
Debug.Print Split(str, ",")(0)
Result is x
The important parameters for Split are string and delimiter, the number after the function specifies the occurence. So if you wanted to select y, you would put 1 there etc. In that case, you would probably include the space in the delimiter so you would not need to trim the result further.
You can use left with Instr to give you all the characters before the first comma.
ActiveCell = Left(ActiveCell,Instr(ActiveCell,",")-1)
Thanks to #pnuts I was able to complete this task. I was unaware that wildcards could be used in Replace. This is my (working) macro:
Columns("S:S").Replace What:=",*", Replacement:=""

VBA - Select columns using numbers?

I'm looking for an alternative to this code, but using numbers.
I want to select 5 columns, the start column is a variable, and then it selects 5 columns from this.
Columns("A:E").Select
How do I use integers instead, to reference columns? Something like below?
For n = 1 to 5
Columns("n : n + 4") .select
do sth
next n
You can use resize like this:
For n = 1 To 5
Columns(n).Resize(, 5).Select
'~~> rest of your code
Next
In any Range Manipulation that you do, always keep at the back of your mind Resize and Offset property.
Columns("A:E").Select
Can be directly replaced by
Columns(1).Resize(, 5).EntireColumn.Select
Where 1 can be replaced by a variable
n = 5
Columns(n).Resize(, n+4).EntireColumn.Select
In my opinion you are best dealing with a block of columns rather than looping through columns n to n + 4 as it is more efficient.
In addition, using select will slow your code down. So instead of selecting your columns and then performing an action on the selection try instead to perform the action directly. Below is an example to change the colour of columns A-E to yellow.
Columns(1).Resize(, 5).EntireColumn.Interior.Color = 65535
you can use range with cells to get the effect you want (but it would be better not to use select if you don't have to)
For n = 1 to 5
range(cells(1,n).entirecolumn,cells(1,n+4).entirecolumn).Select
do sth
next n
Try using the following, where n is your variable and x is your offset (4 in this case):
LEFT(ADDRESS(1,n+x,4),1)
This will return the letter of that column (so for n=1 and x=4, it'll return A+4 = E). You can then use INDIRECT() to reference this, as so:
COLUMNS(INDIRECT(LEFT(ADDRESS(1,n,4),1)&":"&LEFT(ADDRESS(1,n+x,4),1)))
which with n=1, x=4 becomes:
COLUMNS(INDIRECT("A"&":"&"E"))
and so:
COLUMNS(A:E)
In the example code below I use variables just to show how the command could be used for other situations.
FirstCol = 1
LastCol = FirstCol + 5
Range(Columns(FirstCol), Columns(LastCol)).Select
no need for loops or such.. try this..
dim startColumnas integer
dim endColumn as integer
startColumn = 7
endColumn = 24
Range(Cells(, startColumn), Cells(, endColumn)).ColumnWidth = 3.8 ' <~~ whatever width you want to set..*
You can specify addresses as "R1C2" instead of "B2". Under File -> Options -> Formuals -> Workingg with Formulas there is a toggle R1C1 reference style. which can be set, as illustrated below.
I was looking for a similar thing.
My problem was to find the last column based on row 5 and then select 3 columns before including the last column.
Dim lColumn As Long
lColumn = ActiveSheet.Cells(5,Columns.Count).End(xlToLeft).Column
MsgBox ("The last used column is: " & lColumn)
Range(Columns(lColumn - 3), Columns(lColumn)).Select
Message box is optional as it is more of a control check. If you want to select the columns after the last column then you simply reverse the range selection
Dim lColumn As Long
lColumn = ActiveSheet.Cells(5,Columns.Count).End(xlToLeft).Column
MsgBox ("The last used column is: " & lColumn)
Range(Columns(lColumn), Columns(lColumn + 3)).Select
In this way, you can start to select data even behind column "Z" and select a lot of columns.
Sub SelectColumNums()
Dim xCol1 As Integer, xNumOfCols as integer
xCol1 = 26
xNumOfCols = 17
Range(Columns(xCol1), Columns(xCol1 + xNumOfCols)).Select
End Sub

Trouble with getting DateAdd to correctly formulate

So I'm having two issues that I cannot seem to get unkinked. I run reports from a master sheet based off of a template and each finished sheet will have varying numbers of rows. What each finished sheet has in common are two columns(one for a begin date [Column F] and on for an expiration date[Column H]). For each row with a date in Column F I need to add 60 days to the date and put that date in Column H. I have tried working with variations of:
Dim cell As Range
For Each cell In Selection
cell.Value = cell.Value + 60
Next cell
I have tried this also with combinations of different while statements that I use for other things where I am putting values in one column based off of another, but I can't get them to work either.
Some of the problems I am having are: first, when I do manage to get it to enter a date in Column H it always enters 2/29/1900. It doesn't matter if there's a date in Column F or not, or what that date is. Second, when I try to set a range for the selection (this is when I try to combine with "While" statements) it pastes a date number in the entire range instead of only the cells with a date in Column F.
How can I get the macro to only add a date in Column H if there is a date in Column F, and how can I get the darn thing to add 60 days correctly?
Sub Tester()
Dim c As Range, val
For Each c In ActiveSheet.Range("E2:E100")
val = c.Value
If Len(val) > 0 And IsDate(val) Then
c.Offset(0, 2).Value = val + 60
End If
Next c
End Sub

Collect numbers from a column containing empty cells using Excel VBA

I have a little problem, I occasionally bump into this kind of problem, but I haven’t found a fast solution so far.
So, imagine we have an Excel worksheet and let's suppose that we have a couple of numbers in column ’A’ with some empty cells in it. Altogether (just to make it simple) we have the first 10 cells in column 'A' to observe. For example:
3
(empty cell)
(empty cell)
6
(empty cell)
4
(empty cell)
23
(empty cell)
2
Now in the next step I would like to collect these numbers into another column (for example, column ’B’) using VBA. Obviously I just want to collect those cells which contain a number and I want to ignore the empty cells. So I would like to get a column something like this:
3
6
4
23
2
I have already written the following code, but I’m stuck at this point.
Sub collect()
For i = 1 To 10
if cells(i,1)<>"" then...
Next i
End Sub
Is there an easy way to solve this problem?
Probably the quickest and easiest way is to use Excel's Advanced Filter - the only amendment you'll need to make is it add a field name and criteria. You can even list unique items only:
The VBA equivalent is
Sub test()
With Sheet1
.Range("B1:B8").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=.Range( _
"D1:D2"), CopyToRange:=.Range("F1"), Unique:=False
End With
End Sub
You should be able to use the method in the post int the comments, but you could also use SpecialCells like Range("A:A").SpecialCells(xlCellTypeConstants,xlNumbers).Copy to get all of the filled cells.
Edit: needed constants not formulas.
This will work for any number of rows that you select. It will always output in the next column at the start of your selection e.g. if data starts in B10 it will ooutput in C10
Sub RemoveBlanks()
Dim cl As Range, cnt As Long
cnt = 0
For Each cl In Selection
If Not cl = vbNullString Then
Cells(Selection.Cells(1, 1).Row, Selection.Cells(1, 1).Column).Offset(cnt, 1) = cl
cnt = cnt + 1
End If
Next cl
End Sub
If you wish to loop manually and don't mind specifying the maximum row limit;
Dim i As long, values As long
For i = 1 To 10
If cells(i, 1).Value <> "" Then
values = (values + 1)
' // Adjacent column target
cells(values, 2).value = cells(i, 1).value
End If
Next i