StackExchangeGuy
StackExchangeGuy

Reputation: 789

Inserting time (hours and minutes) into a datetime object

I have a script that accepts a start date and a start time as separate parameters. If no start date is provided, I assume they want the date to be today and if no start time, I want to assume it should be "whatever time it is right now".

I don't want to constrain (much) the way that the user inputs the date or time. For example, I want them to be able to enter do -StartDate (Get-Date) so I need to be able to accept that object (which includes the time), then, because no StartTime was entered, I need to replace whatever time is on the object, with the current time.

I thought about saying that if there is a time in the $StartDate variable, then use it, but if they do -StartDate 07/10/2018, then I still need to add the time anyway.

After some searching, this is what I tried and the result:

PS C:\> Get-Date

Tuesday, July 10, 2018 3:15:58 PM

PS C:\> $StartDate = (Get-Date).AddDays(1)
>> $StartTime = [DateTime]::ParseExact((Get-Date -Format HH:mm).ToString(),"HH:mm",[System.Globalization.CultureInfo]::InvariantCulture)
>> [datetime]$StartDate = $StartDate
>> $StartDate = $StartDate.Add([System.Timespan]::Parse($StartTime))
>> $StartDate

Exception calling "Parse" with "1" argument(s): "String was not recognized as a valid TimeSpan."
At line:4 char:1
+ $StartDate = $StartDate.Add([System.Timespan]::Parse($StartTime))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : FormatException

Wednesday, July 11, 2018 3:16:10 PM

So, I think the question is, "how do I take a particular time and insert it into a datetime object?" Or maybe there is a better way to achieve my goal, that's cool too.

Thanks.

Upvotes: 0

Views: 2987

Answers (3)

StackExchangeGuy
StackExchangeGuy

Reputation: 789

Using a suggestion from Ansgar Wiechers, this modified function works the way I want it to:

function foo {
    Param(
        [Parameter(Mandatory = $true)]
        [DateTime]$StartDate,

        [String]$StartTime
    )

    If (-NOT($StartTime)) {
        $currentTime = Get-Date

        $StartDate.Date.Add((New-Timespan -Hour $currentTime.Hour -Minute $currentTime.Minute))
    }
    Else {
       $StartDate.Date.Add([Timespan]::Parse($StartTime))
    }
}

# Tomorrow, at the current time
foo -StartDate (Get-Date).AddDays(1)

# Tomorrow at 13:30
foo -StartDate (Get-Date).AddDays(1) -StartTime '13:30'

# July 5, 2018 at the current time
foo -StartDate "07-05-2018"

Upvotes: 0

Theo
Theo

Reputation: 61068

You can Zero-out the time part of a DateTime object using $StartDate = (Get-Date).Date. To get just the time part of a DateTime object (returned as a TimeSpan object) you can use (Get-Date).TimeOfDay

To test wether the user gave you a ful date including time or not (and if not add the current time to it) this may do the trick for you:

if ($StartDate.TimeOfDay -eq [TimeSpan]::Zero) {
    $StartDate = $StartDate.AddSeconds($StartTime.TotalSeconds)
}

$StartDate

Upvotes: 0

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200273

You can always construct a date via the respective parameters of Get-Date, e.g.

Get-Date -Hour 8 -Minute 30

will give you today's date with the time 8:30.

You can also take just the date portion of a DateTime value like this:

$today = (Get-Date).Date

add a couple days (or just one)

$tomorrow = $today.AddDays(1)

and then add the desired timespan:

$time = New-Timespan -Hour 8 -Minute 30
$tomorrow.Add($time)

which can also be daisy-chained:

$time = New-Timespan -Hour 8 -Minute 30
(Get-Date).Date.AddDays(1).Add($time)

In your particular scenario you would take the start date as a DateTime value, strip off the time, then add the timespan e.g. from a string parameter:

Param(
    [Parameter(Mandatory=$true)]
    [DateTime]$StartDate,
    [Parameter(Mandatory=$true)]
    [String]$StartTime
)

$StartDate.Date.Add([Timespan]::Parse($StartTime))

and invoke it like this:

foo -StartDate (Get-Date) -StartTime '8:30'

or you'd use different parameters for hour and minute:

Param(
    [Parameter(Mandatory=$true)]
    [DateTime]$StartDate,
    [Parameter(Mandatory=$true)]
    [ValidateRange(0,23)]
    [Integer]$Hour,
    [Parameter(Mandatory=$false)]
    [ValidateRange(0,59)]
    [Integer]$Minute = 0
)

$StartDate.Date.Add((New-Timespan -Hour $Hour -Minute $Minute))

and invoke the script/function like this:

foo -StartDate (Get-Date) -Hour 8 -Minute 30

Upvotes: 3

Related Questions