How to get cases to work - vb.net

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

Related

Why does msgbox with these variables produce an error?

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.

Excel Macro VBA: Add minutes and hours together where total can exceed 24 hours

hopefully this is a silly question with an easy answer.
I have no choice really what language I use, which is why I'm doing this in Excel with VBA.
I'm basically calculating total downtime hours over a month. I need to add small amounts of minutes together to find out a total that will be over 24 hours of course.
Here is the scenario:
Server A was down for 3 hours and 52 minutes this month.
Server B was down for 15 hours and 25 minutes this month.
Server B had 7 hours and 23 minutes downtime during a critical period, so this is multplied by 3 to equate it to non-critical downtime.
Server A has: 3 hours 52 minutes at x1
Server B has: 8 hours 2 minutes at x1
Server B has: 7 hours 21 minutes at x3
All downtimes and restoration times are manually listed in a sheet in time formats recognised by excel, eg:
event 1 : 19/11/2017 5:00 : 19/11/2017 14:12
event 2 : 13/11/2017 6:00 : 13/11/2017 6:40
event 3 : 13/11/2017 7:57 : 13/11/2017 9:01
event 4 : 17/11/2017 6:15 : 18/11/2017 8:10
Weekends are not counted
Only minutes between 6am and 6pm are counted
Minutes increase in priority during certain time periods:
06:00-07:00, 07:00-09:00, 09:00-10:00, 10:00-14:00
High priority minutes are multiplied to equate peak time usage with lower standard time usage
I'm struggling to find a way to add times together to count hours, excel trys to give answers relative to 01/01/1900 or some "real" date.
I'm going the opposite way, I have the real dates, I need to work with the hours between them. Is there a data format that is in plain hours:minutes?
I thought it was obvious but I'll state clearly in case, start time and end times are not necessarily on the same day. They can be any time, any relationship, sometimes start time will be after the end time due to how faults are reported. Obviously that counts as 0 minutes in that case.
My current methodology for attacking this problem is:
increase the start time until it becomes valid charge time
calculate the minutes until there is a change such as end of day or higher priority time slot, or start time = end time
add the calculated minutes to a total
increase the start time by the calculated minutes
start cycle again from the the new 'start time' and loop until there are no minutes remaining between start time and end time
startof:
'move to start of next chargeable day, if not on a chargeable day
'eg weekends, public holidays, easy function to write
Do While testForChargeable() = False
opnDate = DateAdd("d", 1, opnDate)
opnTime = "06:00"
Loop
'check if open time is past the end of chargeable time, 18:00
If (opnTime >= endofdayTime) Then
'move to start of next chargeable day
opnDate = DateAdd("d", 1, opnDate)
opnTime = "06:00"
End If
'check if open time is after close time and fault is excluded
If (opnDate >= bisDate) And (opnTime >= bisTime) Then
GoTo last
End If
'check if close time is on same day as start time
If DateDiff("d", opnDate, bisDate) = 0 Then
'if it is, add minutes between opntime and bistime
chargeTime = chargeTime + calculateChargeTime(opnTime, bisTime)
'calculation ends, loop naturally terminates
Else
'if not, add remaining mintes of day to chargeable time
chargeTime = chargeTime + calculateChargeTime(opnTime, endofdayTime)
'move to start of next day
opnDate = DateAdd("d", 1, opnDate)
opnTime = "06:00"
GoTo startof
End If
last:
Cheers
Edit: Now that we're on the same page and I have what I think is a workable solution for you, I'll replace my previous answer [re: How Excel dates are related to value (ie., 1 day = 1)] with this one. The previous answer (and my computer messing up while trying to post it) is viewable in the Edit History.
So, you need a way to count minutes duration, between two DateTimes, and include or exclude sub-time-ranges based on criteria that might require ongoing adjustment, and you want this in a VBA function for use in automation of downtime data analysis.
Try this:
Option Explicit
Function MinsBetween(startDateTime As Date, stopDateTime As Date, count_StartTime As Date, count_StopTime As Date) As Long
Dim startTime As Date, stopTime As Date
'ignore dates, use only the times
startTime = startDateTime - Int(startDateTime)
stopTime = stopDateTime - Int(stopDateTime)
If startTime >= count_StopTime Or stopTime <= count_StartTime Then
'entire period falls outside of times to count
MinsBetween = 0
Exit Function
End If
'make 'adj' times start/end at counted times if necessary
startDateTime = IIf(startTime < count_StartTime, count_StartTime, startTime)
stopDateTime = IIf(stopTime > count_StopTime, count_StopTime, stopTime)
'calculate & return minutes between (never return negative number)
MinsBetween = Abs(DateDiff("n", startDateTime, stopDateTime))
End Function
This function counts only the minutes between startDateTime and stopDateTime that also fall between count_StartTime and count_StopTime.
Expects:
- count_StartTime & count_StopTime to be an Excel Time (or number between 0 and 1)
- startDateTime & stopDateTime to be an Excel Time or DateTime.
Returns a long integer. Could be referenced in VBA or as a worksheet function.
Example usage:
The outage 'event' occurred from 05:00 to 07:03 on 2017/11/19, but only the times between 6am and 6pm should be counted:
Debug.Print MinsBetween("2017/11/19 05:00", "2017/11/19 07:03", "06:00", "18:00")
The outage 'event' occurred from 05:00 to 14:12 on 2017/11/19. The duration that occurred between [peak period] 1pm to 2pm are have higher priority and should be counted as "double-time":
Debug.Print (2 * MinsBetween("2017/11/19 05:00", "2017/11/19 14:12", "13:00", "15:00") )
As weekends are ignored entirely, those reports could be excluded with a simple check like this:
Function isWeekend(wDateTime As Date) As Boolean
isWeekend = Weekday(DateValue(wDateTime)) = vbSaturday Or Weekday(DateValue(wDateTime)) = vbSunday
End Function
...returns TRUE if the supplied date (or datetime) falls on a weekend, otherwise returns FALSE.
You could use a combination of these functions to build sub or worksheet function around your custom criteria and adjust as needed.
For example:
Function DownTimeMinutes(startDateTime As Date, stopDateTime As Date) As Long
'you could process your custom criteria for each start/stop period here
Dim dtMinutes As Long
'for example:
'IGNORE DOWNTIME ON WEEKENDS
If isWeekend(startDateTime) Then
'ignore weekeends
DownTimeMinutes = 0
Exit Function
End If
'COUNT MINUTES BETWEEN 6AM-6PM with "x1" multiplier
dtMinutes = MinsBetween(startDateTime, stopDateTime, "06:00", "18:00")
'DON'T COUNT LUNCH BREAK (or something like that)
'(subtract these minutes from total)
dtMinutes = dtMinutes - MinsBetween(startDateTime, stopDateTime, "12:00", "12:30")
'COUNT MINUTES BETWEEN 14:00-15:00 as "x3"
'(already counted as "x1" so add "2x these minutes"
dtMinutes = dtMinutes + (2 * MinsBetween(startDateTime, stopDateTime, "14:00", "15:00"))
'return adjusted minutes for this downtime event
DownTimeMinutes = dtMinutes
End Function
Side note: This is the short-story of the long-example I was getting at when I thought part of your issue was trouble converting varying M/D/Y , MM/DD/YY , M-DD-YYYY , etc, manual entries to DateTimes that Excel would recognize regardless of the user's Regional date settings.
As I understand it, you don't need it now but I figured I might as well add it to my answer anyway :
=DATE(MID(RIGHT(LEFT(A1,FIND(" ",A1)-1),LEN(LEFT(A1,FIND(" ",A1)-1))-FIND("/",LEFT(A1,FIND(" ",A1)))),FIND("/",RIGHT(LEFT(A1,FIND(" ",A1)-1),LEN(LEFT(A1,FIND(" ",A1)-1))-FIND("/",LEFT(A1,FIND(" ",A1)))))+1,4),LEFT(RIGHT(LEFT(A1,FIND(" ",A1)-1),LEN(LEFT(A1,FIND(" ",A1)-1))-FIND("/",LEFT(A1,FIND(" ",A1)))),FIND("/",RIGHT(LEFT(A1,FIND(" ",A1)-1),LEN(LEFT(A1,FIND(" ",A1)-1))-FIND("/",LEFT(A1,FIND(" ",A1)))))-1),FIND("/",RIGHT(LEFT(A1,FIND(" ",A1)-1),LEN(LEFT(A1,FIND(" ",A1)-1))-FIND("/",LEFT(A1,FIND(" ",A1))))))+TIMEVALUE(RIGHT(A1,LEN(A1)-FIND(" ",A1)))
Generally I don't condone the use of gigantic formulas (I was more concerned about getting it into a single function that about readability), and there are other ways to deal with date issues caused by Regional differences in shared workbooks (including Windows API) but in most cases I find text manipulation will do the job too.

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.

Calculate time (in hours and minutes) from given rate of payment (in VB.net)

How can I generate the time (in hours and minutes) from given rate (for payments)? The user will need to enter the payment and the rate to get the total time duration. How can this mission be accomplished?
example:
rate = $2.00 per hours
payment = $5.00
result:
duration = 02 h 30 minutes
Thank you.
Use TimeSpan to simplify your code...
Private Function GetDuration(hourlyRate as decimal, payment as decimal) As TimeSpan
return TimeSpan.FromHours(payment / hourlyRate)
End Function
' ...
Dim duration = GetDuration(2, 5)
Console.WriteLine("{0} hours {1} minutes", duration.Hours, duration.Minutes)
Fiddle: http://dotnetfiddle.net/2tvYMK
Once you have the decimal point representation of time in hours (ie. 2.5), all you have to do is:
take the integer part - that's the number of full hours;
subtract the integer part from total and multiply by 60; that's the number of minutes
Something along these lines should work:
Dim hours as Integer
Dim minutes as Integer
Dim time as Double
time = payment / rate
hours = CInt(time)
minutes = CInt((time - hours) * 60)
Console.WriteLine("duration = {0} h {1} minutes", hours, minutes)
hours = payment \ rate;
minutes = (payment/rate - hours) * 60;
Use a TimeSpan structure. It will do the calculations of hours and minutes for you.
Dim rate As Double = 2.0
Dim payment As Double = 5.0
Dim time = TimeSpan.FromHours(payment / rate)
Dim duration = [String].Format("{0:00} h {1:00} minutes", time.Hours, time.Minutes)
' ==> "02 h 30 minutes"
You can also use the Decimal type when working with money. It has the advantage of not introducing additional rounding errors when converting from and to binary formats. However, TimeSpan.FromHours expects the hours as Double. Therefore Double seems appropriate for this little example.