A week ago I wrote this script which starts up when you log in and then greets you according to the time of the day. This morning it suddenly suddenly said: "Invalid time" (it would do that if all other elseif options wouldn't match the time). This used to work until today.
Here's my code:
Set objShell = CreateObject("WScript.Shell")
ctime = Time()
usr = objShell.ExpandEnvironmentStrings("%username%")
if ctime > "06:00:00" and ctime < "12:00:00" then
objShell.Popup "Good Morning, " & usr, 5, "", 4096
elseif ctime > "12:00:00" and ctime < "18:00:00" then
objShell.Popup "Good Afternoon, " & usr, 5, "", 4096
elseif ctime > "18:00:00" and ctime < "23:59:59" then
objShell.Popup "Good evening, " & usr, 5, "", 4096
elseif ctime > "00:00:00" and ctime < "06:00:00" then
objShell.Popup "Good night, " & usr, 5, "", 4096
else
objShell.Popup "Invalid time", 5, "", 4096
end if
EDIT: It seems like it works again, now that it's 10 o' clock but for some reason it didn't work before 10, I guess there is still an error in my code?
You are comparing values of time and string data subtype. The Comparison Operators (VBScript) reference is quite bit unclear about it (or about automatic data subtype conversion); I guess conversion time to string with an alternative leading zero manipulation, for instance #09:10:12# time converts to either "9:10:12" or " 9:10:12" string. So force time comparison using time literals by enclosing them in number signs (#), for instance #06:00:00# instead of "06:00:00".
However, there are still gaps in your logic: for instance #06:00:00# or #12:00:00# or #18:00:00# time does not match any if nor elseif condition and will give Invalid time output.
Hence, instead of
if ctime > "06:00:00" and ctime < "12:00:00" then
use either
if ctime >= #06:00:00# and ctime < #12:00:00# then
or
if ctime > #06:00:00# and ctime <= #12:00:00# then
and improve all elseif analogously.
Related
This question already has answers here:
How to measure code execution time in VBScript or JavaScript?
(7 answers)
Closed 2 years ago.
I have a Vbscript which outputs the time taken for my anti-virus to update the signature version on a daily basis at 05:00 AM, before performing a scan. This is the script
Function TimeSpan(dt1, dt2)
If (isDate(dt1) And IsDate(dt2)) = false Then
TimeSpan = "00:00:00"
Exit Function
End If
seconds = Abs(DateDiff("S", dt1, dt2))
minutes = seconds \ 60
hours = minutes \ 60
minutes = minutes mod 60
seconds = seconds mod 60
if len(hours) = 1 then hours = "0" & hours
TimeSpan = hours & ":" & _
RIGHT("00" & minutes, 2) & ":" & _
RIGHT("00" & seconds, 2)
End Function
d1 = LAST_UPDATE
d2 = 22 Jul 20 05:00:00AM
d1 [ LAST_UPDATE ] is the time the update is completed, so what I need is the starting time. The script runs accurately as long as I incorporate the date and time in ' d2 ' [ as shown in the script ]. This means that to output the result on a daily basis, I have to open the vbscript and change the date to current date [ the time remains constant at 05:00:00 AM ]
The output result is given to me after 10 minutes.
I have tried using ' Now ()' but this output includes the time taken from the time the update is completed and the 10 minutes [ that has lapsed ] till the result is provided. This doesnot serve the purpose of this script.
What I am trying to get at is, is there a way which can be incorporated in the script itself,[ with another fuction or so ] which will change the date [ to tomorrow ] and the time [ the time remains constant at 05:00:00 AM ] incrementally after every 24 hours at 12:00:00 AM in the script itself keepiing it ready for the next day's operation without any user action of changing the date manually
I have tried all ways possible to resolve this but have failed. My efforts always culminate in ' Now() ' and the entire excercise is wasted.
Any help will be appreciated.This is the script
Rajdeep
If you simply want to measure the time it takes for the anti-virus update to run, you can use the Timer function like this:
Dim sngStart
Dim sngTimeSpan
sngStart = Timer
' Do work here
sngTimeSpan = Timer - sngStart
sngTimeSpan is a value in seconds.
You can do the same with the Now function:
Dim dStart
dStart = Now
' Do work here
seconds = Abs(DateDiff("S", dStart, Now))
Essentially you are calling Timer or Now twice and calculating the difference between the two, eliminating the need for the d2 variable.
Here's a complete example using a MsgBox to simulate some task being performed:
Dim sngStart
Dim sngEnd
Dim sngSecondsElapsed
Dim iSecondsElapsed
Dim dStart
' Grab system Timer and current time
sngStart = Timer
dStart = Now
' Simulating a delay here by displaying a message box
MsgBox "Click OK after a few moments"
' Calculate seconds elapsed
sngSecondsElapsed = Timer - sngStart
iSecondsElapsed = Abs(DateDiff("S", dStart, Now))
MsgBox "Seconds Elapsed:" & vbCrLf & "Timer method: " & FormatNumber(sngSecondsElapsed, 2) & vbCrLf & "Now method: " & iSecondsElapsed
How limit textbox input to numbers in the range from 1900 to current date?
Private Sub txtYear_Change()
If Not IsNumeric(txtYear.Text) Then
txtYear.Text = ""
ElseIf txtYear.Text < 1900 Or txtYear.Text > Year(Date) Then
txtYear.Text = ""
End If
Exit Sub
You need to place that code in your txtYear_Validate() event instead of the change event. Change will get triggered with each keystroke, so it will almost always immediately fail. Do not validate the entry until it's done, in the validate event.
As explained in Bill's answer, you should use the Validate event.
I just would like to add that your code still has a flaw, that is, it will allow users to enter decimal numbers (e.g., 1900.10). In order to avoid that, you can add another condition:
Private Sub txtYear_Validate(Cancel As Boolean)
If Not IsNumeric(txtYear.Text) Then
txtYear.Text = ""
ElseIf txtYear.Text < 1900 Or txtYear.Text > Year(Date) Then
txtYear.Text = ""
ElseIf Fix(txtYear.Text) <> txtYear.Text Then ' Choose one:
txtYear.Text = Fix(txtYear.Text) ' - Replace it with the integer part.
'txtYear.Text = "" ' - Clear the text.
End If
End Sub
This question already has answers here:
Find time with millisecond using VBScript
(3 answers)
Closed 5 years ago.
My VBScript has a log file which logs information with current date and time using FormatDateTime Function.
I like to format time up to milliseconds and also in the following format:
MM/DD/YY hh:mm:ss:mss AM/PM
But, unfortunately FormatDateTime doesn't let to format time in this way.
After searching for this, I found this answer and it is about how to use Timer function, So I can't log time to log files using it again and again.
As W3schools states,
The Timer function returns the number of seconds since 12:00 AM.
But I want my log file to log time in above format even before 12:00 AM, So using Timer Function isn't the best option for this.
Please let me know a way to do this specially in log files correctly.
The vbscript function Now() will return the current system date and time in this format - 5/2/2017 9:45:34 AM, however if you need to add milliseconds you can use Timer - Timer math from here
'capture the date and timer together so if the date changes while
'the other code runs the values you are using don't change
t = Timer
dateStr = Date()
temp = Int(t)
milliseconds = Int((t-temp) * 1000)
seconds = temp mod 60
temp = Int(temp/60)
minutes = temp mod 60
hours = Int(temp/60)
label = "AM"
If hours > 12 Then
label = "PM"
hours = hours-12
End If
'format it and add the date
strTime = LeftPad(hours, "0", 2) & ":"
strTime = strTime & LeftPad(minutes, "0", 2) & ":"
strTime = strTime & LeftPad(seconds, "0", 2) & "."
strTime = strTime & LeftPad(milliseconds, "0", 3)
WScript.Echo dateStr & " " & strTime & " " & label
'this function adds characters to a string to meet the desired length
Function LeftPad(str, addThis, howMany)
LeftPad = String(howMany - Len(str), addThis) & str
End Function
Another way to do the same thing, with a bit less code. In this code, we're splitting Now() into an array so we can use it for everything except the milliseconds.:
WScript.Echo PrintTimeStamp()
Function PrintTimeStamp()
nowParts = SPLIT(Now(), " ")
timePart = nowParts(1)
t = Timer
milliseconds = Int((t-Int(t)) * 1000)
PrintTimeStamp = nowParts(0) & " " & LeftPad(nowParts(1), "0", 8) & "." & LeftPad(milliseconds, "0", 3) & " " & nowParts(2)
End Function
Function LeftPad(str, addThis, howMany)
LeftPad = String(howMany - Len(str), addThis) & str
End Function
I'm looking to print out the time 6:00am without the seconds. Using TimeValue it includes the seconds. Is there away to do this without including the seconds?
CurrentTime = TimeValue("6:00 am")
Use built-in FormatDateTime with vbShortTime :
CurrentTime = FormatDateTime("6:00:31 am", vbShortTime)
Use a RegExp to zap the offending seconds from the string representation of the date:
>> Set r = New RegExp
>> r.Pattern = ":\d\d "
>> dtCurrentTime = TimeValue("6:00 PM")
>> sCurrentTime = CStr(dtCurrentTime)
>> sCurrentTime = r.Replace(sCurrentTime, " ")
>> WScript.Echo qq(sCurrentTime)
>>
"6:00 PM"
dtCurrentTime = TimeValue("6:00 PM")
sCurrentTime = CStr(dtCurrentTime)
sCurrentTime=Replace (sCurrentTime,":00:00 PM",":00 PM")
MsgBox sCurrentTime
I had the same problem. But I use Mid, Left & Right functions to solve it.
ThisTime = TimeValue(YourTime)
TimeSpace = InStr(1,ThisTime," ")
ThisShortTime = Left(ThisTime,TimeSpace-4) & Right(ThisTime,3)
InStr looks for the space within the time.
Left picks up the left side of the time, minus the second.
Right picks up the last 3 characters of the time, eg " AM" or " PM".
DISCLAIMER: I'm still an uber-n00b with programming concepts and know just enough VBS to hurt myself, so I'm likely to slur/slaughter some of the terms/concepts/ideas that are entailed with this program I'm trying to write. You, the vastly superior programmer who has every right to flame me, have been warned.
I've been trying to write a VBScript to validate data, specifically Dates. Since my users are kind of poor with keyboards, I figured I'd make it easy by separating the entry of each part of the date (Month & Day only, I've got the Year set statically).
Previously, I was having problems with validating the numbers with only 1 "Do...Loop", as I was trying to verify if it was Numeric Input and checking at the same time if it was within the specified range (1 - 12, for the 12 months of the year).
This is what the previous code roughly looked like:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth > 0) _
And (dtFirstMonth < 13) _
And IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
This often resulted in "Data Type Mismatch" errors, so I had to split the Validation Critera to two separate "Do...Loop" statements, as you can see in the current code I have below:
Sub srTest()
Do
dtFirstMonth = InputBox("Please Enter a Numeric Month for the Starting Range", _
"Starting Range Month")
If (dtFirstMonth = vbNull) _
Or (dtFirstMonth = "") _
Or Not IsNumeric(dtFirstMonth) Then
MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
ElseIf (dtFirstMonth <> vbNull) _
And (dtFirstMonth <> "") _
And IsNumeric(dtFirstMonth) Then
Do
dtFirstMonth = Round(dtFirstMonth)
Wscript.Echo dtFirstMonth ' Infinite Loop Here (Basically, As Soon As We Get Into Loop with a Value of 1, We're Stuck)
dtFirstMonth = CInt(dtFirstMonth)
' Must Convert User Input to Integer to
' Prevent Data Mismatch Errors In
' Following "If" Statement; Besides,
' It Passed the First Test to be a
' Numeric Value in the First Place
If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
MsgBox "Please Enter a Valid Numeric Month",, "Enter Month Number"
Exit Do
' Drop Out of 2nd Level Loop to
' Enter Into 1st Level Loop
End If
Loop Until (dtFirstMonth > 0) _
And (dtFirstMonth < 13) _
And IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
If (dtFirstMonth < 1) Or (dtFirstMonth > 12) Then
dtFirstMonth = ""
End If
' dtFirstMonth Was Converted to Integer Earlier
' This is to Meet the Value that Didn't Pass
' the Nested Do & If Statement (Level 2 Do Loop)
' Sets dtFirstMonth to "Empty String" to Continue
' Looping in the Level 1 "Do...Loop" Statement;
' If Omitted, Level 1 "Do...Loop" is Satisfied,
' Thus Ending the Subroutine (Since the Value
' of dtFirstMonth is Still a Numeric Value)
End If
Loop Until IsNumeric(dtFirstMonth) _
And (dtFirstMonth <> "") _
And (dtFirstMonth <> vbNull)
Wscript.Echo dtFirstMonth
End Sub
srTest
I had to set up the 1st "Do...Loop" to check that the User Input (dtFirstMonth) was a indeed a Numeric Value and not a Null Value nor an Empty String. The Nested "Do...Loop", or 2nd "Do...Loop", statement is where I have the same Criteria plus the extra Criteria defining the desired ranges (any number between 1 and 12).
This is working perfectly for number 2-12, but when the script parses the number 1, I enter into an Infinite Loop.
I've checked to make sure that the Infinite Loop is occurring in the 2nd "Do...Loop" by replacing the entire 2nd "Do...Loop" section with "Wscript.Echo dtFirstMonth". By doing this, I get the expected results: a single Echo, not an infinite number of them (technically, I get 2, as I do have another "Wscript.Echo dtFirstMonth" string at the bottom of the Subroutine for the purpose of debugging, but either way, it's not an Infinite Loop).
I've also changed the criterion for the lower range to be like this, yet this doesn't remediate the error:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth >= 1)
I've also tried this, with no resulting success:
Do
' If...Then Statements Here
Loop Until (dtFirstMonth >= CInt(1))
In all reality, there really is no need for this segment, since I converted the User's Input to an integer anyway.
Since this was starting to get confusing, I decided to add the "Round" statement before the script passed the User's Input to the "CInt" function, hoping that it would make sure that it wasn't getting caught as a 0 value or decimal value somehow; yes, this is irrational thought on my part, but I still wanted to explore all avenues (there's also the fact that I have some users with "Fat Finger Syndrome" and some others with "Abuse The Program" mentality, so I figured I'd make sure the script accounted for decimal entries). I added the "Round" string before and after the nested "Do...Loop" and I still had the Infinite Loop issue.
This is as far as I've been able to get on this and now I'm stuck.
I realize that there are likely better ways to do Date/Time Validation in VBScript, and I'm certainly open to any new suggestions, but I'd love to solve this for the pure sake of edification.
Way too much code for a simple input of a number. Just try to keep it short and simple. Example:
Do
dtm = InputBox("Please Enter a Numeric Month for the Starting Range", _
"Starting Range Month")
Select Case True
Case isNull(dtm), (not isNumeric(dtm)), dtm = "", dtm = empty, (dtm < 1 OR dtm > 12)
' too exhaustive, but just for the sake of the example.
MsgBox "Please enter an amount between 1 and 12"
Case else
' Hey, this seems to be a valid amount!
Exit do
End Select
Loop While True
' Do something with dtm
Just showed you some creative Select Casing, this supports lazy exit, so if a value is Null, it escapes before getting evaluated where evaluating could throw an error.
The problem is with your attempt to check for null values:
(dtFirstMonth = vbNull)
The proper way to check for nulls, as demonstrated in AutomatedChaos' answer, is with the IsNull function. vbNull is actually a constant that's used with the VarType function. The value of vbNull is 1, which is why that particular value behaved differently from other entries. That's the fundamental problem, and if you replace every dtFirstMonth = vbNull with IsNull(dtFirstMonth), you won't get an infinite loop when entering 1.
Now, the actual place where your code infinitely loops is interesting. I would expect the first conditional If (dtFirstMonth = vbNull) to evalute true for an entry of "1", and you would get the message box "Please enter a valid numeric month". However, the Else condition is triggered. This is weird because normally, when you compare a string to a number, VBScript will attempt to convert the number to a string or vice versa, so if dtFirstMonth is "1", it should be equal to vbNull (which is 1). However, there appears to be a special case when you compare a string variable to an integer variable. See this example:
' vbNull = 1, built-in constant
dtFirstMonth = "1"
MsgBox (dtFirstMonth = vbNull) ' False
MsgBox ("1" = vbNull) ' True
MsgBox (dtFirstMonth = 1) ' True
MsgBox (CInt(dtFirstMonth) = vbNull) ' True
I don't know if this is a bug or just an obscure detail about VBScript's implicit conversion, but it does illustrate that implicit conversion can be unpredictable in VBScript.
As far as alternative methods go, you may be interested in the IsDate function, which returns True if the given expression can be converted into a date. It may not be ideal for your users and their keyboard skills, but it would reduce your code to:
Do
str = InputBox("Enter a date (MM/DD)")
If IsDate(str) Then
Exit Do
Else
WScript.Echo "Please enter a valid date"
End If
Loop
dt = CDate(str)
' Put your static year here; CDate will default to the current year
dtActual = DateSerial(2007, Month(dt), Day(dt))
WScript.Echo (dtActual) & " - Thanks!"
Note that IsDate should return False for the typical edge cases ("", Null, Empty, etc.), so there's no need for a separate check.
I found a simple program to generate Date and time from http://rindovincent.blogspot.com/p/vbscript-programs.html. I am pasting the same program with permission.
<html>
<body>
<center>
<script type="text/vbscript">
d=CDate("October 22, 2010")
document.write(d&"<br/>")
document.write("Current system date is:"&date&"<br/>")
document.write("Current system time is:"&time&"<br/>")
document.write(DatePart("m",Now())&"<br/>")
document.write(DateAdd("yyyy",1,"31-Jan-10") & "<br />")
document.write(MonthName(10,true)& "<br />")
fromDate="22-sep-10 00:00:00"
toDate="21-oct-10 23:59:00"
document.write(DateDiff("m",fromDate,toDate)&"<br />")
document.write(DateDiff("y",fromDate,toDate) & "<br />")
document.write(DateDiff("w",fromDate,toDate) & "<br />")
document.write(DateDiff("h",fromDate,toDate) & "<br />")
</script>
</center>
</body>
</html>