Why does msgbox with these variables produce an error? - vba

apologies if this is a basic question, but I am self-teaching myself VBA PowerPoint and would appreciate it if someone could explain why I am getting an overflow error.
I have been trying to get the time my program user spends performing an activity using DateDiff and Now to set the start and end timers. My approach is to get the number of seconds and then work out how many days, minutes, hours and seconds will make up this number.
The below code works, however, whenever I use the Messagebox (Msgbox) function I get an overflow error. For example if you look at the code below everything works, until you uncomment one of my commented MsgBoxes and then the program crashes with a Run-time error '6': Overflow. I note the actual crash occurs on one of the subsequent calculation lines below the uncommented message box. I note the first MsgBox which is uncommented does not crash the computer.
I would be grateful if someone could explain why the computer crashes and second are there any changes to my code required in order to make it reliable to use?
Thank you for any comments!
Sub NewTimer()
Dim TimeStart As Date
Dim TimeEnd As Date
Dim Days As Long
Dim Hours As Long
Dim Hours2 As Long
Dim Hours3 As Long
Dim Minutes As Long
Dim Minutes2 As Long
Dim Seconds As Long
Dim TimePassed As String
Dim Seconds2 As Long
Seconds = Int(DateDiff("s", Now, Now + 1))
MsgBox "The total number of seconds that make up this number is " & Seconds
Days = Int(DateDiff("d", Now, Now + 1))
MsgBox "The total number of days in this number is " & Days
Hours2 = Seconds - (Days * 24 * 60 * 60) 'This gets the number of seconds remaining
Hours3 = Hours2 / (60 * 60) 'This works out the number of hours
Hours = Int(Hours3)
'MsgBox Hours
Minutes = Seconds - (Days * 24 * 60 * 60) - (Hours * 60 * 60) ' Hours2 - (Hours * 60 * 60)
'MsgBox Minutes
Minutes2 = Int(Minutes / 60)
'MsgBox Minutes2
'Minutes2 = Minutes / 60
Seconds = Seconds - (Days * 24 * 60 * 60) - (Hours * 60 * 60) - (Minutes2 * 60)
MsgBox "The time taken is " & Days & " days, " & Hours & " hours, " & Minutes2 & " minutes and " & Seconds & " seconds."

As other comments, when I ran your code I had no issues at all. However, you can achieve the same result with this code. See if it helps:
Sub NewTimer()
Dim TimeStart As Double
Dim TimeEnd As Double
Dim TimeDiff As Double
Dim Days As Long
Dim TimeDiffString As String
TimeStart = Now
TimeEnd = TimeStart + 4 + TimeValue("04:13:25")
TimeDiff = TimeEnd - TimeStart
Days = Int(TimeDiff)
TimeDiffString = Days & " days, " & Hour(TimeDiff) & " hours, " & Minute(TimeDiff) & " minutes and " & Second(TimeDiff) & " seconds."
MsgBox TimeDiffString
End Sub
Edit: follow-up to comments below.
In office applications, you can safely think of dates and times as decimal (floating point) numeric values, where the integer part is the number of days and the fraction part is a fraction of the day. Examples will make this clear:
1.5 is a day and a half -> 1 day and 12 hours -> 36 hours etc.
1 day and 2 hours is 1 + 2/24
1 hour is 1 / 24, approx. 0.041667
1 minute is 1 / (24 * 60), approx. 0.000694
1 second is 1 / (24 * 60 * 60), approx. 0.000012 and so on.
Office applications give you many functions you can use to format dates/times. For example in VBA:
Hour() gives you the hour on the clock. Hour(1.27) = Hour(3.27) = Hour(295.27) = 6
Minute() gives you the minutes on the clock. Minute(1.27) = Minute(3.27) = Minute(295.21) = 28
Second() gives you the seconds on the clock. Second(1.27) = Second(3.27) = Second(295.21) = 48
This is the same as saying that (6 hours + 28 minutes + 48 seconds) adds up to 0.27 of 1 day.
Day() gives you the calendar day of the month, where day 1 is defined depending on the context and your settings. For example in Excel VBA day 1 is generally December 31, 1899. therefore, Day(295.21) = 21 because 295.21 is 294 days after December 31, 1899 which corresponds to October 21, 1900.
Month() gives you the calendar month of the year. Therefore, Month(295.27) = 10
Year() gives you the calendar year. Therefore, Year(295.27 = 1900
This explains why I separated the day (the integer part of DateDiff in the code). If for example DateDiff = 295.27, then Day(DateDiff) is going to give you 21 not the 295 days you expect.
Homework: in the code above work out what fraction TimeValue("04:13:25") should result in. Check your answer with this code - no cheating ;):
Sub CheckMyAnswer()
MsgBox Format(TimeValue("04:13:25"), "0.000000")
End Sub
Phew, hope this helps. I am sure if you google the issue you will find far better explanations and plenty of videos, too.

Related

Timing a VBA code returned a negative time

I ran some code in VBA as per https://www.thespreadsheetguru.com/the-code-vault/2015/1/28/vba-calculate-macro-run-time and had a return of a negative value:
-20439 seconds
Does anyone know why? It actually ran for ~ 18hrs (1500 - 0900 next day)
Option Explicit
Sub CalculateRunTime_Minutes()
'PURPOSE: Determine how many minutes it took for code to completely run
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault
Dim StartTime As Double
Dim MinutesElapsed As String
'Remember time when macro starts
StartTime = Timer
'*****************************
'Insert Your Code Here...
'*****************************
'Determine how many seconds code took to run
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
'Notify user in seconds
MsgBox "This code ran successfully in " & MinutesElapsed & " minutes", vbInformation
End Sub
The code uses Timer.
The Timer returns a Single representing the number of seconds elapsed since midnight. SyntaxTimerRemarks In Microsoft Windows the Timer function returns fractional portions of a second. On the Macintosh, timer resolution is one second. MSDN
Thus, if you start running at 15:00, the code would return something meaningful, if you end up to 23:59. If you end the next day at 09:00, it would return negative value.
You can rebuild the code, in order to get the date in account as well. Use Now, which returns the date and the time - 21.02.2018 10:33:55
This looks like a good possible alternative:
Sub WorkstAtMidnight()
Dim StartTime As Date
StartTime = Now()
'Do something incredible
MsgBox Round((Now() - StartTime) * 24 * 60 * 60, 0)
'24 hours times 60 minutes times 60 seconds (usually I just do 24*3600)
End Sub
Another alternative:
MinutesElapsed = Format((Timer - StartTime) / 86400 + IIf(Timer < StartTime, 1, 0), "hh:mm:ss")
This keeps track of the hours and minutes accurately up to a whole day (i.e. it resets at 24 hours of runtime). After which the real question is why does your code take so long!

How to get cases to work

I am trying to answer a question in which I have to use cases in visual basic.
The question is:
Write a program that asks the user for the number of hours worked this week and their hourly rate of pay. The program is to calculate the grass pay. If the number of hours worked is greater than 40, the extra hours are paid at 1.5 times the rate. The program should display an error message if the number of hours worked is not in the range 0 to 60.
Here is the code I wrote, any ideas on what went wrong would be greatly appreciated.
Console.WriteLine("This will calculate the gross profit from the hours you work and the hourly pay")
Console.WriteLine("Your work hours can not be under 0 or above 60,
if you work above 40 hours the extra hours will be 1.5 times the original")
Console.Write("Please enter the hours you work a week: ")
Dim hours As Integer = Console.ReadLine()
Console.Write("Please enter the hourly pay you get: ")
Dim hourlyPay As Decimal = Console.ReadLine()
Dim message As String = "Your gross pay per week is: £"
Dim weeklyPay As Decimal
Select Case hours
Case 0 < hours < 40
weeklyPay = hours * hourlyPay
Case hours > 40 And hours < 60
weeklypay = ((40 * hourlyPay) + ((hours - 40) * (hourlyPay * 1.5)))
Case hours < 0 Or hours > 60
message = "Sorry the hours you entered are above the range try again"
End Select
Console.WriteLine(message & weeklyPay.ToString("N2"))
Console.ReadLine()
Select works on a first come first served basis, by testing for conditions and handling them in order you can eliminate each condition so that all that remains is the 'default' condition.
Select Case hours
Case Is > 60
message = "Sorry the hours you entered are above the range try again"
Case Is < 0
message = "Sorry the hours you entered are below the range try again"
Case Is > 40
weeklypay = ((40 * hourlyPay) + ((hours - 40) * (hourlyPay * 1.5)))
Case Else
weeklyPay = hours * hourlyPay
End Select
MSDN - Select...Case Statement (Visual Basic)
I figured out how to solve it:
Console.WriteLine("This will calculate the gross profit from the hours you work and the hourly pay") 'sends the message of what this program does
Console.WriteLine("Your work hours can not be under 0 or above 60,
if you work above 40 hours the extra hours will be 1.5 times the original") 'explains the boundaries and conditions
Console.ReadLine()
Console.Write("Please enter the hours you work a week: ") 'asks for the hours worked
Dim hours As Integer = Console.ReadLine() 'declares hours as an integer and sets it's value for what the user enters
Console.Write("Please enter the hourly rate of pay: ") 'asks for the hourly rate of pay
Dim hourlyPay As Decimal = Console.ReadLine() 'declares hourlyPay as a decimal and sets it's value for what the user enters
Dim message As String = "Your gross pay per week is: £" 'declares message as a string and sets it's value to tell the user what their pay is - this will be useful later
Dim weeklyPay As Decimal 'declares weekly pay as a decimal
Select Case hours 'An if statement would complicated to use so, i used a select case
Case 0 To 40 'when hours are between 0 and 40, then the weekly pay is normal (hourly rate * hours)
weeklyPay = hours * hourlyPay
Case 40 To 60 'however when hours are above 40, then the extra hours (hours - 40) are paid at a higher rate (1.5 times)
weeklyPay = ((40 * hourlyPay) + ((hours - 40) * (hourlyPay * 1.5)))
Case < 0 'when hours are under the boundary of 0 then send the error message
message = "Sorry the hours you entered are under the range try again "
Case > 60 'when hours are over the boundary of 60 then send the error message
message = "Sorry the hours you entered are above the range try again "
End Select
Console.WriteLine(message & weeklyPay.ToString("N2")) 'this sends the message across to the user and their pay
Console.ReadLine() 'stops the program from terminating

How to subtract Time in Excel VBA?

How do I subtract Time in Excel VBA?
I tried to subtract these two values, but I'm getting this value "2.1527777777778E-02" instead. What does this mean?
Timein = 12/7/16 12:00:00 AM
Timeout = 12/7/16 12:30:00 AM
Here's a sample of my code. Thanks in advance.
Dim Total as Double
Dim Timein as Date
Dim Timeout as Date
Total = TimeValue(Timeout) - TimeValue(Timein)
'Result Total=2.1527777777778E-02
You can use the DateDiff Function to get the difference in year/days/seconds or whatever.
Here the example for minutes.
Dim Timein As Date
Dim Timeout As Date
Timein = "12/7/16 12:00:00 AM"
Timeout = "12/7/16 12:30:00 AM"
Debug.Print DateDiff("n", Timein, Timeout)
Output:
30
Interval Explanation
yyyy Year
q Quarter
m Month
y Day of year
d Day
w Weekday
ww Week
h Hour
n Minute
s Second
What you have done is perfectly correct, as can be seen by the following code:
Sub test()
Dim Total As Double
Dim Timein As Date
Dim Timeout As Date
Timein = CDate(Range("A1").Value)
Timeout = CDate(Range("A2").Value)
Total = TimeValue(Timeout) - TimeValue(Timein)
Debug.Print Total
Debug.Print Format(Total, "hh:mm:ss")
Range("A3").NumberFormat = "hh:mm:ss"
Range("A3").Value = Total
Debug.Print "Number of hours = " & Total * 24
End Sub
As mentioned by vacip in a comment, Date/Time variables are stored in VBA in "days" so, for example, Now for me is the number 42867.7513310185.
2.1527777777778E-02 is using a method of displaying a value called Scientific Notation. In your case, it means 2.1527777777778 times 10 to the power of -2. Or you could think of the E-02 part as meaning shift the decimal point two places to the left (left because it's negative).
So: 0.021527777777778.
Excel treats time (both dates and times of day) as whole days so half a day (12 hours) would be represented as 0.5.
So the result itself represents the decimal fraction of an entire day, if you want this in minutes for example, you would multiply the value by 1440 (24hr x 60min make a day) which would give you 31mins.
In your example, you're finding the difference between 12:00 and 12:30 so you should actually be getting a result of 2.08333333333333E-02 which if multiplied by 1440 would give you 30mins.
Excel gives you tools to find the difference between two points in time though that take all that complex math(s) away - DateDiff and #holger has given you everything you need there to write your own code.
You have defined the total as double, which returns you number. you need to dim the total as date so that returns you a time.
Dim Total as Date
Dim Timein as Date
Dim Timeout as Date
Total = TimeValue(Timeout) - TimeValue(Timein)

Calculate X amount of hrs ahead only counting 9-5 hrs

I'm trying to get a quick ETA on some pre-determined values, 16 and 40. So for example, I need my code to quickly calculate an ETA on an item if it takes 16 hours, but only count the 9-5 (8) hours per day. Obviously I'd need to include the remaining hours of that day, which I have in the code snipped below. However I'm giving myself an ofly sore head trying to work out the best way to proceed with the code. Perhaps someone's got a good idea?
Dim TargetTime as Integer = 16
Dim currentHr As Integer = current.Hour
Dim TodaysRemainingHours As Integer = 0
If currentHr >= 9 AndAlso currentHr < 17 Then
'Count remaining hours
TodaysRemainingHours = (17- currentHr)
Else
'Dont count today
TodaysRemainingHours = 0
End If
My plan is:
TargetTime - TodaysRemainingHours --- Gives the value to count
to.
Somehow calculate the hours based on 9-5 time spans only.
Display lblOutput as: "ETA: 2pm 25/11/2016"
As you can see I know how to get the vaule I need to count to, but I need some help with firstly only counting the hours in each day from 9-5 and then returning the actual hour estimated. This isn't for anything profitable, it's a personal ETA program.
Thank you topshot, your comment helped me work it out! The below code seems to work for me, I haven't identified any issues anyway. I had to make sure I wasn't counting the remaining hours in the current day if the time is past 5pm as well. Thank you.
Dim TargetTime As Integer = 16
Dim current As Datetime = DateTime.now
Dim currentHr As Integer = current.Hour
Dim TodaysRemainingHours As Integer = 0
If currentHr >= 9 AndAlso currentHr < 17 Then
'Count remaining hours
TodaysRemainingHours = (17 - currentHr)
Else
'Dont count today
TodaysRemainingHours = 0
End If
If currentHr >= 9 AndAlso currentHr < 17 Then
'Deduct todays hours from target time.
TargetTime = (TargetTime - TodaysRemainingHours)
'Display results
MsgBox("ETA: " & Now.AddDays(TargetTime / 8))
Else
'Skip todays hours and count from tomorrow morning at 9am
Dim Tomorrow As DateTime = Today.AddDays(1)
Dim TomorrowMorning As TimeSpan = new TimeSpan(09, 00, 0)
Tomorrow = Tomorrow.Date + TomorrowMorning
'Display results
MsgBox("ETA: " & Tomorrow.AddDays(TargetTime / 8))
End If

Accurate Time Math For VB Including Division

The Problem I am having is with doing time mathematics in VB.
I am currently volunteering at a school and Helping with their Before/Aftercare system
So the goal for before care would be to take a time stamp and compare it to the time school starts that day and find how many half hours are in that given time difference rounding up to the nearest half hour.
For Example. A child Gets to Morning Care at 7:36 School starts at 9:30.
What I want my program to do is
9:30-7:36 = 1 hour 54 minutes
1 hour 54 minutes / 30 minutes = 3.XXX
round that up to 4 multiply by price per hour and my cost is 12
The code I have seems to be off by 15 minutes. I will display the code I use below. Please help by letting me know if there are logic issues or if the method chosen for time math is Poor
'Creating all my variables including half constant half variable times to
compare against
Dim DateIn As DateTime = System.DateTime.Now
Dim Month As Integer = Microsoft.VisualBasic.DateAndTime.Month(DateIn)
Dim Year As Integer = Microsoft.VisualBasic.DateAndTime.Year(DateIn)
Dim Day As Integer = Microsoft.VisualBasic.DateAndTime.Day(DateIn)
Dim DateMorning As New Date(Year, Month, Day, 7, 30, 0)
Dim DateSchoolStart As New Date(Year, Month, Day, 9, 30, 0)
Dim halfHour As System.TimeSpan = New TimeSpan(0, 0, 30, 0)
Dim ticksHalfHour As Long = halfHour.Ticks
Dim count As Integer
Dim cost As Integer
'Portion of a function that calculates cost if the time is in the right zone
If (DateIn >= DateMorning And DateIn < DateSchoolStart) Then
CareTime = DateSchoolStart.Subtract(DateIn)
Dim CareTicks As Long = CareTime.Ticks
count = ReturnCount(CareTicks, ticksHalfHour)
cost = count * price
WriteReport(cost, Year, Month, Day, name)
MessageBox.Show("Welcome to morning care " & name & "!")
Return cost
End If
' function that divides the two longs and does a mod calculation
Function ReturnCount(ByVal tick1 As Long, tick2 As Long) As Integer
If (tick1 Mod tick2 = 0) Then
count = tick1 / tick2
Return count
Else
count = 1 + (tick1 / tick2)
Return count
End If
End Function
I believe this is the relevant portion of the code. If you see a flaw in my logic or have a simpler way of achieving my goal your input would be much appreciated.