Insert missing data then add data to two previous columns A & B - excel

below is a VBA that when launched I get an error code of 'Run-Time error '13: Type Mismatch'.
It had worked perfectly before for General Format "dd mmm yyyy hhmm". After a couple of other VBAs it now in a Custom Format "dd mmm yyyy hhmm". The end goal is to have a blank row inserted where a date is skipped over, and have "NO DEPARTURS" placed in the blank row Column A, and for Column B and C have "N/A", and for Column D input the Missing Date in "dd mmm yyyy 0000". When debugged the line beginning with d1= cdate... is highlighted.
Sub Missing_date()
Dim d1 As Date, d2 As Date
r = 1
start:
If Cells(r + 1, "D") = "" Then Exit Sub
d1 = CDate(Split(Cells(r, "D"), " ")(1) & ", " & Split(Cells(r, "D"), " ")(0) & " " & Split(Cells(r, "D"), " ")(2))
d2 = CDate(Split(Cells(r + 1, "D"), " ")(1) & ", " & Split(Cells(r + 1, "D"), " ")(0) & " " & Split(Cells(r + 1, "D"), " ")(2))
If d2 - d1 >= 2 Then
Rows(r + 1).Insert shift:=xlDown
Cells(r + 1, "D") = Format(d1 + 1, "dd mmm yyyy 0000")
Cells(r + 1, "A") = "NO DEPARTURES"
Cells(r + 1, "B") = "N/A"
Cells(r + 1, "C") = "N/A"
End If
r = r + 1
GoTo start
End Sub

You are going to an awful lot of trouble trying to handle dates your own way rather than what Excel would like. I have taken the liberty of presuming that you had no intention of declaring war on Excel. Please try this code.
Option Explicit
Sub InsertMissingDates()
' 111
Dim NextDate As Variant
Dim CellVal As Variant
Dim R As Long ' loop counter: Rows
R = Cells(Rows.Count, "D").End(xlUp).Row
NextDate = CellDate(Cells(R, "D"))
If NextDate = vbError Then Exit Sub
' bottom rows must be inserted before top rows
For R = R - 1 To 2 Step -1
CellVal = CellDate(Cells(R, "D"))
If CellVal = vbError Then Exit For ' exit if date can't be recognised
Do While Int(CDbl(CellVal)) < Int(CDbl(NextDate - 1))
Rows(R + 1).Insert Shift:=xlDown
With Cells(R + 1, "D")
.Value = Int(CDbl(NextDate - 1))
.NumberFormat = "dd mmm yyyy hhmm"
.HorizontalAlignment = xlLeft
End With
Cells(R + 1, "A").Value = "NO DEPARTURES"
Cells(R + 1, "B").Value = "N/A"
Cells(R + 1, "C").Value = "N/A"
NextDate = NextDate - 1
Loop
NextDate = CellVal
Next R
End Sub
Private Function CellDate(Cell As Range) As Variant
' 111
' return vbError if cell's value couldn't be converted to a date
Dim Fun As Variant ' function return value
Dim CellVal As Variant
Dim Sp() As String
CellVal = Cell.Value
If IsDate(CellVal) Then
Fun = CDate(CellVal)
Else
Sp = Split(CellVal, " ")
If UBound(Sp) = 3 Then
Sp(3) = Right("0000" & Sp(3), 4)
Sp(3) = Left(Sp(3), 2) & ":" & Right(Sp(3), 2)
On Error Resume Next
Fun = CDate(Join(Sp))
End If
End If
If VarType(Fun) <> vbDate Then
MsgBox """" & CellVal & """ in row " & Cell.Row & vbCr & _
"couldn't be converted to a date.", _
vbInformation, "Data format error"
Fun = vbError
End If
CellDate = Fun
End Function
The point is that Excel takes a date to be an integer number, like 44135. Tomorrow will be 44136. Therefore each day = 1 and, therefore, each hour = 1/24. 44135.0 is 12AM and 43135.5 denotes 12PM. To display these numbers like 31 Oct 2020 1200 you don't format the number but you format the cell. This is what my code does.
Now you will have cells in your worksheet which have text that looks like a date (your entries) and dates that look like text (entries made by my code). Consider concocting a procedure which looks at the NumberFormat of each cell and changes its value to a proper date if it's Text, applying the reqired format at the same time. You can use lines of code from my above procedures to put it together. Then the function CellDate would become obsolete because its sole job is to mediate between your text dates and Excel's intentions.

Related

Format Date VBA

i want to implement this recorded macro into a macro for my code, i succesfully transformed "E" row into general, and i want to change that date into Short Date format DD/MM/YYYY the macro i recorded is this one below:
Sub Macro2()
'
' Macro2 Macro
Range("L4").Select
ActiveCell.FormulaR1C1 = "=DATEVALUE(MID(RC[-7],1,10))"
Range("L4").Select
Selection.AutoFill Destination:=Range("L4:L4500"), Type:=xlFillDefault
Range("L4:L4500").Select
Selection.NumberFormat = "m/d/yyyy"
End Sub
I tried it by making the function into the L Column, if it is possible i would like to implement it in one column so all values change and then paste them into the E column
The whole E column is like this:
01-10-2019 52:59:76
02-10-2019 52:59:76
02-10-2019 52:59:76
05-10-2019 52:59:76
And i want them to change into
01/10/2019
02/10/2019
02/10/2019
05/10/2019
This the code i used to transform the whole E column data to the format of dd-mm-yyyy hh:mm:ss to correct the error of some data not changing into the correct format
With ActiveSheet.UsedRange.Columns("E").Cells
Columns("E").NumberFormat = "0"
Columns("E").NumberFormat = "General"
End With
If in '01-10-2019 52:59:76' first two digits means day, try please the next code:
Sub testDateFormat()
Dim lastRow As Long, sh As Worksheet, x As String, i As Long
Set sh = ActiveSheet 'use here your sheet, if not active one
lastRow = sh.Range("E" & sh.Rows.count).End(xlUp).Row
sh.Range("E1:E" & lastRow).NumberFormat = "dd/mm/yyyy"
For i = 2 To lastRow
If sh.Range("E" & i).Value <> Empty Then
If chkFind(CStr(sh.Range("E" & i).Value)) = True Then
x = CStr(sh.Range("E" & i).Value)
sh.Range("E" & i).Value = Format(DateSerial(Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(2), _
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(1), _
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(0)), "dd/mm/yyyy")
Else
Debug.Print "Unusual string on the row " & i
End If
End If
Next i
End Sub
Private Function chkFind(strVal As String) As Boolean
On Error Resume Next
If WorksheetFunction.Find(" ", strVal) = 11 Then
chkFind = True
If Err.Number <> 0 Then
Err.Clear
On Error GoTo 0
chkFind = False
End If
Else
chkFind = False
End If
On Error GoTo 0
End Function
If first digits represents month, then the last two array (split) elements must be vice versa:
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(0), _
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(0))
instead of
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(1), _
Split(left(x, WorksheetFunction.Find(" ", x) - 1), "-")(1))

VBA Looping to compare multiple values

I have created a nested for loop to compare 3 different cell values within 2 sheets. The loop works fine when the data is small, but when I run on 5,000 rows its too slow and crashes excel. Any idea of how to run this more efficiently.
Sub RowMatch()
Dim x As Integer
' Make sure we are in the right sheet
Worksheets("Q416").Activate
' Set numrows = number of rows of data.
NumRows = Range("C2", Range("C2").End(xlDown)).Rows.count
' find the reference range
Worksheets("Q415").Activate
NumRows2 = Range("C5", Range("C5").End(xlDown)).Rows.count
Worksheets("Q416").Activate
MsgBox ("Total # of Rows on this sheet = " & NumRows & " and " & NumRows2 & " in Ref Range")
Range("A1").Select
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
'MsgBox NumRows2
For y = 1 To NumRows2
'MsgBox (ActiveCell.Offset(x, 0).Value & " & " & Worksheets("Q415").Cells(y + 1, 1))
If ActiveCell.Offset(x, 0).Value = Worksheets("Q415").Cells(y + 1, 1).Value _
And ActiveCell.Offset(x, 2).Value = Worksheets("Q415").Cells(y + 1, 3).Value Then
If ActiveCell.Offset(x, 5).Value = Worksheets("Q415").Cells(y + 1, 6).Value Then
'If NumRows(i).Value = ActiveCell.Offset(1, 0).Value Then
ActiveCell.Offset(x, 10).Value = "Same"
Else
ActiveCell.Offset(x, 10).Value = ActiveCell.Offset(x, 5).Value - Worksheets("Q415").Cells(y + 1, 6).Value
End If
End If
Next y
Next x
End Sub
Reading and writing to cells is one of the slowest operations you can do in Excel VBA. Instead, you should place the values contained in the worksheets into arrays and work with them there, Here is an excellent reference: http://www.cpearson.com/excel/ArraysAndRanges.aspx. Use your NumRows variables and either a column letter or number to define the ranges that will consitute the arrays e.g:
myRange = Range("A1:C" & NumRows)
myArray = myRange.value
From the link to Chip Pearsons site:
Dim Arr() As Variant
Arr = Range("A1:B10")
Dim R As Long
Dim C As Long
For R = 1 To UBound(Arr, 1) ' First array dimension is rows.
For C = 1 To UBound(Arr, 2) ' Second array dimension is columns.
Debug.Print Arr(R, C)
Next C
Next R

How 16.06.2016 is bigger than 29.10.2016

I have a macro to fill dates background if they are not forward than today. It works nicely but, however, just in one page, DateValues are not compared correctly.
I tried to show the result with MessageBoxes, it says 16.06.2016 is bigger than 29.10.2016
My macro:
Sub DolguRenkleri(ByVal StartIndex As Integer, ByVal EndIndex As Integer)
Dim Tarih As String
Dim Formul As String
Dim Formul2 As String
Tarih = Left(Now, 10)
For i = StartIndex To EndIndex - 1
MsgBox (Cells(i, 2).Value > DateValue(Tarih))
If Cells(i, 2) <= DateValue(Tarih) Then
With Range("A" + CStr(i), "H" + CStr(i))
.Interior.ColorIndex = 6
End With
Formul = "=TOPLA(D" + CStr(i + 1) + ":D" + CStr(EndIndex - 1) + ")"
Formul2 = "=F6-A" + CStr(i)
Else: With Range("A" + CStr(i), "H" + CStr(i))
.Interior.ColorIndex = 2
End With
End If
Next i
Range("F1").FormulaLocal = Formul
Range("F7").FormulaLocal = Formul2
End Sub
it must be that "16.06.2016" string in cell B10 is not recognized as a real Date value, notwithstanding you may have selected that cell and assigned it a "Date" format
in this case, use
If DateValue(Replace(Cells(i, 2).Value, ".", "/")) <= DateValue(Tarih) Then

Excel forumla for converting text to date, day & time

I have column filled with below text data
Sun Aug 30 23:49:00 IST 2015
I need to split in three columns:
Time "23:49:00"
Date "Aug 30 2015" and
Day "Sun".
You can do this without macro, but if macros are needed as part of a larger effort, then:
Sub dural()
Dim v As String, r As Range
For Each r In Intersect(Range("A:A"), ActiveSheet.UsedRange)
v = r.Value
If v <> "" Then
ary = Split(v, " ")
r.Offset(0, 1) = ary(3)
r.Offset(0, 2) = ary(1) & " " & ary(2) & " " & ary(5)
r.Offset(0, 3) = ary(0)
End If
Next r
End Sub
The code can be adapted to handle your choice of columns.
If the date you're attempting to read is in cell A1, then the following three formulas will work:
Day
=LEFT(A1, 3)
Date
=TRIM(MID(A1, 5, 6)) & RIGHT(A1, 5)
Time
=TRIM(MID(A1, 11, 9))

Counting distinct values in excel - frequency function

Counting distinct values in excel - frequency function
yes I have read
Counting distinct values in excel - frequency function
I am try to count a column with different numbers
column contains (search)
1 3 7 9 5 1 3 9 4
result looking for;
C1 C2
1 = 2
2 = 0
3 = 2
4 = 1
etc
You can use COUNTIF to count the number of elements that match a condition.
Suppose you have your numbers in column A, say from A1 to A10:
A1: 1
A2: 3
A3: 7
etc...
Type in somewhere on your sheet, say in column B, the values you are interested in:
B1: 0
B2: 1
etc...
and in C1, type in
=COUNTIF($A$1:$A$10, B1)
This should count the number of values equal to B1 (i.e. 0), in A1:A10.
Enter your numbers in column A and a sequence in column B
A B
1 1
2 1
3 1
4 1
2 1
3 1
4 1
Select both columns and create a pivot table putting col A in rows. Select {COUNT} as function and you are done.
Not exactly what you are asking but i use a macro to generate frequency tables. I like it. Original code was posted by MWE at http://www.vbaexpress.com/kb/getarticle.php?kb_id=406 and i have (hopefully) improved it a bit. Have left in a little bit of redundant code so i get more replies :p
Sub zzzFrequencyDONT_SELECT_WHOLE_COLUMN()
' if user selects massive range - usually whole column - stops them
If Selection.Rows.Count > 60000 Then
MsgBox "Range selected is way too large - over 60,000. You have probably selected an entire column. Select a range of under 60,000 cells and try again"
End If
If Selection.Rows.Count > 60000 Then
Exit Sub
End If
'
' Function computes frequency count of unique values in a selection
'
Dim Count() As Integer
Dim I As Integer, J As Integer
Dim Num As Integer, NumOK As Integer, MaxNumOK As Integer, NumBad As Integer
Dim Row As Integer, Col As Integer, Temp1 As Integer, Temp2 As Integer
Dim strBuffer As String, strBadVals As String
Dim CellVal As Variant
Dim Ans As VbMsgBoxResult
Num = 0
NumBad = 0
NumOK = 0
MaxNumOK = 50
ReDim Count(MaxNumOK, 2)
strBuffer = ""
'
' sequence through each cell in selection
'
For Each Cell In Selection
Num = Num + 1
On Error Resume Next
CellVal = Cell.Value
Select Case Err
Case Is = 0
'
' no error, examine type
'
Select Case LCase(TypeName(CellVal))
Case "integer", "long", "single", "double"
'
' numeric type; if single or double, use
' Fix function to reduce to integer portion
'
If TypeName(CellVal) = "single" Or _
TypeName(CellVal) = "double" Then
CellVal = Fix(CellVal)
End If
'
' check if previously seen
' if so, simply bump counter
' if not, increment NumOK and store value
'
For I = 1 To NumOK
If CellVal = Count(I, 1) Then
Count(I, 2) = Count(I, 2) + 1
GoTo NextCell
End If
Next I
NumOK = NumOK + 1
If NumOK > MaxNumOK Then
MsgBox "capacity of freq count proc exceeded" & vbCrLf & _
"Displaying results so far", vbCritical
GoTo SortCount
End If
Count(NumOK, 1) = CellVal
Count(NumOK, 2) = 1
Case Else
NumBad = NumBad + 1
If Cell.Text <> "" Then
strBadVals = strBadVals & Cell.Text & vbCrLf
Else
strBadVals = strBadVals & "<blank>" & vbCrLf
End If
End Select
Case Is <> 0
NumBad = NumBad + 1
If Cell.Text <> "" Then
strBadVals = strBadVals & Cell.Text & vbCrLf
Else
strBadVals = strBadVals & "<blank>" & vbCrLf
End If
End Select
NextCell:
Next Cell
'
' counting done, sort data
'
SortCount:
For I = 1 To NumOK
For J = I To NumOK
If I <> J Then
If Count(I, 1) > Count(J, 1) Then
Call SwapVals(Count(I, 1), Count(J, 1))
Call SwapVals(Count(I, 2), Count(J, 2))
End If
End If
Next J
Next I
'
' store count data for display
'
Dim percentstore As Single
percentstore = Str(Count(I, 2)) / Str(Num)
For I = 1 To NumOK
strBuffer = strBuffer & Str(Count(I, 1)) & vbTab + Str(Count(I, 2)) & vbTab & FormatPercent(Str(Count(I, 2)) / Str(Num)) & vbCr
Next I
'
' display results
'
MsgBox "CTRL C to copy" & vbCrLf & _
"# cells examined = " & Str(Num) & vbCrLf & _
"# cells w/o acceptable numerical value = " & NumBad & vbCrLf & _
"# unique values found = " & NumOK & vbCrLf & _
"Frequency Count:" & vbCrLf & "value" & vbTab & "frequency" & vbTab & "Percent" & vbCr + strBuffer, vbInformation, "Frequency count - CTRL C to copy"
If NumBad > 0 Then
Ans = MsgBox("display non-numerics encountered?", vbQuestion & vbYesNo)
If Ans = vbYes Then MsgBox "Non Numerics encountered" & vbCrLf & strBadVals
End If
'
' write to worksheet?
'
' Ans = MsgBox("Ok to write out results below selection?" & vbCrLf + _
' "results will be two cols by " & (NumOK + 1) & " rows", vbQuestion + vbYesNo)
' If Ans <> vbYes Then Exit Sub
' Row = Selection.Row + Selection.Rows.Count
' Col = Selection.Column
' Cells(Row, Col) = "Value"
' Cells(Row, Col + 1) = "Count"
' For I = 1 To NumOK
' Cells(Row + I, Col) = Count(I, 1)
' Cells(Row + I, Col + 1) = Count(I, 2)
' Next I
End Sub
Sub SwapVals(X, Y)
'
' Function swaps two values
'
Dim Temp
Temp = X
X = Y
Y = Temp
End Sub

Resources