Date from Text format to Date format in VBA - vba

I want to change dates from text format to date format (custom) dd/mm/yyyy hh:mm . I have been reading all types of similar questions inside the website but nothing seems to work for me. Even if I apply changes, the date stays in a text format. Is there a way to use the Date function in VBA. Or generally, any ideas about how I can finally make it work. My dates are vlookups from an excel sheet named "TMS", where they are in a text format. The destination sheet is "Tracker". The dates are imported from a website to the "TMS" sheet so I have to perform the change in format automatically inside the excel. My code is provided below. Much appreciated!!
The code below is the fixed code, for which the date format worked, but it does not run the loop for every row, instead it just copy paste the value of the first row to the other rows. In other words, it works perfectly for the first row, but not for the other!
Sub Tracker()
Sheets("TMS").Select
lastrow = Range("B" & Rows.Count).End(xlUp).Row
With Range("G2:G" & lastrow)
If Not IsEmpty(Range("G2:G" & lastrow)) Then
.value = .Parent.Evaluate("DATE(MID(" & .Address & ",7,4),MID(" & .Address & ",4,2),LEFT(" & .Address & ",2))+RIGHT(" & .Address & ",4)")
End If
End With
Sheets("Tracker").Select
lastrow = Range("B" & Rows.Count).End(xlUp).Row
With Range("AG2:AG" & lastrow)
.Formula = "=VLOOKUP(B2,TMS!B:G,6,FALSE)"
.value = .value
End With
End Sub

simply add to your With Range("G2:G" & lastrow) part:
.Value = .Parent.Evaluate("DATE(MID(" & .Address & ",7,4),MID(" & .Address & ",4,2),LEFT(" & .Address & ",2))+RIGHT(" & .Address & ",4)")
this should change all strings to numerical values in one step :)
EDIT
As Evaluate does not want to return an array this way, we simply force it via INDEX:
.Value = .Parent.Evaluate("INDEX(DATE(MID(" & .Address & ",7,4),MID(" & .Address & ",4,2),LEFT(" & .Address & ",2))+RIGHT(" & .Address & ",4),)")

in the image above, I have illustrated the formulas used to convert from text to their various components then back to a date serial including time. The format for F2 was set as a custom format to display correctly.

I am not sure how your worksheet is organised but considering the dates are imported to Sheets("TMS").Range("G2:G" & lastrow), and you are not able to change their format by using only .NumberFormat = "mm/dd/yyyy hh:mm" then you need to get rid of the complete text and paste them as dates.
You should also avoid selecting sheets. Your code should look something similar to this. Please correct the parts if I guess them incorrectly.
Sub Tracker()
Dim lastrow As Long
Dim arr() As Date
With Sheets("TMS")
lastrow = .Range("B" & .Rows.Count).End(xlUp).Row
ReDim arr(lastrow) As Date
For i = 2 To lastrow
arr(i) = .Range("G" & i).Value
Next i
.Range("G2:G" & lastrow).Delete
For i = 2 To lastrow
.Range("G" & i) = arr(i)
Next i
.Range("G2:G" & lastrow).NumberFormat = "mm/dd/yyyy hh:mm"
End With
With Sheets("Tracker")
lastrow = .Range("B" & .Rows.Count).End(xlUp).Row
With .Range("AG2:AG" & lastrow)
.Formula = "=VLOOKUP(B2,TMS!B:G,6,FALSE)"
.NumberFormat = "mm/dd/yyyy hh:mm"
End With
End With
End Sub

Try this code.
Sub Tracker()
Dim vDB, vT, vD
Dim i As Long
With Sheets("TMS")
lastrow = .Range("B" & Rows.Count).End(xlUp).Row
With .Range("G2:G" & lastrow)
vDB = .Value
If IsDate(vDB(1, 1)) Then
Else
For i = 1 To UBound(vDB, 1)
vT = Split(vDB(i, 1), " ")
vD = Split(vT(0), "/")
vDB(i, 1) = DateSerial(vD(2), vD(1), vD(0)) + Val(Trim(vT(1)))
Next i
End If
.Value = vDB
.NumberFormat = "mm/dd/yyyy hh:mm"
End With
End With
With Sheets("Tracker")
lastrow = .Range("B" & Rows.Count).End(xlUp).Row
With .Range("AG2:AG" & lastrow)
.Formula = "=VLOOKUP(B2,TMS!B:G,6,FALSE)"
.NumberFormat = "mm/dd/yyyy hh:mm"
.Value = .Value
End With
End With
End Sub

Related

Concatenate two ranges without looping

I want to concatenate two ranges into one WIHTOUT using a loop.
Below is the code. The lines with comment's is basically the solution I want to avoid.
With ws_AUoM
lCountEntriesInAUoMFile = .Cells(Rows.Count, "B").End(xlUp).Row
.Range("O2:O" & lCountEntriesInAUoMFile).Value = .Range("B2:B" & lCountEntriesInAUoMFile).Value & .Range("F2:F" & lCountEntriesInAUoMFile).Value
' For lLoopCounterAUoM = 2 To lCountEntriesInAUoMFile
'
' .Cells(lLoopCounterAUoM, "O").Value = .Cells(lLoopCounterAUoM, "B").Value & .Cells(lLoopCounterAUoM, "F").Value
'
' Next lLoopCounterAUoM
End With
This line:
.Range("O2:O" & lCountEntriesInAUoMFile).Value = .Range("B2:B" & lCountEntriesInAUoMFile).Value & .Range("F2:F" & lCountEntriesInAUoMFile).Value
returns the error "Type Mismatch". I have double checked the sizes and location of each range. Yet it does not work. What am I missing here?
You can do this:
Dim r As Long
With ws_AUoM
r = .Cells(.Rows.Count, "B").End(xlUp).Row
.Range("O2:O" & r).Value = .Evaluate("B2:B" & r & " & F2:F" & r)
End With
Evaluate knows you're giving it an array formula, and will return the resulting array, which you can assign directly to the sheet.

vba to sort the data into matrix form

I have some data, for the first column date, it contains two dates.
Then I have the fund code and the categories, the last column is the categories value.
How shall I put them into matrix format, for example, the categories is horizontal and the value correspond to the fund name and categories and the date.
Following code should be helpful.
Option Explicit
Sub Demo()
With Application
.ScreenUpdating = False 'stop screen flickering
.Calculation = xlCalculationManual 'prevent calculation while execution
End With
Dim i As Long, lastrow As Long, tblLastRow As Long, tblLastColumn As Long
Dim dict As Object
Dim rng As Variant
Dim ws As Worksheet
Dim cel As Range, dateRng, fundCodeRng As Range, categoryRng As Range, valueRng As Range
Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Worksheets("Sheet1") 'change Sheet1 to your worksheet
With ws
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row 'get last row with data
'set ranges for date, fund code, category and value to be used later in code
Set dateRng = .Range("A2:A" & lastrow)
Set fundCodeRng = .Range("B2:B" & lastrow)
Set categoryRng = .Range("C2:C" & lastrow)
Set valueRng = .Range("D2:D" & lastrow)
'get unique records for date and fund coding combined together
For i = 2 To lastrow
dict(.Cells(i, 1).Value & "|" & .Cells(i, 2).Value) = dict(.Cells(i, 1).Value & "|" & .Cells(i, 2).Value)
Next
With .Range("F2").Resize(dict.Count) 'date and fund code will be displayed from cell F2
.Value = Application.Transpose(dict.Keys)
.TextToColumns Destination:=.Cells, DataType:=xlDelimited, Other:=True, OtherChar:="|"
.Offset(, 2).Resize(dict.Count).Value = Application.Transpose(dict.Items)
End With
'empty dictionary
dict.RemoveAll
Set dict = Nothing
Set dict = CreateObject("Scripting.Dictionary")
'get unique categories and display as header
rng = .Range("C1:C" & lastrow)
For i = 2 To UBound(rng)
dict(rng(i, 1) & "") = ""
Next
.Range("H1").Resize(1, UBound(dict.Keys()) + 1).Value = dict.Keys 'categories will be displayed from column H
tblLastRow = .Range("F" & Rows.Count).End(xlUp).Row 'get last row in new table
tblLastColumn = Cells(1, Columns.Count).End(xlToLeft).Column 'get last column of category in new table
'display corresponding values for date, fund code and category
For Each cel In .Range(.Cells(2, 8), .Cells(tblLastRow, tblLastColumn)) 'Cells(2, 8) represent Cell("H2")
cel.FormulaArray = "=IFERROR(INDEX(" & valueRng.Address & ",MATCH(1,(" & dateRng.Address & "=" & .Cells(cel.Row, 6) & ")*(" & fundCodeRng.Address & "=""" & .Cells(cel.Row, 7) & """)*(" & categoryRng.Address & "=""" & .Cells(1, cel.Column) & """),0)),"""")"
cel.Value = cel.Value
Next cel
End With
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
See image for reference.
EDIT :
If Fund Code could be numbers also then replace
cel.FormulaArray = "=IFERROR(INDEX(" & valueRng.Address & ",MATCH(1,(" & dateRng.Address & "=" & .Cells(cel.Row, 6) & ")*(" & fundCodeRng.Address & "=""" & .Cells(cel.Row, 7) & """)*(" & categoryRng.Address & "=""" & .Cells(1, cel.Column) & """),0)),"""")"
with
cel.FormulaArray = "=IFERROR(INDEX(" & valueRng.Address & ",MATCH(1,(" & dateRng.Address & "=" & .Cells(cel.Row, 6) & ")*(Text(" & fundCodeRng.Address & ",""0"")=""" & .Cells(cel.Row, 7) & """)*(" & categoryRng.Address & "=""" & .Cells(1, cel.Column) & """),0)),"""")"

Correcting formula in vba excel

I want to create a macro that check all the cells of a column and if the first two characters of a cell is "BB" then i want the macro to extract three characters from the cell and paste it to the next column but a the corresponding row.
But my formula after the if clause is not working.
this is what i have done since:
Sub test()
Dim lmid As String
Dim srange, SelData, ExtBbFor As String
Dim lastrow As Long
Dim i, icount As Integer
lastrow = ActiveSheet.Range("B30000").End(xlUp).Row
srange = "G1:G" & lastrow
SelData = "A1:G" & lastrow
Range(srange).Formula = "=mid(E1,1,3)"
For i = 1 To lastrow
If InStr(1, LCase(Range("E" & i)), "bb") <> 0 Then
Range("G" & i).Formula = "=mid("E & i", 4, 3)"
End If
Next i
End Sub
thanks in advance
Try with below. It will work
Range("G" & i).Value = Mid(Range("E" & i), 4, 3)
If the cell is not limited to 7 then you need as below
Range("G" & i).Value = "=Mid(E" & i & ", 3, " & Len(E & "& i & ") & ")"
It will extract from the 3rd character up to the last character in a cell.
Your syntax is wrong where you're trying to concatenate strings, I think you mean to use:
Range("G" & i).Formula = "=MID(E" & i & ",4,3)"
Based on your code I think this will do the exact same thing without having to loop or declare any variables:
Sub test()
With Range("G1:G" & Cells(Rows.Count, 2).End(xlUp).Row)
.FormulaR1C1 = "=IF(UPPER(LEFT(RC[-2],2))=""BB"",MID(RC[-2],4,3),"""")"
.Value = .Value
End With
End Sub

Convert 'yyyymmdd hhmmss' to 'mm/dd/yy hh:mm'

I have a row of data (Cell A3 and down) that contains a Unix timestamp in yyyymmdd hhmmss format that I'm trying to convert to mm/dd/yy hh:mm format automatically.
The code I have so far works when I have the data starting in cell A1, but I need A1 to remain blank, therefore the data starts at A2. Here is an example screenshot of column A:
Sub auto_open()
'
' auto_open Macro
'
'
ChDir "C:\"
Workbooks.Open Filename:="C:\Users\username\Desktop\file1.csv"
Intersect(Sheets("file1").Range("A:EW"), Sheets("file1").UsedRange).Copy ThisWorkbook.Sheets("Golden").Range("A2")
Windows("file1.csv").Activate
Application.CutCopyMode = False
ActiveWorkbook.Close SaveChanges = False
Dim x As Integer
Dim y As String
Dim z As String
Dim w As String
NumRows = Range("A3").End(xlDown).Row
Windows(ThisWorkbook.Name).Activate
For x = 2 To NumRows
z = Cells(x, 1).Value
y = Mid(z, 5, 2) & "/" & Mid(z, 7, 2) & "/" & Left(z, 4)
w = Mid(z, 10, 2) & ":" & Mid(z, 12, 2) & ":" & Mid(z, 14, 2)
y = y + TimeValue(w)
Cells(x, 1).Value = y
Next x
Range("A3").Select
End Sub
It errors whether I set the range to A2 or A3 and down.
Does anyone have recommendations?
Debug highlights y = Mid(z, 5, 2) & "/" & Mid(z, 7, 2) & "/" & Left(z, 4) but I'm not sure what the problem is.
Format cells (custom > mm/dd/yyyy hh:mm:ss) also does not work in my case, unfortunately.
This will do it with no looping at all:
Sub kyle()
With [a3].Resize([a1048576].End(xlUp).Row - 2)
.Value = Evaluate("transpose(transpose(DATE(MID(" & .Address & ",1,4),MID(" & .Address & ",5,2),MID(" & .Address & ",7,2)) + TIME(MID(" & .Address & ",10,2),MID(" & .Address & ",12,2),MID(" & .Address & ",14,2))))")
End With
End Sub
Note: you can then use whatever number formatting for the dates you please.
Try this:
Sub Kyle()
Dim cell As Range
ThisWorkbook.Activate
For Each cell In Range("A2", Cells(Rows.Count, "A").End(xlUp))
If cell.Value Like "######## ######" Then
cell.Value = CDate(Format(cell.Value, "####-##-#####:##:##"))
End If
Next cell
End Sub
Then format the column however you prefer.
For me, that converts
20150904 213613
20150124 194003
20150404 163056
20151220 100509
20150510 213512
to this:
09/04/2015 21:36
01/24/2015 19:40
04/04/2015 16:30
12/20/2015 10:05
05/10/2015 21:35
#ExcelHero answered my question via email. The following is the working code for anyone who needs future reference.
With [a3].Resize([a65536].End(xlUp).Row - 2)
If Len(.Item(1)) = 15 Then
.Value = Evaluate("transpose(transpose(DATE(MID(" & .Address & ",1,4),MID(" & .Address & ",5,2),MID(" & .Address & ",7,2)) + TIME(MID(" & .Address & ",10,2),MID(" & .Address & ",12,2),MID(" & .Address & ",14,2))))")
End If
.NumberFormat = "mm/dd/yyyy hh:mm"
End With

How to increase only last digit of a serial number string in Excel VBA?

I'm new to vba and trying to write a barcode scanner algorithm. It works fine right now but I want to keep serial numbers in my exel table and their structure has to be like "A151000". I want with each barcode entered a cell with an inputbox also be assigned to a serial number. for example when a new entry(Barcode) written in column C I want in column B serial numbers last digit increased by 1 and stored in that cell automatically.
Right now I can drag the cell from corner and exel increases the last digit. How can I trigger this with new entries automatically? Thanks in advance.
A151000
A151001
A151002
...
Sub DataInput()
Dim SearchTarget As String
Dim myRow As Long
Dim Rng As Range
Static PrevCell As Range
Dim FoundCell As Range
Dim CurCell As Range
Dim a As String
Dim Target As Range
Dim buttonclick As Boolean
V = True
If PrevCell Is Nothing Then
myRow = Selection.Row
Set PrevCell = Range("C" & myRow)
End If
Set Rng = Range("C:C,C:C") 'Columns for search defined here
With Rng
Set FoundCell = .Cells.Find(What:=SearchTarget, _
After:=PrevCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=True)
End With
Dim Eingabezahl As String
Do While Eingabezahl! = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Range("C" & Range("C" & Rows.Count).End(xlUp).Row + 1) = Eingabezahl
Range("D" & Range("D" & Rows.Count).End(xlUp).Row + 1) = Now()
Range("E" & Range("E" & Rows.Count).End(xlUp).Row + 1) = "VALID"
Loop
End Sub
TO use the Autofill function and not change your original code you could just add in the autofill in your sub:
Dim Eingabezahl As String
Dim rngLastBCell As Range
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngLastBCell = Range("B" & Rows.Count).End(xlUp)
rngLastBCell.AutoFill Destination:=Range(rngLastBCell, rngLastBCell.Offset(1)), Type:=xlFillDefault
Range("C" & Range("C" & Rows.Count).End(xlUp).Row + 1) = Eingabezahl
Range("D" & Range("D" & Rows.Count).End(xlUp).Row + 1) = Now()
Range("E" & Range("E" & Rows.Count).End(xlUp).Row + 1) = "VALID"
Loop
Or you could use the following that using the same concept (an autofill) but condenses al of your calls to the worksheet into a single line:
Dim Eingabezahl As String
Dim rngLastBCell As Range
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngLastBCell = Range("B" & Rows.Count).End(xlUp)
rngLastBCell.AutoFill Destination:=Range(rngLastBCell, rngLastBCell.Offset(1)), Type:=xlFillDefault
rngLastBCell.Offset(1, 1).Resize(, 3) = Array(Eingabezahl, Now(), "VALID")
Loop
Although I would recommend just using appenending the current row to the end of your serial and not making as many calls to the worksheet by using an array:
Dim rngB As Range
Dim Eingabezahl As String
Dim SerialBase As String
SerialBase = "A15100"
Do While Eingabezahl = ""
Eingabezahl = InputBox("Last barcode scanned" & " " & Eingabezahl)
Set rngB = Range("B" & Rows.Count).End(xlUp).Offset(1)
rngB.Resize(, 4).Value = Array(SerialBase & rngB.Row, Eingabezahl, Now(), "VALID")
Loop