Confusing to my condition if else using two conditions - vb.net

How Can I use "AND" in if else condition.
1st Condition: (Val(TextBox9.Text) > Val(time.Text))
2nd Condition:
((Format(CDate(Strings.Right(TextBox9.Text.Trim, 11)))) >
(Format(CDate(Strings.Right(time.Text.Trim, 11)))))
I have a problem in my statement condition, it is always execute when the first condition becomes true. I want my condition execute when my two condition becomes true, My big problem is when my 1st condition becomes true and my second condition is false it still executing which is wrong, the output should be "Second Condition is false".
If (Val(TextBox9.Text) > Val(time.Text)) AndAlso
((Format(CDate(Strings.Right(TextBox9.Text.Trim, 11)))) >
(Format(CDate(Strings.Right(time.Text.Trim, 11))))) Then
Console.writeline("Execute both condition is true")
else
Console.writeline("Second Condition is false")
end if

If you are having trouble diagnosing the issue with your conditionals, break them up into several lines, to help you better understand what you are comparing. For example you could do this:
Dim firstCompare = Val(TextBox9.Text) > Val(Time.Text)
Dim formattedTB9 = Format(CDate(Strings.Right(TextBox9.Text.Trim, 11)))
Dim formattedTime = Format(CDate(Strings.Right(Time.Text.Trim, 11)))
Console.WriteLine(String.Format("{0} > {1}", formattedTB9, formattedTime))
Dim secondCompare = formattedTB9 > formattedTime
If (firstCompare) AndAlso (secondCompare) Then
Console.WriteLine("Execute both condition is true")
Else
Console.WriteLine("One of the conditions is false")
End If
Now looking at your code, are you sure you want to be comparing formatted strings of dates and times you just converted from a textbox? Now that things are broken up, leverage the debugger to determine what values you are comparing and focus on tweaking it to be exactly what you want. Use the correct datatypes when comparing objects and ensure you understand how functions like Val and CDate work.

This is not a good way to compare two dates and times. You should first compare dates (not dates converted to strings) and only if they are same compare times. That's because if one date is larger or smaller than other, time doesn't matter. But when they are same, time is important. And you shouldn't compare strings, because when it's formated mm/dd/yyyy, months and days are more important for comparing than years.
If CDate(Strings.Right(TextBox9.Text.Trim, 11))>CDate(Strings.Right(time.Text.Trim, 11)) Then
Console.writeline("Date1 is bigger")
elseif CDate(Strings.Right(TextBox9.Text.Trim, 11))=CDate(Strings.Right(time.Text.Trim, 11))
If Val(TextBox9.Text) > Val(Time.Text) Then
Console.writeline("Date1 is bigger")
elseif Val(TextBox9.Text) = Val(Time.Text)
Console.writeline("Dates are equal")
else
Console.writeline("Date1 is smaller")
end if
else
Console.writeline("Date1 is smaller")
end if

Related

IIF false expression impacting truthiness?

I am developing an SSRS tablix report and struggling to remove some error messages from certain cells. The Expression in the cell is as follows:
=Iif(IsNothing(First(Fields!Details.Value)) , "", Join(Code.RemoveDuplicates(LookupSet(Fields!studyTitle.Value, Fields!studyTitle.Value, Fields!Link.Value ,"DataSet1")), vbCrLf ))
The custom function that's referenced is as follows:
Public Shared Function RemoveDuplicates(ByVal items As Object()) As String()
System.Array.Sort(items)
Dim k As Integer = 0
For i As Integer = 0 To items.Length - 1
If i > 0 AndAlso items(i).Equals(items(i - 1)) Then
Continue For
End If
items(k) = items(i)
k += 1
Next
Dim unique As [String]() = New [String](k - 1) {}
System.Array.Copy(items, 0, unique, 0, k)
Return unique
End Function
The problem I'm encountering is that cells in the output will display "#ERROR" if they are being run through the custom function with multiple blank values.
The goal of the initial IIF statement is to test those rows first to make sure that the function is only applied to those rows that have values, and the other cells should just be blank. The problem is that I'm still seeing errors for those cells, as if the false condition is applied anyway.
However, if I edit my IIF statement to have the same test condition but different true-part and false-part i.e.:
Iif(IsNothing(First(Details.Value)), "true", "false"))
Then suddenly I see exactly the rows I would expect to see marked true and false. If this is the case then I can't figure out where the errors are coming from in my initial statement.
I know the issue has to be somewhere with the RemoveDuplicates function because when I take that part out and just Join my duplicated values then I see no errors, and the false rows are the same as identified above.
Does anyone see something I'm missing that is generating this error or causing this seemingly inconsistent behavior from the IIf function?
Use If instead of IIf. The If construct shortcuts the evaluation, while the IIf evaluates all expressions.
=If(IsNothing(First(Fields!Details.Value)) , "", Join(Code.RemoveDuplicates(LookupSet(Fields!studyTitle.Value, Fields!studyTitle.Value, Fields!Link.Value ,"DataSet1")), vbCrLf ))
This is only available in VB.net and is not available in VBA. In VBA, you would use a standard If-Then-Else construct.

Excel VBA how to use index when we have more if then else function

I have a VBA code with more then 50 lines of If Then ElseIf function. When I run macro, it will satisfy one "if" condition. If the data meet, 50th Elseif condition, then macro will go through unto 49 if condition. I know, one basic value that meet the condition. Since I am able to find value that meet condition, Can I directly jump into that particular if Condition? Any help would be much appreciated
If A=10 and B=39 then
Do Something....
Elseif A=11 and B=30 and C=56 then
Do Something....
Elseif A=13 and B=35 and C=60 then
Do Something....
...
etc
Here Since I know A=13, Can I directly jump to
Elseif A=13 and B=35 and C=60 then
without going through first two if condition?
To your question - can you prioritize the 49. ElseIf condition - NO.
But you can put it in number 1 or 2, if you want to do it faster in debugging.
Like this:
Public Sub TestMe()
Dim a As Long
a = 5
If a < 6 Then
Debug.Print "The most popular"
ElseIf a = 5 Then
Debug.Print "The 2. most popular"
ElseIf a > 2 Then
Debug.Print "The 3. most popular"
End If
End Sub
As mentioned in the comments, the fact that you would have about 50 small evaluations would not slow your code (unless there is a non optimized function in the evaluations or you are accessing a database there).

Equating time values in IF statement

Good morning,
I am having an issue whereby logical statements regarding time values are not evaluating as expected.
Is there a known issue with equating recurring decimals logically?
For clarity here is a sample of the code in question.
Function compareTimes(timeCurrent, timeStart, timeEnd, timeBreak1, Optional timeLunch As Variant, Optional timeBreak2 As Variant)
If timeCurrent >= timeStart And timeCurrent < timeEnd Then
If timeCurrent = timeBreak1 Or timeCurrent = timeBreak2 Then
compareTimes = "b"
ElseIf IsMissing(timeLunch) = False Then
timeLunchEnd = timeLunch + (1 / 48)
If timeCurrent >= timeLunch And timeCurrent < timeLunchEnd Then
compareTimes = "L"
Else
compareTimes = 1
End If
Else
compareTimes = 1
End If
Else
compareTime = 0
End If
End Function
All arguments of the function are Excel times in the form h:mm.
An example of the error is the 2nd If statement - when timeCurrent and timeBreak1 are the same cell in Excel, the function outputs "b" as expected.
But if timeCurrent and timeBreak1 are in different cells with same value (e.g 12:00) it returns 1 instead.
Any help on understanding logicals and floating points would be much appreciated.
Though you may be showing the time as h:mm, Excel actually stores the full value including seconds. If you change the cell formatting to h:mm:ss, the values may not be "identical" as assumed. Times are stored as Date.Time where, numbers before the decimal represent days and those after the decimal represent the fractional part of a 24 hour day (ie 0.5 = 12:00 noon). Try changing the formatting of the cells to show date and time just to be sure the entire "date value" is consistent with your expectations.
The variables for time should be defined as double to ensure there are no issues with the data types being considered. It's not clear how the time is entered.

Comparing dates for overlap - not avoiding

I'm working on a timetabling piece of code. I am using a system of university modules and events associated to those modules, ie
Module CSC3039
Event1 - Lecture
Event2 - Lecture
Event3 - Practial etc
I need to check the times of each event in the module against each other and compare for clashes. The clashes do not need to be rectified, just highlighted. The table I will use is Events containing Event_ID (PK), Module_code (FK), Start_Date_Time, End_Date_Time plus other fields that don't matter here. I have figured out that I need to implement a For Each statement, ultimately resulting in an if statement such as:
if (startTime1 <= endTime2 or endTime1 >= startTime2) CLASH
My problem is trying to figure out the actual for loop here. I don't know what to write to declare my start times and end times. I presume it is a case of taking event1 and getting its start and end and then checking if event 2, 3 or 4 fit the above if statement. I'm trying to get this but could really use some guidance.
EDIT... Based on suggestions below I have implemented the following code:
'return all relevant tables from the Modules database, based on the module code entered by the user.
Dim eventTime = (From mods In db.Modules
Join evnt In db.Events On mods.Module_code Equals evnt.Module_code
Join rm In db.Rooms On rm.Room_ID Equals evnt.Room_ID
Join build In db.Buildings On build.Building_code Equals rm.Building_code
Where ((mods.Module_code = initialModCode) And (evnt.Room_ID = rm.Room_ID))
Select evnt.Event_ID, evnt.Module_code, evnt.Event_type, evnt.Start_Date_Time, evnt.End_Date_Time, build.Building_code, rm.Room_Number)
'use the gridview to display the result returned by the above query
gdvEventsTable.DataSource = eventTime
gdvEventsTable.DataBind()
Dim listClashes As New List(Of Array)
For i As Integer = 0 To eventTime.Count - 1
For j As Integer = i + 1 To eventTime.Count - 1
If (eventTime.ToList(i).Start_Date_Time < eventTime.ToList(j).End_Date_Time) And (eventTime.ToList(i).End_Date_Time > eventTime.ToList(j).Start_Date_Time) Then
MsgBox("Clash", MsgBoxStyle.MsgBoxSetForeground, "")
listClashes.Add(eventTime)
Else
MsgBox("No Clash", MsgBoxStyle.MsgBoxSetForeground, "")
End If
Next
Next
When trying to add an event to my array list I have noticed, in debug, that no events are sent to the list.
If you want to compare all the pairs of events that are in an array or some kind of a collection, you can use a loop like:
Dim ModuleEventArray() As ModuleEvent
'...
For i As Integer = 0 To ModuleEventArray.Length - 1
For j As Integer = i + 1 To ModuleEventArray.Length - 1
'test if ModuleEventArray(i) overlaps with ModuleEventArray(j)
Next
Next
ModuleEvent here would be another class or structure that has fields startTime and endTime. The test
if (startTime1 <= endTime2 or endTime1 >= startTime2)
is not enough to test for overlap, but maybe you can figure out the correct test yourself :)
EDIT:
Since I see you use some sort of collection, not array, the code you need should be something like:
For i As Integer = 0 To eventTime.Count - 1
For j As Integer = i + 1 To eventTime.Count - 1
If (eventTime.Item(i).Start_Date_Time < eventTime.Item(j).End_Date_Time) And (eventTime.Item(i).End_Date_Time > eventTime.Item(j).Start_Date_Time) Then
MsgBox("Clash")
Else
MsgBox("No Clash")
End If
Next
Next
Before you write your code, you need to first decide what your algorithm is going to be. For example, if you use the naive method your presume, the code is indeed straightforward (basically 2 nested loops) but the complexity if O(n²).
Depending on how much data you have, whether it is in a database, how likely you expect clashes to be, whether you always have the full list of events at the start or you need to find clashes incrementally, etc... different solutions might be preferred. One consideration is whether you need to partition the list into non-clashing sets of events or just produce a yes/no answer (one one for each event) stating whether there is a clash.
You might consider doing something different instead, like sorting the list by start time before you start comparing. That will allow you to walk the list only once.
My comparisons are coming from the database. Prior to the code below I have a query which returns all the records from my Events table, based on the user input of a Module_Code. This code will show the clashes, through a msgbox. I will be changing it to populate a list. It's not the prettiest and will probably lead to a lot of duplication but it achieves my main objective.
For Each evnt In eventTime
Dim startTime1 = evnt.Start_Date_Time
Dim endTime1 = evnt.End_Date_Time
For Each evat In eventTime
Dim startTime2 = evat.Start_Date_Time
Dim endTime2 = evat.End_Date_Time
If (startTime1 < endTime2) And (endTime1 > startTime2) Then
MsgBox("Clash")
Else
MsgBox("No Clash")
End If
Next
Next

(OrElse and Or) and (AndAlso and And) - When to use?

What is the difference between (OrElse and Or) and (AndAlso and And)?
Is there any difference in their performances, let say the correctness benefit?? Is there any situation that I shoudn't use OrElse and AndAlso?
Or/And will always evaluate both1 the expressions and then return a result. They are not short-circuiting.
OrElse/AndAlso are short-circuiting. The right expression is only evaluated if the outcome cannot be determined from the evaluation of the left expression alone. (That means: OrElse will only evaluate the right expression if the left expression is false, and AndAlso will only evaluate the right expression if the left expression is true.)
Assuming that no side effects occur in the expressions and the expressions are not dependent (and any execution overhead is ignored), then they are the same.
However, in many cases it is that the expressions are dependent. For instance, we want to do something when a List is not-Nothing and has more than one element:
If list IsNot Nothing AndAlso list.Length > 0 Then .. 'list has stuff
This can also be used to avoid an "expensive" computation (or side-effects, ick!):
If Not Validate(x) OrElse Not ExpensiveValidate(x) Then .. 'not valid
Personally, I find that AndAlso and OrElse are the correct operators to use in all but the 1% - or less, hopefully! - of the cases where a side-effect is desired.
Happy coding.
1 An Exception thrown in the first expression will prevent the second expression from being evaluated, but this should hardly be surprising ..
Besides the short-circuiting mentioned in the other answers, Or/And are usable as bitwise operators where OrElse/AndAlso are not. Bitwise operations include combining values of Flags enums, such as the FileAttributes enumeration where you might indicate a file is both read only and hidden by FileAttributes.ReadOnly Or FileAttributes.Hidden
The difference is that OrElse and AndAlso will short-circuit based on the first condition, meaning that if the first condition doesn't pass, the second (or more) conditions will not be evaluated. This is particularly useful when one of the conditions might be more intensive than the other.
Example where Or is fine (both conditions evaluated):
If Name = "Fred" Or Name = "Sam" Then
It really doesn't matter which way around they are evaluated
The following AndAlso is useful because the second condition might fail
If Not SomeObject Is Nothing AndAlso CheckObjectExistsInDatabase(SomeObject) Then
This allows for the first condition to check whether the object has been set and only if it has been set will go and check the database (or some other task). If this had been a plain And keyword, both would be evaluated.
#Gideon - glad someone pointed that out. Here is a simple test that shows the dramatic impact of AndAlso:
Dim tm As New Stopwatch
Const tries As Integer = 123456
Dim z As Integer = 0
Dim s() As String = New String() {"0", "one"}
Debug.WriteLine("AndAlso")
For x As Integer = 0 To s.Length - 1
z = 0
tm.Restart() 'restart the stopwatch
For y As Integer = 0 To tries
If s(x) = x.ToString AndAlso s(x) = y.ToString Then '<<<<<<<<<<
z += 1
End If
Next
tm.Stop()
Debug.WriteLine(x.ToString.PadRight(3, " "c) & z.ToString.PadRight(10, " "c) & tm.Elapsed.ToString)
Next
Debug.WriteLine("And")
For x As Integer = 0 To s.Length - 1
z = 0
tm.Restart() 'restart the stopwatch
For y As Integer = 0 To tries
If s(x) = x.ToString And s(x) = y.ToString Then '<<<<<<<<<<
z += 1
End If
Next
tm.Stop()
Debug.WriteLine(x.ToString.PadRight(3, " "c) & z.ToString.PadRight(10, " "c) & tm.Elapsed.ToString)
Next