I want to cancel the lock when the dates match. I have LockoutEndDateUtc field at database with DateTime.Now.AddMinutes(5)) - value. So tell me the correct syntax for writing this condition please.
if (DateTime.Now == user.LockoutEndDateUtc) { } ?
A few things:
DateTime.Now returns the local time. You should use DateTime.UtcNow instead.
It is nearly impossible to exactly match the current time, because typically these values are tracked with up to 7 decimal places. Instead, you should use >, <, >= or <=.
I'm assuming a few things not stated in your question, but if you meant to lock out the user for 5 minutes, then probably you meant to set the database value with:
user.LockoutEndDateUtc = DateTime.UtcNow.AddMinutes(5);
and probably you should compare it with:
if (DateTime.UtcNow >= user.LockoutEndDateUtc)
Related
The question is simple: Why does this give the wrong answer (0)
IIf(Date()>=#3/16/2018#>=Date()-30,1,0)
While this gives the correct answer (1)
IIf(Date()>=#3/16/2018# AND #3/16/2018#>=Date()-30,1,0)
More specifically, what is Access doing in the first case?
This situation is made even more curious because, when I execute this code, I get an unexpected answer (1)
IIf(Date()<=#3/16/2018#<=Date()-30,1,0)
You can't compound comparisons in Access!
Using your last example, Access first executes the first comparison:
Date()<=#3/16/2018#
That might result in True or False. Let's say it's True
Then, Access evaluates the second comparison:
True <= Date() - 30
(This is since they're processed from left to right, and the first one is true).
This doesn't make much sense, but Access can cast a boolean to a number (-1 = True, 0 = False), and a date too (for example, today = 43186, since dates are defined as the number of days elapsed since 1899-12-30).
That means the second comparison results in:
-1 <= 43186 - 30
And that's certainly true. You also see that if the first comparison is false, the second one will be true nonetheless. Your comparison will pretty much always return true.
Can anyone explain the following results:
?DateAdd("s", 54, 0) = #12:00:54 AM#
True
?DateAdd("s", 55, 0) = #12:00:55 AM#
False
?DateAdd("s", 56, 0) = #12:00:56 AM#
True
UPDATE: Ross Presser's answer provides the what: the difference has to do with the fact that binary fractions cannot always represent decimal fractions. But WHY is the floating point offset different when both expressions evaluate to the same data type?
?TypeName(DateAdd("s", 55, 0))
Date
?TypeName(#12:00:55 AM#)
Date
?VarType(DateAdd("s", 55, 0)) = VarType(#12:00:55 AM#)
True
When I've encountered this sort of floating point artifact in the past, it's usually been because the result was actually two different types, at least at some point during the evaluation. That does not seem to be the case here. I'm still confused.
UPDATE 2: Ross's updated answer provided additional insight into the problem. I've made progress in tracking this down. Each answer seems to raise new questions. It appears that both DateAdd and the date literal are using double precision, but for some reason DateAdd is rounding to 18 decimal places (or perhaps truncating at 19 and not rounding at all):
?CDbl(#12:00:55 AM#) - CDbl(55/86400)
0
?CDbl(DateAdd("s", 55, 0)) - CDbl(55/86400)
-1.0842021724855E-19
?0.000636574074074074 - 0.0006365740740740741
-1.0842021724855E-19
Any ideas why this might be the case?
Date in VBA is expressed as an integer number of days plus a floating point fraction representing the time. Since the time is a float (or perhaps a double), it cannot exactly express every second with perfect precision. 55 seconds is 55/86400, or 0.00063657407 of a day. This is probably not precisely representable in a float.
For more insight, try subtracting the Dateadd value from the literal value, and converting to float.
EDIT: Here's the insight I was talking about:
? cdbl(dateadd("s",55,0)) - cdbl(#12:00:55 AM#)
-1.0842021724855E-19
The parsing algorithm that takes the time literal to a Date structure is apparently doing something different than the dateadd function does, leading to an error in the 19th decimal place. My guess would be that one or the other of these is using Single where it should be using Double. You can call this a bug and report it to Microsoft, I suppose.
EDIT 2: A google search turned up this link where people are talking about the floating point reality beneath VBA's date type. They gave a different example, where the error is in the 17th place instead of the 19th:
? DateAdd("h",2,#8:00#) - #10:00#
-5.55111512312578E-17
And there's also this gentleman who wrote some VBA code to do DateAdd's job more accurately. (The site on that page presents the code in a badly formatted code block that destroys all the newlines, but the code is downloadable.)
I'm trying to write a function of this form:
Function cont(requestdate As Date)
cont = requestdate
End Function
Unfortunately, when I enter =cont(12/12/2012) into a cell, I do not get my date back. I get a very small number, which I think equals 12 divided by 12 divided by 2012. How can I get this to give me back the date? I do not want the user to have to enter =cont("12/12/2012").
I've attempted to google for an answer, unfortunately, I have not found anything helpful. Please let me know if my vocabulary is correct.
Let's say my user pulled a report with 3 columns, a, b and c. a has beginning of quarter balances, b has end of quarter balances and c has a first and last name. I want my user to put in column d: =cont(a1,b1,c1,12/12/2012) and make it create something like:
BOQ IS 1200, EOQ IS 1300, NAME IS EDDARD STARK, DATE IS 12/12/2012
So we could load this into a database. I apologize for the lack of info the first time around. To be honest, this function wouldn't save me a ton of time. I'm just trying to learn VBA, and thought this would be a good exercise... Then I got stuck.
Hard to tell what you are really trying to accomplish.
Function cont(requestdate As String) As String
cont = Format(Replace(requestdate, ".", "/"), "'mm_dd_YYYY")
End Function
This code will take a string that Excel does not recognize as a number e.g. 12.12.12 and formats it (about the only useful thing I can think of for this UDF) and return it as a string (that is not a number or date) to a cell that is formatted as text.
You can get as fancy as you like in processing the string entered and formatting the string returned - just that BOTH can never be a number or a date (or anything else Excel recognizes.)
There is no way to do exactly what you're trying to do. I will try to explain why.
You might think that because your function requires a Date argument, that this somehow forces or should force that 12/12/2012 to be treated as a Date. And it is treated as a Date — but only after it's evaluated (only if the evaluated expression cannot be interpreted as a Date, then you will get an error).
Why does Excel evaluate this before the function receives it?
Without requiring string qualifiers, how could the application possibly know what type of data you intended, or whether you intended for that to be evaluated? It could not possibly know, so there would be chaos.
Perhaps this is best illustrated by example. Using your function:
=Cont(1/1/0000) should raise an error.
Or consider a very simple formula:
=1/2
Should this formula return .5 (double) or January 2 (date) or should it return "1/2" (string literal)? Ultimately, it has to do one of these, and do that one thing consistently, and the one thing that Excel will do in this case is to evaluate the expression.
TL;DR
Your problem is that unqualified expression will be evaluated before being passed, and this is done to avoid confusion or ambiguity (per examples).
Here is my method for allowing quick date entry into a User Defined Function without wrapping the date in quotes:
Function cont(requestdate As Double) As Date
cont = CDate((Mid(Application.Caller.Formula, 7, 10)))
End Function
The UDF call lines up with the OP's initial request:
=cont(12/12/2012)
I believe that this method would adapt just fine for the OP's more complex ask, but suggest moving the date to the beginning of the call:
=cont(12/12/2012,a1,b1,c1)
I fully expect that this method can be optimized for both speed and flexibility. Working on a project now that might require me to further dig into the speed piece, but it suits my needs in the meantime. Will update if anything useful turns up.
Brief Explanation
Application.Caller returns a Range containing the cell that called the UDF. (See Caveat #2)
Mid returns part of a string (the formula from the range that called the UDF in this case) starting at the specified character count (7) of the specified length (10).
CDate may not actually be necessary, but forces the value into date format if possible.
Caveats
This does require use of the full dd/mm/yyyy (1/1/2012 would fail) but pleasantly still works with my preferred yyyy/mm/dd format as well as covering some other delimiters. dd-mm-yyyy or dd+mm+yyyy would work, but dd.mm.yyyy will not because excel does not recognize it as a valid number.
Additional work would be necessary for this to function as part of a multi-cell array formula because Application.Caller returns a range containing all of the associated cells in that case.
There is no error handling, and =cont(123) or =cont(derp) (basically anything not dd/mm/yyy) will naturally fail.
Disclaimers
A quick note to the folks who are questioning the wisdom of a UDF here: I've got a big grid of items and their associated tasks. With no arguments, my UDF calculates due dates based on a number of item and task parameters. When the optional date is included, the UDF returns a delta between the actual date and what was calculated. I use this delta to monitor and calibrate my calculated due dates.
All of this can absolutely be performed without the UDF, but bulk entry would be considerably more challenging to say the least.
Removing the need for quotes sets my data entry up such that loading =cont( into the clipboard allows my left hand to F2/ctrl-v/tab while my right hand furiously enters dates on the numpad without need to frequently (and awkwardly) shift left-hand position for a shift+'.
I am trying to calculate create a time remaining calculator in VB.NET and it won't let me and I can't seem to figure out why. Here is my code
Dim PrefendinedDateTime As DateTime = "3:00:00"
Dim TimeNow As DateTime = DateTime.Now
Dim ElapsedTime As TimeSpan = (TimeNow - frmStartDateTime)
Dim TimeRemaining As TimeSpan = PrefendinedDateTime - New DateTime(ElapsedTime.Ticks)
txtTimeRemaining.Text = New DateTime(TimeRemaining.Ticks).ToString("HH:mm:ss")
I get this error message:
Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks.
Parameter name: ticks
Not quite sure what this means
You cannot cast a timespan to a date, because those are different ticks. What you need is this:
txtTimeRemaining.Text = TimeRemaining.ToString("g")
or this:
txtTimeRemaining.Text = TimeRemaining.ToString("hh\:mm\:ss")
Notice how format string is different for TimeSpan, compared to formatting a date time, for example, and that : now requires escaping. This is explained in detail in below link #2.
References:
Standard TimeSpan Format Strings # MSDN
Custom TimeSpan Format Strings # MSDN
Let's stop here for a second, while I try to explain why it did not work for you. Forget about ticks, think in seconds, because it's a measurable interval, that's easy to get a grasp on. Suppose you time interval is a second. Now you are trying to create a date, passing one second into it. What do you expect to get? 1 second AD, i.e. 1st year, 1st month etc.? Fair enough.
Suppose now you have an interval of minus 1 second (yes, intervals can be negative). You would think it's 1 second BC, right? Unfortunately, negative dates in .NET are not allowed.
As a general rule of thumb, intervals of time (represented in .NET by a TimeSpan), and points in time (represented by a DateTime) should be treated separately, because they are logically different entities. There is one-way relation though, i.e. two dates can represent a TimeSpan. However, a TimeSpan does not represent two dates. In fact, no matter how many TimeSpans you have, you will never be able to relate them to any point in time.
This is an ugly one. I wish I wasn't having to ask this question, but the project is already built such that we are handling heavy loads of validations in the database. Essentially, I'm trying to build a function that will take two stacks of data, weave them together with an unknown batch of operations or comparators, and produce a long string.
Yes, that was phrased very poorly, so I'm going to give an example. I have a form that can have multiple iterations of itself. For some reason, the system wants to know if the entered start date on any of these forms is equal to the entered end date on any of these forms. Unfortunately, due to the way the system is designed, everything is stored as a string, so I have to format it as a date first, before I can compare. Below is pseudo code, so please don't correct me on my syntax
Input data:
'logFormValidation("to_date(#) == to_date(^)"
, formname.control1name, formname.control2name)'
Now, as I mentioned, there are multiple iterations of this form, and I need to loop build a fully recursive comparison (note: it may not always be typical boolean comparisons, it could be internally called functions as well, so .In or anything like that won't work.) In the end, I need to get it into a format like below so the validation parser can read it.
OR(to_date(formname.control1name.1) == to_date(formname.control2name.1)
,to_date(formname.control1name.2) == to_date(formname.control2name.1)
,to_date(formname.control1name.3) == to_date(formname.control2name.1)
,to_date(formname.control1name.1) == to_date(formname.control2name.2)
:
:
,to_date(formname.control1name.n) == to_date(formname.control2name.n))
Yeah, it's ugly...but given the way our validation parser works, I don't have much of a choice. Any input on how this might be accomplished? I'm hoping for something more efficient than a double recursive loop, but don't have any ideas beyond that
Okay, seeing as my question is apparently terribly unclear, I'm going to add some more info. I don't know what comparison I will be performing on the items, I'm just trying to reformat the data into something useable for ANY given function. If I were to do this outside the database, it'd look something like this. Note: Pseudocode. '#' is the place marker in a function for vals1, '^' is a place marker for vals2.
function dynamicRecursiveValidation(string functionStr, strArray vals1, strArray vals2){
string finalFunction = "OR("
foreach(i in vals1){
foreach(j in vals2){
finalFunction += functionStr.replace('#', i).replace('^', j) + ",";
}
}
finalFunction.substring(0, finalFunction.length - 1); //to remove last comma
finalFunction += ")";
return finalFunction;
}
That is all I'm trying to accomplish. Take any given comparator and two arrays, and create a string that contains every possible combination. Given the substitution characters I listed above, below is a list of possible added operations
# > ^
to_date(#) == to_date(^)
someFunction(#, ^)
# * 2 - 3 <= ^ / 4
All I'm trying to do is produce the string that I will later execute, and I'm trying to do it without having to kill the server in a recursive loop
I don't have a solution code for this but you can algorithmically do the following
Create a temp table (start_date, end_date, formid) and populate it with every date from any existing form
Get the start_date from the form and simply:
SELECT end_date, form_id FROM temp_table WHERE end_date = <start date to check>
For the reverse
SELECT start_date, form_id FROM temp_table WHERE start_date = <end date to check>
If the database is available why not let it do all the heavy lifting.
I ended up performing a cross product of the data, and looping through the results. It wasn't the sort of solution I really wanted, but it worked.