VBA stops printing values in excel - excel

I have written a macro to take values from an external simulation tool and prints the results in excel.The simulaion tool will give values only every 30 seconds and will run for days. Hence i have given a delay in VB for 30 seconds in loop. I leave it overnight for running. In the next morning i could see none of the results were updated after certain rows.But the VBA editor header shows the macro is running and the external simulation tool is also running. The last updated row in excel is not constant everytime. Why does VBA stops printing the results in excel? Any help will be much appreciated.
Sample code:
For l = 3 To lastrow1_mul + 2
Module4.Wait 30
nv = send_data.Call
Sheets(SecondSheetName).Range(SecondSheetCol_9 & l) = Hex(nv)
dv = DT.Call
If dv = 44 Then
Sheets(SecondSheetName).Range(SecondSheetCol_10 & l) = "A"
ElseIf dv = 54 Then
Sheets(SecondSheetName).Range(SecondSheetCol_10 & l) = "B"
Else
Sheets(SecondSheetName).Range(SecondSheetCol_10 & l) = "C"
End If
Next l
Module 4:
Function Wait(PauseTime As Single)
Dim StartTime As Single
StartTime = Timer
While Timer < StartTime + PauseTime
DoEvents
Wend
End Function
Send_data and DT are external simulation tool's functions.Variable lastrow1_mul's value is getting updated around 7000 but rows in excel stops printing around 500 itself(not constant always) .

looks OK but look at using Application.OnTime shown below. Also what happens if the simulation hasnt returned data, shoudnt you build in a bigger, maybe 45 second intervals?
Application.OnTime Now + TimeValue("00:00:30"), "RunProcess"

The 'Timer' i used in the code was the culprit. Timer counts the seconds elapsed(in fractions) since midnight. So it will not update when the time becomes 00.00.00. So the wait function i wrote will keep on waiting!
Here is the solution
Function Wait()
Dim StartSecond As Single
Dim EndSecond
StartSecond = Now
EndSecond = DateAdd("s", 30, Now)
While Now < EndSecond
DoEvents
Wend
End Function

Related

Excel vba : Convert Unix Timestamp to Date Time

I know this has been asked quite a bit, but for some reason none of the solutions seem to work for me.
I have a unix time stamp (for example purposes use 1637402076084)
On my excel sheet I can convert that fine using
= (C2/ 86400000) + DATE(1970,1,1)
However I want to do this in my VBA code as there's a lot of data and I prefer doing it all in an array then applying my array to the sheet (for performance purposes)
However in my code I'm trying to use dateAdd
DateAdd("s", 1637402076084#, "1/1/1970 00:00:00")
but I get an overflow error
I'm assuming this is because the unix timestamp is too big? But it's one that gets returned from an api call and is a geniune one (as demonstrated by the formula) but I'm not sure why my code isn't working.
There are two types of UNIX timestamps. 10 digits and 13 digits. The function you try using is for 10 digits type. To convert the 13 digits type, you should create another function, exactly as you use in the cell:
Function fromUNIX13Digits(uT) As Date
fromUNIX13Digits = CDbl(uT) / 86400000 + DateSerial(1970, 1, 1)
End Function
And test it as:
Sub testFromUNIX13()
Debug.Print fromUNIX13Digits("1637402076084")
End Sub
For 10 digits type, you can use:
Public Function fromUnix10(ts) As Date
fromUnix10 = DateAdd("s", CDbl(ts), "1/1/1970")
End Function
And test it using:
Sub testFromUnix10()
Debug.Print fromUnix10("1651680385")
Debug.Print Format(fromUnix10("1651680385"), "yyyy/mm/dd hh:nn:ss")
End Sub
Or build a function able to deal with both types:
Function FromUNIX(uT) As Date
If Len(uT) = 10 Then
FromUNIX = DateAdd("s", CDbl(uT), "1/1/1970")
ElseIf Len(uT) = 13 Then
FromUNIX = CDbl(uT) / 86400000 + DateSerial(1970, 1, 1)
Else
MsgBox "No UNIX timestamp passed to be converted..."
End If
End Function
And test it using:
Sub testFromUnix_()
Dim x As String, y As String
x = "1637402076084"
y = "1651680385"
Debug.Print FromUNIX(x)
Debug.Print FromUNIX(y)
End Sub

Run a Macro at a specific time for a certain time amount and stop that macro or line of code to run another macro or line for a new time?

I have a worksheet that on Mac it has a add button that will increase the value of the Cabs Loaded each time you press it. I have multiple time locations 0530, 0600, 0630, etc. That the one adds button needs to increase based on the current time listed.
The code below is what I have tried, it runs the function code first once it reaches the time cap. The sub code runs along with the code for the function once it reached said time. I need it to stop the first addition at H10 so it will only add on the next at H12 for a certain timed amount before going to the next ones.
Sub Button_One()
If Time <= TimeSerial(18, 26, 0) Then GoTo Next1
If Time >= TimeSerial(18, 28, 0) Then Exit Sub
Sheets("A-1 Am").Range("h12").Value = Sheets("A-1 Am").Range("h12").Value + 1
Next1: Button_One1
End Sub
Function Button_One1()
Sheets("A-1 Am").Range("h10").Value = Sheets("A-1 Am").Range("h10").Value + 1
End Function
If Time < TimeSerial(13, 15, 0) Then
RunWhen = Now + TimeSerial(0, 0, cRunIntervalSeconds)
Application.OnTime EarliestTime:=RunWhen, Procedure:=cRunWhat, _
Schedule:=True
End If
Any information to get this to work will be appreciated!!! I've been trying for weeks to figure it out!

Parsing HTML with Excel VBA

Hi StackOverflow community!
Before I go to the nearest petrol station to buy a gallon of petrol and then proceed to a shopping centre (wiping tears of desperation along the way) to set my self on fire...
I am trying to parse few websites, each an instance of finance.google.co.uk, for share prices. This sub only opens 3 sites(for now, I'm planning few hundred), get the share price from each and puts it in cells A1, A2, A3 respectively. The code I wrote works fine only after starting/ restarting my laptop and running excel the first time. 2nd and subsequent runs produce random results, meaning 2nd run will give me say A1 and A3 values, next A1, next A1 and A2 etc. Have spent last few days trying to figure out what is going on. Also I cant find a way to get rid of the "On Error Resume Next" line. If I do that I get "Method 'Navigate' of Object 'IWebBrowser2' failed" error, any idea why?. BTW, I'm green, code for personal use, or trying to. So maybe I overlooked something painfully simple, or what I think is the case, simply don't know that simple thing.
The gear:
- windows7 32bit
- IE 11
My sub:
Sub Google_Finance()
Dim o(3) As String
o(1) = "http://finance.google.co.uk/finance?q=LON%3ABARC"
o(2) = "http://finance.google.co.uk/finance?q=LON%3ACCH"
o(3) = "http://finance.google.co.uk/finance?q=LON%3ASUK2"
Dim IE As Object
Set IE = New InternetExplorer
IE.Visible = False
For i = 1 To 3
IE.navigate o(i)
On Error Resume Next
Do While IE.Busy
DoEvents
Loop
Next i
Dim n as Integer
n = 1
Dim v(3) As Variant
v(1) = IE.document.getElementById("ref_11248216_l").innerText"
v(2) = IE.document.getElementById("ref_243113080920948_l").innerText
v(3) = IE.document.getElementById("ref_14572000_l").innerText
For i = 1 To 3
Sheet1.Range("a" & n) = v(i)
n = n + 1
Next i
IE.Quit
Set IE = Nothing
End Sub
Cheers,
Sam
I tried running the code on my side. I don't get the error you are getting when removing 'on error'. Code works OK for me few times in a row, no issues occurred.
To me it looks like this: the error you are getting is happening when IE is trying to reach the page. Because you use 'on error resume next', the compiler does not try to rerun this task on failure, thus any error leads to no data for the value it is trying to read from the web.
You should either: a) remove 'on error resume next' or b) change error handling to loop the task until completion.
For solution a) you will need to overcome your error, which I believe is explained here
For solution b) you will need to change your sub to include a loop - example solution can be found here
Hope this helps!

VBA subroutine slows down a lot after first execution

I have a subroutine that generates a report of performance of different portfolios within 5 families. The thing is that the portfolios in question are never the same and the amount in each family neither. So, I copy paste a template (that is formated and...) and add the formated row (containing the formula and...) in the right family for each portfolio in the report. Everything works just fine, the code is not optimal and perfect of course, but it works fine for what we need. The problem is not the code itself, it is that when I execute the code the first time, it goes really fast (like 1 second)... but from the second time, the code slows down dramatically (almost 30 second for a basic task identical to the first one). I tried all the manual calculation, not refreshing the screen and ... but it is really not where the problem comes from. It looks like a memory leak to me, but I cannot find where is the problem! Why would the code runs very fast but sooooo much slower right after... Whatever the length of the report and the content of the file, I would need to close excel and reopen it for each report.
**Not sure if I am clear, but it is not because the code makes the excel file larger or something, because after the first (fast) execution, if I save the workbook, close and reopen it, the (new) first execution will again be very fast, but if I would have done the same excat thing without closing and reopening it would have been very slow...^!^!
Dim Family As String
Dim FamilyN As String
Dim FamilyP As String
Dim NumberOfFamily As Integer
Dim i As Integer
Dim zone As Integer
Sheets("RapportTemplate").Cells.Copy Destination:=Sheets("Rapport").Cells
Sheets("Rapport").Activate
i = 3
NumberOfFamily = 0
FamilyP = Sheets("RawDataMV").Cells(i, 4)
While (Sheets("RawDataMV").Cells(i, 3) <> "") And (i < 100)
Family = Sheets("RawDataMV").Cells(i, 4)
FamilyN = Sheets("RawDataMV").Cells(i + 1, 4)
If (Sheets("RawDataMV").Cells(i, 3) <> "TOTAL") And _
(Sheets("RawDataMV").Cells(i, 2) <> "Total") Then
If (Family <> FamilyP) Then
NumberOfFamily = NumberOfFamily + 1
End If
With Sheets("Rapport")
.Rows(i + 8 + (NumberOfFamily * 3)).EntireRow.Insert
.Rows(1).Copy Destination:=Sheets("Rapport").Rows(i + 8 + (NumberOfFamily * 3))
.Cells(i + 8 + (NumberOfFamily * 3), 6).Value = Sheets("RawDataMV").Cells(i, 2).Value
.Cells(i + 8 + (NumberOfFamily * 3), 7).Value = Sheets("RawDataMV").Cells(i, 3).Value
End With
End If
i = i + 1
FamilyP = Family
Wend
For i = 2 To 10
If Sheets("Controle").Cells(16, i).Value = "" Then
Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = True
Else
Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = False
End If
Next i
Sheets("Rapport").Cells(1, 1).EntireRow.Hidden = True
'Define printing area
zone = Sheets("Rapport").Cells(4, 3).End(xlDown).Row
Sheets("Rapport").PageSetup.PrintArea = "$D$4:$Y$" & zone
Sheets("Rapport").Calculate
Sheets("RANK").Calculate
Sheets("SommaireGroupeMV").Calculate
Sheets("SommaireGroupeAlpha").Calculate
Application.CutCopyMode = False
End Sub
I do not have laptop with me at the moment but you may try several things:
use option explicit to make sure you declare all variables before using them;
from what I remember native vba type for numbers is not integer but long, and integers are converted to long, to save the computation time use long instead of integers;
your Family variables are defined as strings but you store in them whole cells and not their values i.e. =cells() instead of =cells().value;
a rule of a thumb is to use cells(rows.count, 4).end(xlup).row
instead of cells(3, 4).end(xldown).row.;
conditional formatting may slow down things a lot;
use for each loop on a range if possible instead of while, or even copy range to variant array and iterate over that (that is the fastest solution);
use early binding rahter of late binding, i.e., define objects in a proper type as soon a possible;
do not show printing area (page breaks etc.);
try to do some pofiling and look for the bottlenecks - see finding excel vba bottlenecks;
paste only values if you do not need formats;
clear clipboard after each copy/paste;
set objects to Nothing after finishing using them;
use Value2 instead of Value - that will ignore formatting and take only numeric value instead of formatted value;
use sheet objects and refer to them, for example
Dim sh_raw As Sheet, sh_rap As Sheet
set sh_raw = Sheets("RawDataMV")
set sh_rap = Sheets("Rapport")
and then use sh_raw instead of Sheets("RawDataMV") everywhere;
I had the same problem, but I finally figured it out. This is going to sound ridiculous, but it has everything to do with print page setup. Apparently Excel recalculates it every time you update a cell and this is what's causing the slowdown.
Try using
Sheets("Rapport").DisplayPageBreaks = False
at the beginning of your routine, before any calculations and
Sheets("Rapport").DisplayPageBreaks = True
at the end of it.
I had the same problem. I am far from expert programer. The above answers helped my program but did not solve the problem. I'm running excel 2013 on a 5 year old lap top. Open the program without running it, go to File>OptionsAdvanced, Scroll down to Data and uncheck "Disable undo for large Pivot table refresh...." and "Disable undo for large data Model operation". You could also try leaving them checked but decreasing their value. One or both of these seem to be creating a ever increase file that slows the macro and eventual grinds it to a stop. I assume closing excel clears the files they create so that's why it runs fast when excel is closed and reopened at least for a while. Someone with more knowledge will have to explain what these changes will do and what the consequences are of unchecking them. It appears these changes will be applied to any new spread sheets you create. Maybe these changes would not be necessary if I had a newer more powerful computer.

Using an if statement within a for loop- Excel VBA

I'm having trouble using an if statement inside a for loop in excel vba. The output of the debugger is not what I expect. I can post the full code of what I am trying to accomplish, but I think I have narrowed it down to what I don't understand. Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
For i = 9 To 60 Step 3
If Cells(i, "DR").Value < Cells(i, "EB").Value Then
Debug.Print i & "-ifloopstart"
Cells(i, "DR").Value = 999999
Debug.Print i & "-ifloopend"
End If
Next i
End Sub
The output of the debugger is:
9-ifloopstart
33-ifloopstart
51-ifloopstart
51-ifloopend
33-ifloopend
9-ifloopend
However, I expected:
9-ifloopstart
9-ifloopend
33-ifloopstart
33-ifloopend
51-ifloopstart
51-ifloopend
Can someone explain how this works? It seems to be looping back to the beginning of the if statement instead of finishing the if statement. How can I modify the code to get the output I expect? I've been struggling with this for hours and it seems so simple :( .
Each time the worksheet is updated with Cells(i, "DR").Value = 999999, Worksheet_Change gets called again.
Think of it this way. Each time that above code gets called, you modify a cell, which triggers the worksheet change method again.
So you are effectively nesting three calls of this function:
called once, with i = 9
called again, with i = 33
called again, with i = 51
finishes i = 51 call
finishes i = 33 call
finishes i = 9 call
VBA then goes backwards from each of these to get back to the first time your method was run.
Edit: as Tim says you can disable this with Application.EnableEvents=False

Resources