I have two columns that contain information in the following format.
Column A - 35 days
Column B - 29 days
How can i subtract the two columns to show just a number, like 35 days - 29 days = 6.
The following equation should do the trick
= VALUE(MID(A1, 1, FIND(" ",A1))) - VALUE(MID(B1, 1,FIND(" ",B1)))
First we find the index of the space " " in the cell using FIND(" ", A1). Then we cut the string in the cell and we take the first index to the index of the space by MID(A1, 1, ...). Then we convert this value to a number using VALUE(...).
If all your days always have 2 digits, none of them are >= 100, then we can simplify this by
= VALUE(MID(A1, 1, 2)) - VALUE(MID(B1, 1,2))
But, I think the general case is preferable.
You can use the Replace function and replace days with an empty string, then you can convert your string to a integer with CInt:
?CInt(Replace("39 days", "days", ""))-CInt(Replace("25 days", "days", ""))
14
Edit:
or like Jeeped suggested in the commment you could use:
?Val("39 days")-Val("25 days")
14
You can also use SUBSTITUTE() function.
=(TRIM(SUBSTITUTE(A1,"days",""))*1)-TRIM(SUBSTITUTE(B1,"days",""))*1
Edit:
Only SUBSTITUTE() will also work.
=SUBSTITUTE(A1,"days","")-SUBSTITUTE(B1,"days","")
Change the cell number format to Custom with a format mask of 0 \d\a\y\s. Now type in 35 into A1 and 29 into B1. Now, while the cells display 35 days and 29 days they can be conventionally used like,
'on the worksheet
=a1-b1
'in vba
i = range("a1").value - range("b1").value
'in vba to see *35 days* in the Immediate window
?range("a1").text
You could even get a little fancier with a custom number format of,
[>1]0 \d\a\y\s;[=1]0 \d\a\y;0 \d\a\y\s;
Try this code:
Sub SumDays()
Dim lastRow As Long, i As Long, cellA As String, cellB As String
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastRow
cellA = Cells(i, 1).Value
cellB = Cells(i, 2).Value
Cells(i, 3).Value = CInt(Mid(cellA, 1, InStr(1, cellA, " ") - 1)) + CInt(Mid(cellB, 1, InStr(1, cellB, " ") - 1))
Next
End Sub
Related
I am trying to make a macro in VBA-Excel that allows me to generate a simple sum (using a + sign) in a specific cell; keeping all the numbers in the formula of the cell. I mean i need that the output formula "hold" the values/adding formulas that are in a certain range. The numbers should be added automatically to the + formula. An special restriction is that in the event that there is no number in a cell of the range, the formula should not incorporate "0".
For example The data shown below are to numbers or sums within a Range (A1:A7):
A1: 5
A2: 7,5 --> =5+2,5
A3:
A4: 1
A5: 1 --> =3-2
A6:
A7: 5,5
Where A2: =5+2,5 and A5: =3-2. The other terms are just numbers.
Range of the example = A1:A7
Formula Output of the macro on B1 (or Cells(1, 2)) should be:
=5 + 5 + 2,5 + 1 + 3 - 2 + 5,5 (20)
The pseudo code should be like:
for i = 1 to 7 -> Cells(1, 2).FormulaLocal = if Cell(i,1) is a number (or an existing adding formula with values), add to the current formula. if its blank or 0, skip to next i (or row).
Output: formula "= Value1(5) + formula2(5+2,5) + Skip0Value3() +
Value4(1) and so on..
I already tried the following code with partially positive results:
Sub summanual()
Dim i As Integer
Dim y As String
For i = 1 To 7
If Cells(i, 1) <> 0 Then
y = Cells(i, 1)
Cells(1, 2).FormulaLocal = Cells(1, 2).FormulaLocal & "+" & y
End If
Next i
If Cells(1, 2) <> 0 Then
Cells(1, 2).FormulaLocal = "=" & Cells(1, 2).FormulaLocal
Else
Cells(1, 2) = ""
End If
End Sub
This works only for positives values. Negatives values are added
like "+-" to the output formula.
The output formula only stores the results of the origin cell. Ex:
A2 is 5+2,5 but it is added like 7,5. It should be split. Same with
A5.
Is fine to declare "y" variable as String in this case?
Any other optimization? Maybe there is a completely different
approach with better and faster result? Just new with vba-excel
Any help would be appreciated
Thanks
I have to convert some formatted text to excel time, but I could not find a solution by myself.
Here are some examples of the input text and how it should be converted:
- 1 Hour 14 minutes ==> 01:14:00
- 1 minute. ==> 00:01:00
- 1 Hour 1 minute ==> 01:01:00
- 2 minutes ==> 00:02:00
- 3 minutes 12 seconds ==> 00:03:12
- 29 seconds ==> 00:00:29
Observe that some times there are both minutes and seconds and some others only one of minutes/seconds, besides some times you find minutes (plural) and some others just minute (singular). Finally, some punctuation signs could be in the text some times.
The data is in a spreadsheet column and I want to extract the excel formatted time in a different column on the spreadsheet.
I've tried different versions of TimeValue() and DateValue() and some nested replace() all of them in a cell formula, but none of them worked for all cases.
Could you give me an idea or some advice on how to approach this problem?
Thanks,
Paul
I played with your question for a day and see that others have done the same. I admire the solution offered by Ron Rosenfeld using FilterXML which I briefly considered and discarded as too outlandish. It isn't. But neitehr is it neat. For "neat" look no further than the UDF below. Call it from the worksheet with something like =TextToTime(A1) and be sure to format the cell you put this in as Time, perhaps like hh:mm:ss.
Function TextToTime(Cell As Range) As Double
Dim Fun(2) As String
Dim Txt() As String
Dim Tmp As Variant
Dim i As Integer
Txt = Split(Cell.Value)
For i = 1 To UBound(Txt)
If Not IsNumeric(Txt(i)) Then
Tmp = 0
Tmp = InStr("HMS", UCase(Left(Trim(Txt(i)), 1)))
If Tmp Then
Fun(Tmp - 1) = Val(Txt(i - 1))
End If
End If
Next i
For i = LBound(Fun) To UBound(Fun)
If Fun(i) = "" Then Fun(i) = 0
Next i
TextToTime = TimeValue(Join(Fun, ":"))
End Function
This function is very versatile. It can translate strings like "5 hours 10 minutes 15 seconds" or "5 hours, 10 minutes, 15 seconds" (with commas) or even "5 hours & 10 minutes and 15 seconds". It needs the spaces around the numbers but doesn't balk at extra spaces or typos. It fails on "75 minutes and 66 seconds" but that could be dealt with if it's an issue. The key advantage of VBA is that almost anything can be dealt with using just a few extra lines of code. Worksheeet functions don't have that capability.
Since you did not include VBA as a tag, here are some formula solutions.
If you have Windows Excel 2013+ with the FILTERXML function, you can use the following:
=IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'hour')]/preceding-sibling::*[1]")/24,0)+
IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'min')]/preceding-sibling::*[1]")/1440,0)+
IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'sec')]/preceding-sibling::*[1]")/86400,0)
If you do not have the FILTERXML function:
Create a named formula:
Formulas → Defined Names → Define Name → New Name → seq_99 → Refers to: → =IF(ROW(INDEX($A:$A,1,1):INDEX($A:$A,255,1))=1,1,(ROW(INDEX($A:$A,1,1):INDEX($A:$A,255,1))-1)*99)
Then use this formula:
=IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("hour*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/24,0)+
IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("min*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/1440,0)+
IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("sec*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/86400,0)
Algorhythm:
Find the string hour or min or sec
Return the node prior to each of those strings
divide by the appropriate factor to create an excel time value
Note: Custom format column B as hh:mm:yy
As pointed out by #ScottCraner in the comments, the formulas can be shortened by creating an array formula:
Using FILTERXML:
=SUM(IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,"&{"'hour'","'min'","'sec'"}&")]/preceding-sibling::*[1]")/{24,1440,8640},0))
without FILTERXML:
=SUM(IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH({"hour*","min*","sec*"},TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/{24,1440,8640},0))
In some earlier versions of Excel, you may need to "confirm" this array-formula it by holding down ctrl + shift while hitting enter. If you do this correctly, Excel will place braces {...} around the formula as observed in the formula bar
Well, you can take this and edit it to suit your needs:
Here is the formula :
=IF(IFERROR(FIND("da",A2,1),0)>0,LEFT(A2,FIND(" ",A2,1)-1)*24,0)+IFERROR(1*MID(A2,FIND(" ",A2,FIND(" ",A2,1)+1),FIND(" ",A2,FIND(" ",A2,FIND(" ",A2,1)+1)+1)-FIND(" ",A2,FIND(" ",A2,1)+1)),0*1)
I just wanted the date converted to hours so you can finish to what you want.
If you decide to use VBA and you keep the same format in Column A you could use the below code:
Code:
Sub Converter()
Dim i As Long, y As Long, LastRow As Long
Dim arrData As Variant, arrLine As Variant
Dim Hours As String, Minutes As String, Seconds As String
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
arrData = .Range("A1:A" & LastRow)
For i = LBound(arrData) To UBound(arrData)
Hours = "00"
Minutes = "00"
Seconds = "00"
arrLine = Split(arrData(i, 1), " ")
For y = LBound(arrLine) To UBound(arrLine)
If InStr(1, UCase(arrLine(y)), "HOUR") > 0 Then
Hours = Right("0" & arrLine(y - 1), 2)
ElseIf InStr(1, UCase(arrLine(y)), "MINUTE") > 0 Then
Minutes = Right("0" & arrLine(y - 1), 2)
ElseIf InStr(1, UCase(arrLine(y)), "SECOND") > 0 Then
Seconds = Right("0" & arrLine(y - 1), 2)
End If
Next y
.Range("B" & i).Value = Hours & ":" & Minutes & ":" & Seconds
Next i
End With
End Sub
Output:
I have to convert some formatted text to excel time, but I could not find a solution by myself.
Here are some examples of the input text and how it should be converted:
- 1 Hour 14 minutes ==> 01:14:00
- 1 minute. ==> 00:01:00
- 1 Hour 1 minute ==> 01:01:00
- 2 minutes ==> 00:02:00
- 3 minutes 12 seconds ==> 00:03:12
- 29 seconds ==> 00:00:29
Observe that some times there are both minutes and seconds and some others only one of minutes/seconds, besides some times you find minutes (plural) and some others just minute (singular). Finally, some punctuation signs could be in the text some times.
The data is in a spreadsheet column and I want to extract the excel formatted time in a different column on the spreadsheet.
I've tried different versions of TimeValue() and DateValue() and some nested replace() all of them in a cell formula, but none of them worked for all cases.
Could you give me an idea or some advice on how to approach this problem?
Thanks,
Paul
I played with your question for a day and see that others have done the same. I admire the solution offered by Ron Rosenfeld using FilterXML which I briefly considered and discarded as too outlandish. It isn't. But neitehr is it neat. For "neat" look no further than the UDF below. Call it from the worksheet with something like =TextToTime(A1) and be sure to format the cell you put this in as Time, perhaps like hh:mm:ss.
Function TextToTime(Cell As Range) As Double
Dim Fun(2) As String
Dim Txt() As String
Dim Tmp As Variant
Dim i As Integer
Txt = Split(Cell.Value)
For i = 1 To UBound(Txt)
If Not IsNumeric(Txt(i)) Then
Tmp = 0
Tmp = InStr("HMS", UCase(Left(Trim(Txt(i)), 1)))
If Tmp Then
Fun(Tmp - 1) = Val(Txt(i - 1))
End If
End If
Next i
For i = LBound(Fun) To UBound(Fun)
If Fun(i) = "" Then Fun(i) = 0
Next i
TextToTime = TimeValue(Join(Fun, ":"))
End Function
This function is very versatile. It can translate strings like "5 hours 10 minutes 15 seconds" or "5 hours, 10 minutes, 15 seconds" (with commas) or even "5 hours & 10 minutes and 15 seconds". It needs the spaces around the numbers but doesn't balk at extra spaces or typos. It fails on "75 minutes and 66 seconds" but that could be dealt with if it's an issue. The key advantage of VBA is that almost anything can be dealt with using just a few extra lines of code. Worksheeet functions don't have that capability.
Since you did not include VBA as a tag, here are some formula solutions.
If you have Windows Excel 2013+ with the FILTERXML function, you can use the following:
=IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'hour')]/preceding-sibling::*[1]")/24,0)+
IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'min')]/preceding-sibling::*[1]")/1440,0)+
IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,'sec')]/preceding-sibling::*[1]")/86400,0)
If you do not have the FILTERXML function:
Create a named formula:
Formulas → Defined Names → Define Name → New Name → seq_99 → Refers to: → =IF(ROW(INDEX($A:$A,1,1):INDEX($A:$A,255,1))=1,1,(ROW(INDEX($A:$A,1,1):INDEX($A:$A,255,1))-1)*99)
Then use this formula:
=IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("hour*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/24,0)+
IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("min*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/1440,0)+
IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH("sec*",TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/86400,0)
Algorhythm:
Find the string hour or min or sec
Return the node prior to each of those strings
divide by the appropriate factor to create an excel time value
Note: Custom format column B as hh:mm:yy
As pointed out by #ScottCraner in the comments, the formulas can be shortened by creating an array formula:
Using FILTERXML:
=SUM(IFERROR(FILTERXML("<t><s>" & SUBSTITUTE(LOWER(A1)," ","</s><s>") & "</s></t>","//s[contains(.,"&{"'hour'","'min'","'sec'"}&")]/preceding-sibling::*[1]")/{24,1440,8640},0))
without FILTERXML:
=SUM(IFERROR(INDEX(TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),-1+MATCH({"hour*","min*","sec*"},TRIM(MID(SUBSTITUTE(TRIM(A1)," ",REPT(" ",99)),seq_99,99)),0))/{24,1440,8640},0))
In some earlier versions of Excel, you may need to "confirm" this array-formula it by holding down ctrl + shift while hitting enter. If you do this correctly, Excel will place braces {...} around the formula as observed in the formula bar
Well, you can take this and edit it to suit your needs:
Here is the formula :
=IF(IFERROR(FIND("da",A2,1),0)>0,LEFT(A2,FIND(" ",A2,1)-1)*24,0)+IFERROR(1*MID(A2,FIND(" ",A2,FIND(" ",A2,1)+1),FIND(" ",A2,FIND(" ",A2,FIND(" ",A2,1)+1)+1)-FIND(" ",A2,FIND(" ",A2,1)+1)),0*1)
I just wanted the date converted to hours so you can finish to what you want.
If you decide to use VBA and you keep the same format in Column A you could use the below code:
Code:
Sub Converter()
Dim i As Long, y As Long, LastRow As Long
Dim arrData As Variant, arrLine As Variant
Dim Hours As String, Minutes As String, Seconds As String
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
arrData = .Range("A1:A" & LastRow)
For i = LBound(arrData) To UBound(arrData)
Hours = "00"
Minutes = "00"
Seconds = "00"
arrLine = Split(arrData(i, 1), " ")
For y = LBound(arrLine) To UBound(arrLine)
If InStr(1, UCase(arrLine(y)), "HOUR") > 0 Then
Hours = Right("0" & arrLine(y - 1), 2)
ElseIf InStr(1, UCase(arrLine(y)), "MINUTE") > 0 Then
Minutes = Right("0" & arrLine(y - 1), 2)
ElseIf InStr(1, UCase(arrLine(y)), "SECOND") > 0 Then
Seconds = Right("0" & arrLine(y - 1), 2)
End If
Next y
.Range("B" & i).Value = Hours & ":" & Minutes & ":" & Seconds
Next i
End With
End Sub
Output:
I have a program that is supposed to read the date from a cell. In that cell, I have given it the value of =NOW() just by typing it into the cell outside of VBA. The cell is formatted as a date and the format is: dd-month (for example; 28-Jan). When VBA reads the cell, it reads it as mm/dd/yyy 00:00:00 AM/PM. Is there a way to make my code read the month from the format I set? A section of my code is below:
dashpos = InStr(1, ThisWorkbook.Worksheets("Main").Cells(2, 15), "-")
curmonth = Right(ThisWorkbook.Worksheets("Main").Cells(2, 15).Value, dashpos + 1)
The cell containing the date is Cell(2,15). I then go on to use the three letters on the month to determine the following month using a Select Case curmonth.
If your format is mm/dd/yyy 00:00:00 AM/PM in the worksheet, then the month will always have two digits. Therefor:
curmonth = CLng(Left(ThisWorkbook.Worksheets("Main").Cells(2, 15).Text, 2))
Sub testDateExtraction()
'Next day in the format you use in the sheet (no matter, in fact...):
Debug.Print Format(ThisWorkbook.Worksheets("Main").Cells(2, 15).Value + 1, "dd-mmm")
'Next month
Debug.Print MonthName(Month(ThisWorkbook.Worksheets("Main").Cells(2, 15).Value) + 1, True)
'If you insists to use the string type data:
Dim strDate As String, strMonth As String
strDate = CStr(Format(ThisWorkbook.Worksheets("Main").Cells(2, 15).Value + 1, "dd-mmm"))
strMonth = Right(strDate, 3)
Debug.Print MonthName(Month(DateValue(Day(Date) & "-" & strMonth & "-2020")) + 1, True)
End Sub
I then go on to use the three letters on the month to determine the following month
If you want to determine the next month, you can just use DateAdd and Month. The cell format is irrelevant.
The following returns the month number:
Month(DateAdd("m", 1, Cells(2,15)))
If you want it as a three letter string, for some reason, then
Format(DateAdd("m", 1, Cells(2,15)), "mmm")
I have a spreadsheet with a load of random text and numbers in column A like so:
Column A
Row 1 = 471806121601 5205569 - 0007 Standard White Toilet Tissue 27
Row 2 = 471814121601 5206177 - 0014 Premium White Toilet Tissue 6
Row 3 = 471814121601 5206178 - 0007 Premium White Toilet Tissue 27
Row 4 = 471806121601 5206180 - 0014 Premium Kitchen Towel 2x75l 6
I have about 2000 lines in total. In each cell, is a Purchase order number (12 digits) and an item number next to it (7 digits).
I am trying to extract the po number and put it into column B and extract the item number and put it into column C
Column B Column C
471806121601 5205569
471814121601 5206177
471814121601 5206178
471806121601 5206180
Here is my code:
Option Explicit
Sub main()
Dim cell As Range
Dim arr As Variant, arrElem As Variant
With Worksheets("Orders") '<--| change "Strings" to your actual worksheet name
For Each cell In .Range("A1", .Cells(.Rows.Count, "A").End(xlUp))
arr = Split(Replace(cell.Value, " ", " "), " ") '<--| change "A"'s to your actual relevant column index
For Each arrElem In arr
If IsNumeric(arrElem) Then
If Len(arrElem) = 12 Then cell.Offset(0, 1).Value = arrElem
End If
Next arrElem
Next cell
End With
Dim cell2 As Range
Dim arr2 As Variant, arrElem2 As Variant
With Worksheets("Orders") '<--| change "Strings" to your actual worksheet name
For Each cell2 In .Range("A1", .Cells(.Rows.Count, "A").End(xlUp))
arr2 = Split(Replace(cell2.Value, " ", " "), " ") '<--| change "A"'s to your actual relevant column index
For Each arrElem2 In arr2
If IsNumeric(arrElem2) Then
If Len(arrElem2) = 7 Then cell2.Offset(0, 3).Value = arrElem2
End If
Next arrElem2
Next cell2
End With
End Sub
This code does work. However it takes absolutely ages and only does one line at a time...Slowly.
Is there a quicker way of doing this? Thanks
If your PO and IN are always the same length in col B put
=MID(A2, 1, 12)
And in col C
=MID(A2, 14, 7)
However if your number change but are always the first two swap the above for,
=MID(A2,1,FIND(" ",A2,1)-1)
And
=MID(A2, FIND(" ", A2, 1)+1, 7)
Respectively.
just use split(string,delimiter)(0) and (1) why replace the space, just use that as the delim. If Row # is in, then use (1) and (2), or you could consider split(split(input,"-")," ") maybe a little faster, not sure though. Also, once you're done no need to complete the loop, so consider, do until with flags rather than for next, although exit for is available
Formula wise, it could be done using something like this
=MID(D1,FIND("é",SUBSTITUTE(D1," ","é",3)),FIND("é",SUBSTITUTE(D1," ","é",4))-FIND("é",SUBSTITUTE(D1," ","é",3)))
and
=MID(D1,FIND("é",SUBSTITUTE(D1," ","é",4)),FIND("é",SUBSTITUTE(D1," ","é",5))-FIND("é",SUBSTITUTE(D1," ","é",4)))