2

I am trying to test Time out after 30 seconds.

Sample code:

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Seconds 30
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$stopwatch.Start()
$timeout.Seconds
$stopwatch.elapsed.Seconds
do{

    if($a -eq "n"){
        Write-Host "This block will never run"
        break
    }

    if($stopwatch.elapsed.Seconds -lt $timeout.Seconds){
        Write-Host "Testing this block: Time OUT!!"
        break
    }

}while($a -eq $b)

$stopwatch.Stop()

But the if block if($stopwatch.elapsed.Seconds -lt $timeout.Seconds) is true even $stopwatch.elapsed.Seconds value is 0 and $timeout.Seconds value is 30 in the loop and complete the code in few milliseconds and not taking 30 seconds to print the Time out statement.

Could anyone please give me pointer to resolve this issue.

0

3 Answers 3

3

A couple of things:

  • You don't need these two lines: $timeout.Seconds and $stopwatch.elapsed.Seconds above the loop
  • Your while condition should be while($a -ne $b)
  • The test inside the loop should read if($stopwatch.elapsed.Seconds -ge $timeout.Seconds)

Try

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Seconds 30
$stopwatch = [System.Diagnostics.Stopwatch]::new()
$stopwatch.Start()
do {
    if($stopwatch.Elapsed.Seconds -ge $timeout.Seconds){
        Write-Host "Testing this block: Time OUT!!"
        break
    }
    # no timeout, so proceed with what needs to be done here
    # . . .
} while($a -ne $b)  # loop forever unless you set $a equal to $b in the loop somewhere

$stopwatch.Stop()
Sign up to request clarification or add additional context in comments.

4 Comments

Hi Theo, Thank you for above suggestion. I am trying to run Write-Host "Testing this block: Time OUT!!" after 30 seconds. could you please suggest the if condition using $stopwatch.Elapsed.Seconds -ge $timeout.Seconds in it.
@shivam Well.. if you run this, that code block wil run as soon as the elapsed time of the stopwatch (in seconds) is greater or equel to the $timeout TimeSpan you have set to a certain number of seconds. In fact, you don't even need that $timeout variable and you can simply hardcode to if($stopwatch.Elapsed.Seconds -ge 30). When a new StopWatch is started, the initial .Seconds wil be 0 and will increase over time.
Yes @Theo agreed, however I will parametrized the timeout value so that I can use as per the need that is reason i am trying with above condition
Theo, I originally thought that $stopwatch.Elapsed.Seconds -ge $timeout.Seconds is fine, because the timeout is less than 1 minute, but then I realized that $stopwatch.Elapsed.Seconds can be a problem - at least hypothetically: If, before the test, more than 1 minute has passed, you need to use $stopwatch.Elapsed.TotalSeconds for the test to work as intended.
3

Theo's helpful answer addresses incidental logic problems with your approach and offers a solution that probably will work, but isn't fully robust: If the activity in your loop exceeds 1 minute before the timeout condition is tested, the test won't work as intended (even with the logic problems fixed).

You have two options:

  • Use .TotalSeconds instead of .Seconds, for the reasons explained below.

  • More simply, taking advantage of the fact that [timespan] instances are directly comparable (see below), you can use:

    if ($stopwatch.elapsed -gt $timeout) { # ... 
    

As zett42 points out, [timespan] instances are directly comparable, due to implementing the .NET System.IComparable interface (as well as its generic counterpart); e.g.:

   # -> $true - a timespan representing a 61-second duration 
   #            is greater than one representing a 60-second (1-minute) duration.
   [timespan]::FromSeconds(61) -gt [timespan] '00:01:00'

Therefore, as shown in the top section, you can simply directly compare $stopwatch.elapsed and $timeout - both of which are [timespan] instances.

The .Seconds property of a [timespan] instance is only the seconds component, potentially alongside larger units, such as minutes (.Minutes) and hours (.Hours)

You need the .TotalSeconds property to get the total amount of seconds (analogously, there are also .TotalDays, .TotalHours, and .TotalMinutes properties).

Also note that .Seconds is always a whole number ([int]), whereas .TotalSeconds can be a fractional value ([double]).

To illustrate the difference:

PS> [timespan] '00:01:05' | # 1 minute and 5 seconds 
      Select-Object Seconds, TotalSeconds

Seconds TotalSeconds
------- ------------
      5           65

Comments

0

@sivam The issue is-

  • You're not applying the proper properties of the timespan command if it goes beyond 59 seconds then at 60 seconds it will consider it 1 minute.
  • Update the condition inside the loop if($stopwatch.elapsed.Seconds -lt $timeout.Seconds)

Try

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Minutes 1
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$stopwatch.Start()
$timeout.Minutes
$stopwatch.elapsed.Minutes
do{
    if($a -eq "n"){
        Write-Host "This block will never run"
        break
    }
    if($stopwatch.elapsed.Minutes -ge $timeout.Minutes){
        Write-Host "Time OUT!!"
        break
    }
}while($a -ne $b)
$stopwatch.Stop()

2 Comments

Using .Minutes suffers the same conceptual flaw as using .Seconds: you're only checking the minute component of the timespan, not the total amount of minutes. While your command is less likely to malfunction, it still can, namely if the more than 1 hour has elapsed before the $stopwatch.elapsed.Minutes -ge $timeout.Minutes test. For instance, ([timespan] '01:01').Minutes is 1, even though the timespan represents 61 seconds. /cc @shivam
Also, will consider it 1 minute is a bit confusing, given that a [timespan] instance represents a duration that can be expressed in any unit, on demand - you're free to ask for the duration of a 1-minute timespan in seconds (.TotalSeconds) or minutes (.TotalMinutes), for instance.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.