VBA Compare times correctly - excel

I am using VBA to compare two times from a spreadsheet.
Im my example the actual value form the sheet is 23:00 in two cells. I use them for an if-statement, the values both come from two different arrays from the type Variant.
if dataArr(v1) = rowArr(v2) Then
If I debug the two values it shows the two value like this
0,958333333333333 / 0,958333333333333
They seem the same but the compare in the if-statement returns false
So I subtracted the two value to see if the result is zero.
dataArr(v1) - rowArr(v2)
In this case the result is not zero but
3,33066907387547E-16
So something is wrong with the compare or the two double values that represent the time.
The only working solution I found was to convert them to string values by
CStr(dataArr(v1)) = CStr(rowArr(v2))
which returns true as it should be.
I don't really like this solution because it is not really how it should work. I also investigated what happens to the values before they end up in the compare but I could not find any mistake . Actually all the values in the dataArr are coming from the spreadsheet (ListObject.DataBodyRange.Value) and then certain values are copied to the rowArr out of the dataArr so it really should be the same value.
Any suggestions? Thanks!

If the cells are actually formatted for time instead of a string, I would make the definition of my arrays a "Date" not a "Variant".
Then you would have all the date/time related functionality in VBA at your disposal (like DateDiff() ).

Sometimes floating point inaccuracies creep in. If you want to compare then take the Absolute Value (ABS) of the subtraction and see if it is below a tolerance level, say, 1E-7 (a millionth).

Thanks to Florent B I got a solution that works!
Florent B: To compare the equality of two dates, you need to round to the precision which is 24hrs x 60min x 60 sec
So the solution is:
If Round(dataArr(v1) * 86400) = Round(rowArr(v2) * 86400) Then
It makes perfektly sense. Thanks a lot!

Related

nested if calculation in excel

I have column I as a calulation column and this is what I currently wrote.
and this gives me nothing.
=IF(B2<>""&D2<>"",B2*D2,IF(B2<>""&D2=""&C2<>"",B2*C2,IF(A2<>""&C2<>""&AND(B2&D2=""),A2*C2,IF(A2<>""&C2=""&D2<>""&B2="",A2*D2,A2*C2))))
The logic is if B2 and D2 are not null multiply b2*d2
if B2 is not null and D2 null then b2*c2
If B2 is null and D2 is not null then a2*d2
else a2*c2
Is any ways to make this code work?
Thank you
Alternative ways or rewriting your formula:
=IF(AND(B2<>"",D2<>""),B2*D2,IF(D2="",IF(B2<>"",B2*C2,A2*C2),IF(D2<>"",A2*D2,A2*C2)))
=IF(AND(B2<>"",D2<>""),B2*D2,IF(AND(B2="",D2=""),A2*C2,IF(D2="",B2*C2,A2*D2)))
They will make negligible difference in performance and what not. BruceWayne's answer is probably more readable in terms of following your logic and therefore easier to maintain or understand in the future. The above answers should provide the same results but are a few characters shorter in length.
And as a wacky alternative for thinking potentially outside the box:
=CHOOSE(SUM((B2<>"")*2+(D2<>""))+1,A2*C2,A2*D2,B2*C2,B2*D2)
Expanding (not just my waist size)
I had time on my hands so I was fooling around with the concept of TRUE and FALSE being equal to 1 and 0 when sent through a math operation. When I started looking at the options this reminded me of how a binary number works. Not that I have bgiven it too much thought, but I think it works because the options for each cell are binary or TRUE/FALSE. Since every possible combination was covered with a unique out come, I just had to come up with a formula that would produce unique results. In this case I just took the converting a a binary number approach. The key is TRUE = 1 after a math operation and FALSE = 0. Now going the other direction is not quite the same but as Jeeped once put it, 0 is FALSE and everything else is TRUE. so 3, -3, and 3.14 are all treated as TRUE if using the numerical values as the outcome of a logic check.
=IF(3.14,"THIS NUMBER IS TRUE","ONLY 0 IS FALSE")
So less side tracking and back on point (not sure how much I need to expand to!).
Looking at the table above, you will note in the yellow area, all possible combination for BLANK and NOT BLANK are listed. If you then assign a value to the column the same way binary numbers are (note row A) you can then start generating all the possible numbers
I started by generating the list I needed in E2:E5 for numbers that CHOOSE could work with. I assumed 0 would beat up CHOOSE and cause it to fail. I knew that FALSE+FALSE=0 and I also knew that TRUE+TRUE=2 and that both TRUE+FALSE=1 and FALSE+TRUE=1. I needed a way to distinguish the later two and I knew I needed a total of 4 results. That is when binary counting/conversion whatever you want to call it kicked in. I placed the following formula in D2 and copied down
=SUM((A2<>"")*2+(B2<>""))
Note the brackets around the logic check and
that the logic checks are sent through a math
operation before being summed.
technically speacking it is really:
=SUM((A2<>"")*2+(B2<>"")*1)
however the *1 is not needed
once I had that list generate, it was a simple +1 added to it to get into the 1 to 4 range seen in E2:E5.
Now that I had a way of generating the index number the only thing left to do was to match up the required results/formula with the right combination.
=CHOOSE(SUM((A2<>"")*2+(B2<>""))+1,"A","B","C","D")
Well I felt like I was beating a dead horse there for a bit, so if I over explained, my apologies. If there is something still missing ask for more explination.
UPDATE TID BIT
IF there were more columns to check it may be possible to adjust the choose formula by simply adding the next binary value to the column and making sure there is an appropriate number of results in the choose list. There should be 2^(# of columns to check) options
=CHOOSE(SUM((A2<>"")*4+(A2<>"")*2+(B2<>""))+1,"A","B","C","D","E","F","G","H")
Which kind of beats multiple nested IFs for brevity, but I think I finds the nested IFs easier to understand.
You should be using AND():
=IF(AND(B2<>"",D2<>""),B2*D2,IF(AND(B2<>"",D2=""),B2*C2,IF(AND(B2="",D2<>""),A2*D2,A2*C2)))
You seem to be mixing operators from other programming languages:
In Excel:
AND : binary operator : AND(TRUE, FALSE) => FALSE
& : concatenation : "Hello " & "World" => "Hello World"

Using ROUND after Nested IF Statements in Excel

I am working on a spreadsheet for a client that calculates values and shows them as fractions after a good amount of deductions. We were running some test after I had it all set and ready and they ran a certain number through the spread sheet. I'll try to beak it down as easily as possible (any value with brackets is user input. So Width is [94.5(94 1/2)] that number get subtracted by 7.5312(7 17/32 that equals 86.9688(86 31/32) that number is then divided by [3] which then equals 28.9896(28 95/96) This is where the problem is though. 95/96 is not a "real" fraction is there a way I can round numbers like this down to 64ths? They were expecting 63/64ths Even though the math is correct they need it to round down in those cases.
The If statement is this:
=IF(E4=1,(K4-F19)/1,IF(E4=2,(K4-G19)/2,IF(E4=3,(K4-H19)/3,IF(E4=4,(K4-I19)/4,IF(E4=5,(K4-J19)/5,IF(E4=6,(K4-K19)/6,IF(E4=7,(K4-L19)/7,IF(E4=8,(K4-M19)/8,IF(E4=9,(K4-N19)/9,IF(E4=10,(K4-O19)/10,0))))))))))
This is a single part of the IF statement:
=IF(E4=1,(K4-F19)/1
Is there a way around this or are they SOL(Sorta Outta Luck)?
Thanks for any insight.
Assuming in A1, please try:
=ROUNDDOWN(A1*64,0)/64
with suitable formatting.
This ensures that all results are multiples of 1/64.

Is there Infinity in Spreadsheets?

I am wondering if there is any way to represent infinity (or a sufficiently high number) in MS Excel.
I am particularly looking for something like Double.POSITIVE_INFINITY or Double.MAX_VALUE in Java.
I like to use 1e99 as it gives the largest number with the fewest keystrokes but I believe the absolute maximum is actually 9.99999E+307. At that stage of the number spectrum I don't think there is much difference as far as Excel is concerned.
I think it's worth adding that, Infinity as well as other special values can be returned from a vba function (How do you get VB6 to initialize doubles with +infinity, -infinity and NaN?):
Function Infinity(Optional Recalc) As Double
On Error Resume Next
Infinity = 1/0
End Function
When entered as a cell formula a large number is shown (2^1024). You can set a conditional format to show "+Infinity" as a number format with a formula condition:
=AND(ISNUMBER(A1),A1>2^1023*(2-2^-52))
A dummy argument containing a dynamic reference can be inserted so that values are recalculated when the workbook is opened, for example:
=Infinity(IF(,) IF(,))
With LibreOffice 6 I use 1.79769313486231E+308 that seems the largest number it allows me to enter, but I miss not having an exact representation of +- infinite, also because I suspect the number above is implementation specific...
This is an other point that makes me think that spreadsheets are great for visualising, editing and simple computations on tabular data, but for doing more complex operations/modelling a real programming language is a must...

Excel IF Date less than a Date not working

I have the following Excel code:
=IF(K4<=31/03/2014,TRUE,FALSE)
K4 contains a date:
01/01/2014
Yes, the code brings back FALSE, I have also tried =IF(K4<="31/03/2014",TRUE,FALSE) but with the same result.
Any ideas or suggestions as to where I am going wrong?
Use
=IF(K4<=DATE(2014,3,31),TRUE,FALSE)
You are testing an inequality with a Float <= String, which returns FALSE. The DATE(,,) fx gives you the required Float for equality comparison.
Alternatively, =K4<=DATE(2014,3,31) is a shorter way of achieving the same.
What K4<=31/03/2014 evaluates to is:
K4 <= (31/03)/2014
31/03 gives 10.333... and that divided by 2014 gives 0.005131... which is why it will always evaluate to false (01/01/2014 is equivalent to 41640, i.e. the number of days since '00/01/1900')
I don't know if it's a system thing, but =IF(K4<="31/03/2014",TRUE,FALSE) gives me TRUE, but then, so does =IF(K4<="31/03/2013",TRUE,FALSE).
A quick and dirty trick would be to multiply the string by 1:
=IF(K4<="31/03/2014"*1,TRUE,FALSE)
The multiplication tells excel to convert the string to a number, if it is parsable (You can also use any other numerical operation that doesn't change the value itself, such as +0).
Note: Excel dates and numbers are the same. Dates are just formatted differently so that a number with a specific format can appear as a date, time, or any other format you can have.
Also, if you really are using this IF construct, you are better of simply using the comparator:
=K4<="31/03/2014"*1
I had the same problem and found that excel was not recognizing one of my 2 columns as a date. (Try changing the date format to 14-Mar-12 to see if this is the case for you)

Using MIN function in excel when using mm:ss.00 fields and ignoring 00:00.00

Does anyone know how I can get excel to look at the following fields, all formatted in mm:ss.00 and return the lowest time. I am using this to calculate PB's - personal best times - in a sports club race sheet.
The formula I am using is
=MIN(J5,(U5),(AE5),(AO5),(AY5),(BI5),(BS5),(CC5),(CM5),(CW5),(DG5),(DQ5),(EA5),(EK5),(EU5))
The problem I have at the moment is that it is including 00:00.00 values in the cells and returning a MIN value of 00:00.00.
Any suggestions would be welcomed.
many thanks
Nigel
Use the following:
=SMALL((J5,U5,AE5,AO5,...),COUNTIF((J5,U5,AE5,AO5,...),0)+1)
COUNTIF counts the amounts of 0 (you maybe need to adjust this value based on your formatting, but it should work). SMALL returns the n-smallest number of the given matrix, with n being the counted value + 1.
Therefore if no 0 is in the matrix, you get the 1st-smallest (aka the smallest), with one 0 you get the 2nd-smallest and so on. Maybe you need to add a check if every value is 0, if that could happen, as in that case SMALL would try to retrieve the value on position list_size+1 of the list, which of course isn't present.

Resources