Reputation: 121
I have created a Powershell/XAML app, that on button press makes a RESTAPI call, parses the JSON response into fields in the app front end. All fine so far.
These fields will be populated with a string representing a time, so "1800" or "2000" etc.
The user can then change this from 1800 to 1900 for example.
This is all fine, and in the background the app will use 1900 to update a setting to be used in a POST back.
However there are other settings that are offset by 90 mins of the time above. I don't want the user to have update each one, which is why I am trying to programmatically.
But try as I might, I cannot take a string of 1800, add 90 mins to it and make the value 1930 (not 1890).
Upvotes: 2
Views: 558
Reputation: 5046
When I read this question I wanted to solve it with minimal string manipulation, leaning on time related objects and methods instead. datetime
was the first object I thought of, but it expects a date (year, month, day). Things actually simplify if we use timespan
. Its static method, ParseExact
, can parse the string directly.
$offsetTimeSpan = [timespan]::FromMinutes(90)
$timeField = '830'
$timeStr = $timeField.PadLeft(4, '0')
$timeSpan = [timespan]::ParseExact($timeStr, 'hhmm', [CultureInfo]::InvariantCulture)
$offsetTime = $timeSpan.Add($offsetTimeSpan)
$offsetTime.ToString('hhmm')
$timeField
is used to represent the time you get from the RESTAPI. PadLeft
is only needed if it's possible for a leading 0 to be missing. ParseExact
does the heavy lifting of converting the string to a time type. Because timespan
doesn't have an AddMinutes
member, we use the Add
method passing in a timespan
of 90 minutes, $offsetTimeSpan
.
You don't mention anything about overflowing past midnight. You can test for overflow using $offsetTime.Days
, if any special processing is required.
Upvotes: 0
Reputation: 439477
Using [timespan]
instances is another option:
$time = '1800'
([timespan] ($time -replace '(?<=^..)', ':') + '01:30').ToString('hhmm') #->'1930'
$time -replace '(?<=^..)', ':'
uses the regex-based -replace
operator to insert :
after the first two characters - see this regex101.com page for an explanation of the regex and the ability to experiment with it.
Due to expressing the results only in terms of hours and minutes, the calculation wraps around at midnight, so that adding '05:30'
, for instance, would yield '0030'
The RHS operand needn't be cast to [timespan]
directly, because the data type of the LHS - with its explicit [timespan]
cast - implicitly converts the RHS to [timespan]
too, with '01:30'
representing 1
hour and 30
minutes, i.e. 90
minutes.
If you want to define the duration to add in terms of 90
minutes, use the following instead (there are analogous static methods for other units, such as ::FromSeconds()
:
[timespan]::FromMinutes(90)
Alternatively, you can cast a number to [timespan]
, which is interpreted as ticks, which are 100-nanosecond units; there are 1e9
(10 to the power of 9) nanoseconds in a second, and therefore 1e7
100-nanosecond units in a second. Thus, multiplying with 1e7
gives you seconds, and multiplying that with 60
minutes.
# 90 minutes expressed as ticks
[timespan] 90 * (60 * 1e7)
Upvotes: 0
Reputation: 8355
You could parse the input as a DateTime
object (ignoring the date part) and then use the AddMinutes
method.
$input = '1800'
$hour = $input.Substring(0,2)
$minute = $input.Substring(2,2)
$dateInputStr = "0001-01-01,${hour}:${minute}:00"
[datetime]$dateInput = ([datetime]$dateInputStr)
$dateInput = $dateInput.AddMinutes(90)
$dateInput.ToString("HHmm")
Upvotes: 1