How to convert VBA Now() into seconds to determine total program runtime - vba

I'm working on a problem where I need to determine the total time my program takes to execute. First line of code needs to write the current "Start time" and last lines of code need to write the current "End time". Then I'm subtracting "Start time" - "End Time" = Total Time.
I'm confused how I would use the FORMAT() function within VBA on the value of C2 to convert into seconds? Is there an other function that would work better than FORMAT? Basically I'm confused about Excel's Date Serial values and what they represent.
Code is below
EDIT: Thanks for the responses everyone. Both answers below work for what I'm trying to do.
sub ExecutionTime()
Worksheets("Table").Range("A2").Value = Now()
'All my executable code goes here. It's a relatively small program compiling a table so it
runs very quick.
Worksheets("Table").Range("B2").Value = Now()
Worksheets("Table").Range("C2").Value = Worksheets("Table").Range("A2").Value - Worksheets("Table").Range("B2").Value
end Sub

Do not use a Date data member or the Now method to analyze run time of your program. Instead, the Timer function is the most appropriate solution as it returns a Single representing seconds. It will require no type conversion and yields a more accurate result than an integer amount of seconds.
Using LimaNightHawk's answer as a template as you should be storing these in local variables instead of writing directly to the worksheet.
Dim startTime as Single
startTime = Timer()
' Do stuff
Dim endTime as Single
endTime = Timer()
Dim runTime as Single
runTime = endTime - startTime
Results should be written at the end of the routine.
With Worksheets("Table")
.Range("A2").Value = startTime
.Range("B2").Value = endTime
.Range("C2").Value = runTime
End With
Documentation on the timer function

In the first line of your program get the date (no need to format):
Dim startTime as Date
startTime = Now()
At the end of your program, get the date again:
Dim endTime as Date
endTime = Now()
Then use the DateDiff
Dim timeInSeconds as long
timeInSeconds = DateDiff("s", startTime, endTime)

DateDiff() is what you are looking for. The "s" defines that you are looking for the difference in seconds.
Worksheets("Table").Range("C2").Value = DateDiff("s", Worksheets("Table").Range("A2").Value, Worksheets("Table").Range("B2").Value)
EDIT: http://www.likeoffice.com/28057/excel-date to learn more about working with dates and times in Excel VBA. It is important to understand that dates work differently within the context of VBA, and have their own unique set of syntax functions for manipulating.
2nd EDIT: A cleaner version of this would be:
StartDateTime = Now()
'Run Code
Worksheets("Table").Range("C2").Value = DateDiff("s", StartDateTime, Now())

There's a few ways you can use VBA to format cells / variables.
In no particular order, firstly you can format ranges with the NumberFormat property which can be applied like so:
Worksheets("Table").Range("C2").Value = Now()
Worksheets("Table").Range("C2").NumberFormat = "ss"
The other way is that you could format Now() using the Format() function:
Worksheets("Table").Range("C2").Value = Format(Now(), "ss")
See the documentation from Microsoft to implement different formats:
NumberFormat: http://msdn.microsoft.com/en-us/library/office/ff196401%28v=office.15%29.aspx
Format: http://msdn.microsoft.com/en-us/library/office/gg251755%28v=office.15%29.aspx

How i generally go about bragging my process time to user
Sub Process()
Dim startTime as Date
Dim endTime as Date
startTime = Now
'Logic for what your process must do
endTime = Now
MsgBox "Process completed in : " & Format(endTime - startTime, "hh:mm:ss")
End Sub

Related

VBA Double to Time

I have a VBA user form which when I press save after input data it writes to a spread sheet and set my time and date to Now() that is being written to a spread sheet where I split the now() value into time and date, when I read it back I get the date but my time in decimal format I would like to convert that decimal number back to time what is the formula for that thank you in advance my decimal number is something like '0.12425576899' so far I found this but it converts that to '00:the minutes on the double:00' here is the code
Public Function FromDecimalTime(ByVal t As Double) As Date
FromDecimalTime = TimeSerial(0, Fix(t), (t - Fix(t)) * 60)
End Function
The following will convert the Double into the Date Format. In order to only show the time portion of the date format, use the Format function:
Sub trythis()
Dim t As Double
t = Now()
Debug.Print CDate(t)
Debug.Print Format(t, "hh:mm:ss")
End Sub

How to make a spreadsheet formula execute every day

I have the following formula which fetches data from the same day from table UniqueLast:
=IFERROR(QUERY(UniqueLast!$A$3:X;"select * where dateDiff(A, now())=0"))
It runs correctly but sometimes the table where this formula is executed keeps the result from the previuos day which is already old. How can I make a regulation for running the formula in 00:00?
Create a macro function and include the above expression. Use VBExpress and create a script (.exe) to open the spreadsheet and run the macro. Add it in the Windows scheduled tasks.
Function to call in Macro
Function getNextRunTime() As Date
Dim curDate As Date
Dim curTime As Date
Dim chkTime As Date
Dim runTime As Date
curDate = Date
curTime = TimeValue(Now)
runTime = curDate + TimeValue("15:59:00")
chkTime = curDate + curTime
If chkTime > runTime Then 'schedule for next day'
runTime = DateAdd("d", 1, runTime)
End If
getNextRunTime = runTime
End Function
The SQL statement parameter of the QUERY function should be a single value of type TEXT. NOW() it not valid Google Query Language function. Google Sheets magnes dates on the background as numbers with a different EPOCH date so we should convert it to a date with the proper format. Try
=QUERY(
UniqueLast!$A$3:X,
"select * where dateDiff(A, date """&TEXT(now(),"yyyy-mm-dd")&""")=0"
)
Removed IFERROR in order to make it easy to check if change proposed works with the OP data. You could add it later once you are sure that it does.

TimeZone issue with Windows 7

When a date is returned from our UTC server database Windows very helpfully changes the Date to a DateTime (say 23 June 2017 to 2017-06-23 00:00) and then makes an adjustment for the current Time Zone (to, say 2017-06-22 16:00)... For years we have used the code below to convert it back...
About four months ago users running Windows 7 (Windows 10 doesn't seem to be effected) that did not have 'Automatically adjust clock for Daylight Saving Time' checked, or live in a state like Arizona where that option is not available, noticed that reports where returning the date from the day before - our DB is returning the correct date but the conversion is no longer working correctly..
Any suggestions?
Thanks
Public Function LocalDateFormat(ByVal InputDate As Date) As String
Dim vDate As String = InputDate.ToString("d", System.Globalization.CultureInfo.InvariantCulture)
Dim LocalZone As TimeZone = TimeZone.CurrentTimeZone
Dim CurrentOffset As TimeSpan = LocalZone.GetUtcOffset(InputDate)
Dim DayLightSaving As Boolean = LocalZone.IsDaylightSavingTime(InputDate)
Dim CalculatedOffset As New DateTime(InputDate.Ticks, DateTimeKind.Local)
If CurrentOffset.CompareTo(TimeSpan.Zero) < 0 Then
CalculatedOffset -= LocalZone.GetUtcOffset(InputDate)
If DayLightSaving = True Then
CalculatedOffset = CalculatedOffset.AddHours(1)
End If
Else
CalculatedOffset += LocalZone.GetUtcOffset(InputDate)
If DayLightSaving = True Then
CalculatedOffset = CalculatedOffset.AddHours(-1)
End If
End If
InputDate = CalculatedOffset
Dim vCulture As String = System.Globalization.CultureInfo.CurrentCulture.ToString
Dim vReturnDate As String = ""
Select Case vCulture
Case "en-US"
vReturnDate = Format(InputDate, "MM/dd/yyyy")
Case "en-GB"
vReturnDate = Format(InputDate, "dd/MM/yyyy")
Case Else
vReturnDate = Format(InputDate, "dd/MM/yyyy")
End Select
Return vReturnDate
End Function
Your entire function can be re-written as:
Public Function LocalDateFormat(ByVal InputDate As Date) As String
Return InputDate.ToLocalTime().ToShortDateString()
End Function
With the code so small, you may want to rethink whether there's any benefit of having this in a function at all.
As far as why your existing function didn't work properly:
TimeZone.GetUtcOffset already factors in whether DST is in effect or not, though it has some problems with that that are described in the MSDN docs.
You shouldn't be using TimeZone any more at all. If you need to work with time zones, use TimeZoneInfo, or Noda Time. In this case, you don't need either of them, as you're just converting from UTC to local time, which is what DateTime.ToLocalTime does.
This code has some logic that appears to think one should subtract an hour for DST if the offset is positive. Sorry, but DST doesn't work that way - you always add an hour (unless you are in Lord Howe Island, Australia, where you add 30 minutes).
It also seems to think you should add the offset from UTC if its positive and subtract it if its negative. This is essentially an absolute value function, and also incorrect.
All the culture stuff is handled for you by formatting within the current culture. There's no need to do it by hand.
You say it works fine on Windows 10, but I'm sorry - this is bad code that will have errors wherever it is run. Just use the built-in APIs provided by the framework. Don't reinvent the wheel. :)

Issue in Converting string to Date in VBA

I need to write a function which will convert 2 string parameters to dates and
return true/false after comparing the dates.
I have tried to implement this requirment by writing below mentioned code
Function CompareDate(StringDate1 As String, StringDate2 As String) As Boolean
Dim Date1 As Date
Dim Date2 As Date
Date1 = CDate(StringDate1)
Date2 = CDate(StringDate2)
If Date1 > Date2 Then
CompareDate = True
Else
CompareDate = False
End If
End Function
Dim test As Boolean
test = CompareDate("03-Mar-2016 02:43 PST", "01-Mar-2016 11:33 PST")
But I am getting "Type Mismatch" error at this line Date1 = CDate(StringDate1).
Any idea what needs to be modified to fix the issue.
Note : My function also needs to consider time and time zone while comparing dates.
try cdate(split(StringDate1," ")(0)) and (1) will give you the time to check also, when date1=date2? or you can replace the PST part
The parse problem is with the presence of a timezone. There are a lot of ways to manage this date time depending on what your endgame is but the most straightforward is just to drop off the timezone and let CDATE parse it. In the following code I assume that a) all of your times are in PST and b) there is a timezone on the end of every date. If these assumptions are wrong, modifications are necessary. If essential, managing multiple time zones could be done by converting everything to one time zone and, if desired, tracking what time zone it came from. But I don't know of any standard VBA module that knows the time zones so that would need an array from you.
Function CompareDate(strDate1 As String, strDate2 As String) As Boolean
Dim Date1 As Date
Dim Date2 As Date
Date1 = CDate(Left(strDate1, InStrRev(strDate1, " ")))
Date2 = CDate(Left(strDate2, InStrRev(strDate2, " ")))
CompareDate = (Date1 > Date2)
End Function
Maybe you could construct the timezone vs UTC offset array from the table here but I don't have time to process it right now. Pretty straightforward once you construct that array.
i think it would help if you formatted the date before doing CDate.
dateX = format(StringDate1, "mm/dd/yyyy")
You can also try somethign like this
dateX = cdate(format(stringdate1,"mm/dd/yyyy") - see that how works.
I don't have anythignt to test it with. If worst comes to worst, instead of passing the StringDate1 as string, pass it as Date and should be all set then. No need to do CDate in that case.
Function CompareDate(StringDate1 As Date, StringDate2 As Date) As Boolean
and Wherever you call this function CompareDate....do CDate then.. as such...
Call CompareDates(cdate(stringdate1), cdate(stringdate2))
The date portion gives you an integer value referring to the date, and the time portion gives you a fractional value for the time. So just add the two such as (using #Nathan_Sav code):
cdate(split(StringDate1," ")(0)) + cdate(split(StringDate1," ")(1))
Give this a try:
Function CompareDate(StringDate1 As String, StringDate2 As String) As Boolean
Dim Date1, Date2
Date1 = Split(StringDate1, " ")
Date2 = Split(StringDate2, " ")
CompareDate = IIf(DateDiff("d", Date1(0), Date2(0) > 0 And DateDiff("n", Date1(1), Date2(1)) > 0), True, False)
End Function

VBA - Displaying how long a sub took to run

I am trying to use the following code to display how long a series of commands took to run. In this example case, I expected it to come back with "10" or something similar.
Instead it comes back with:
What is going on and how can I format this correctly?
Sub timeyWimey()
Dim t1 As Date
Dim t2 As Date
Dim timeTaken As Date
t1 = Now()
Application.Wait (Now + TimeValue("0:00:10"))
t2 = Now()
timeTaken = t2 - t1
MsgBox timeTaken
End Sub
Edit:
Final Code after some great Answers:
Sub timeyWimey()
'Dim t1 As Double
'Dim t2 As Double
t1 = Now()
Application.Wait (Now + TimeValue("0:00:10"))
t2 = Now()
timeTaken = t2 - t1
MsgBox Format(timeTaken, "nn:ss.000")
End Sub
Results in:
BAM! Problem Solved! Thanks everyone for your help!
Date's are stored as a numeric value within the MS Access and MS Excel. So if in your immediate window (Ctrl+G) you type ?Cdbl(now()) you will get a number like this: 42195.5204050926.
The whole numbers depicts how many days have passed since 1899 December 30th, and the decimal shows how much of the current day has passed.
So in your code you are basically saying something like this:
timeTaken = 42195.5222337963 - 42195.5204050926
In this example I just checked Now() once and then again a few minutes later. So I ended up with 0.0018287037.
Now if I go to display that using a Date variable such as in your example, am basically saying what time was it at 0.0018287037 which is December 30th 1899, 12:02:38 AM.
You can visually see this by going back to your immediate window and typing ?cdate(0.0018287037) and you will get a result like: 12:02:38 AM. To take it one step further you can then type ?cdate(1.0018287037) and you will get a result saying: 1899-12-31 12:02:38 AM
So in your situation you can simply just change:
MsgBox timeTaken
To:
MsgBox Format(timeTaken, "nn:ss")
Note: I hadn't noticed in the screenshot it says "Excel" though this answer should still be valid.
Normally you'd use the DateDiff function to calculate the difference between two dates, but i think in your case you'll want something else, as DateDiff won't give you milliseconds. Instead, just replace your call to the "Now" function by Timer(), which is just a number of seconds (careful though, it only gives you the time elapsed since midnight, so t2 - t1 can be negative, and if your commands last several days you won't get any meaningful result).
You can try the timer function. As other answers indicate, there may be some caveats.
Dim startTime As Double, endTime As Double
startTime = Timer
Application.Wait (Now + TimeValue("0:00:10"))
endTime = Timer
msgBox endTime - startTime