Add Time from TimeSpan Object in Powershell - powershell

This has been driving me nuts, and it's got to be something simple I'm missing.
I'm simply trying to get the total hours from a TimeSpan object and use that to add to a DateTime object.
$mytime = "1/1/2020 10:00:00"
$hours = (New-TimeSpan -Start $mytime).TotalHours
Get-Date
(Get-Date $mytime).AddHours($hours)
The result is
Wednesday, February 5, 2020 11:25:37 AM
Wednesday, February 5, 2020 11:25:37 AM
In the above, the time doesn't change! However if I just assign a value to $hours, it works fine.
$mytime = "1/1/2020 10:00:00"
$hours = 100
Get-Date
(Get-Date $mytime).AddHours($hours)
Wednesday, February 5, 2020 11:25:37 AM
Sunday, January 5, 2020 5:00:01 AM
I've tried all manner of variable assignments and casting, but no matter what I do I can't get the TotalHours value to work. Why can't I use $hours? TotalHours is supposed to be a normal double, and even if I cast it to double ([double]$hours = New-Timespan...) nothing changes.

TotalHours includes fractional hours. The value of $hours will be something like 844.1311..... The value of TotalHours is basically:
$ts = New-TimeSpan -Start $mytime
$ts.Ticks / [TimeSpan]::TicksPerHour
If you want the integer value, try:
$mytime = "1/1/2020 10:00:00"
$hours = [math]::Truncate((New-TimeSpan -Start $mytime).TotalHours)
(Get-Date $mytime).AddHours($hours)
I haven't tested it, but you might need to use Math.Floor() instead if you can potentially have $mytime in the future.
Truthfully, though, if you want the same hour of day today as another date, it's more logical to do this:
$mytime = Get-Date "1/1/2020 10:00:00"
$today = (Get-Date).Date
$today.AddHours($mytime.Hour)
Or:
$mytime = Get-Date "1/1/2020 10:00:00"
[DateTime]::Today.AddHours($mytime.Hour)

It works for me. You're adding 844.4 hours (35 days) in the first example, the number of hours to get to the current day and time, and 100 hours (4 days) in the second.
$mytime = "1/1/2020 10:00:00"
$hours = (New-TimeSpan -Start $mytime).TotalHours
$hours
844.404845696333
(Get-Date $mytime).AddHours($hours)
Wednesday, February 5, 2020 2:24:17 PM
$mytime = "1/1/2020 10:00:00"
$hours = 100
(Get-Date $mytime).AddHours($hours)
Sunday, January 5, 2020 2:00:00 PM
Here's another example:
[datetime]'2:28pm' + (new-timespan -Hours 1)
Wednesday, February 5, 2020 3:28:00 PM
If it's under 24 hours, it can be as simple as ([timespan] is implied in the 2nd argument):
[datetime]'2:28pm' + '1:0'
Wednesday, February 5, 2020 3:28:00 PM
Subtracting two datetimes:
[datetime]"Wednesday, February 5, 2020 11:25:37 AM" - [datetime]"1/1/2020 10:00:00"
Days : 35
Hours : 1
Minutes : 25
Seconds : 37
Milliseconds : 0
Ticks : 30291370000000
TotalDays : 35.0594560185185
TotalHours : 841.426944444444
TotalMinutes : 50485.6166666667
TotalSeconds : 3029137
TotalMilliseconds : 3029137000

Related

Increment hours by 30 minutes 20 times in Powershell

I have to create multiple job in my app. These jobs should be separated by 30 minutes apart starting at 17:00. My dilemma how to get 20 times in hour and minutes ( HH:MM) format starting at 17:00 ?? Onces i have those times , i can loop all jobs 30 minutes apart.
Thank you
So far i have tried
$ts = New-TimeSpan -Hours 17 -Minutes 00
But adding minutes to $ts not working
PS F:\> $ts.AddMinutes(30)
Method invocation failed because [System.TimeSpan] does not contain a method named 'addminutes'.
At line:1 char:1
+ $ts.AddMinutes(30)
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
You can simply add a new timespan:
$newts = $ts + (New-TimeSpan -Minutes 30)
You can add a string that will automatically convert to type [timespan], since the left argument is [timespan]:
$ts = [timespan]'17:30'
$ts += '0:30'
$ts
Days : 0
Hours : 18
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 648000000000
TotalDays : 0.75
TotalHours : 18
TotalMinutes : 1080
TotalSeconds : 64800
TotalMilliseconds : 64800000
Paolo's helpful answer shows how to add a timespan to an existing timespan, where the + operation translates to the [timespan] type's .Add() method.
By contrast, it is the [datetime] / [datetimeoffset] types that have an .AddMinutes() .AddMinutes() method.
Therefore, you could do the following:
# Get today's date at 17:00 hours
$start = Get-Date -Hour 17 -Minute 0 -Second 0 -MilliSecond 0
# Loop 20 times and add 30 minutes each, and format as "HH:mm"
0..19 | ForEach-Object { $start.AddMinutes($_ * 30).ToString('HH:mm') }
Output:
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
00:00
00:30
01:00
01:30
02:00
02:30

For a given month and year how to get the second Sunday using PowerShell?

I am trying to calculate the second Sunday of a month.
using PowerShell script, how to get the second Sunday of a month for any given year?
Using the integer value of Dayofweek as a (negative) offset 0..6 for Sunday..Saturday.
Get the Last Sunday of the previous Month and add 14
## Q:\Test\2019\04\29\SO_55905125.ps1
function Get-Sunday2nd {
param(
[int]$Year=(Get-Date).Year,
[int]$Month=(Get-Date).Month,
[switch]$Time)
$LastDayPrevMonth = (Get-Date -Year $Year -Month $Month -Day 1).Date.AddDays(-1)
$Sunday2nd = $LastDayPrevMonth.AddDays(14-[int]$LastDayPrevMonth.DayOfWeek)
$Sunday2nd
}
Get-Sunday2nd 2019 5
Sonntag, 12. Mai 2019 00:00:00
Get-Sunday2nd -Year 2018 -Month 5
Sonntag, 13. Mai 2018 00:00:00

Get the last day of a month on powershell

I'm trying to put in a .txt file the first day and the last day of the months using PowerShell.
In the exemple below i was trying to get the first and the last day of July, but i'm just getting the first day. The second line of the script isn't working.
#PowerShell "(Get-Date).AddMonths(1).ToString('01/MM/yyyy')" >>dates.txt
$LastDayInMonthString = "$($(get-date).AddMonths(1).ToString("dd/mm/yyy"))$LastDayInMonth" >>dates.txt
Someone can say me what is wrong?
I wanted a .txt file like it: 01/07/2018, 31/07/2018.
The first line write the first day of next month,
and second line write the last day of that month.
Much simpler solution is to call into the DaysInMonth function
[DateTime]::DaysInMonth(2018, 11)
For the current month that would look like:
$today = get-date
$lastDay = [DateTime]::DaysInMonth($today.Year, $today.Month)
$firstDate = [DateTime]::new($today.Year, $today.Month, 1)
$lastDate = [DateTime]::new($today.Year, $today.Month, $lastDay)
$firstDate
$lastDate
This also works around any hindering daylight savings changes and other weird things that can happen with timezones etc.
Or if pure strings are all you need:
(get-date -Format "yyyy/MM") + "/1"
(get-date -Format "yyyy/MM") + "/" + [DateTime]::DaysInMonth((get-date).Year, (get-date).Month)
An easy way is to take the last day of the previous year and add 1..12 months to it:
1..12 | % { (New-Object DateTime(2017,12,31)).AddMonths($_) }
Output will be in the user's date/time format, in my case Dutch:
woensdag 31 januari 2018 00:00:00
woensdag 28 februari 2018 00:00:00
zaterdag 31 maart 2018 00:00:00
maandag 30 april 2018 00:00:00
donderdag 31 mei 2018 00:00:00
zaterdag 30 juni 2018 00:00:00
dinsdag 31 juli 2018 00:00:00
vrijdag 31 augustus 2018 00:00:00
zondag 30 september 2018 00:00:00
woensdag 31 oktober 2018 00:00:00
vrijdag 30 november 2018 00:00:00
maandag 31 december 2018 00:00:00
If required you can format it as you need it, e.g.
1..12 | % { (New-Object DateTime(2017,12,31)).AddMonths($_).ToString("yyyyMMdd") }
20180131
20180228
20180331
20180430
20180531
20180630
20180731
20180831
20180930
20181031
20181130
20181231
This seems simple enough
$firstDate = [DateTime]::new($reportDate.Year, $reportDate.Month, 1)
$lastDate=$firstDate.AddMonths(1).AddDays(-1)
Edit removed the for only date unneccessary time adjustments
In PowerShell to get the first day and last of next month
$CIGB = New-Object System.Globalization.CultureInfo('en-GB')
'{0}, {1}' -f (Get-Date -Day 1).AddMonths(1).ToString('d',$CIGB),
(Get-Date -Day 1).AddMonths(2).AddDays(-1).ToString('d',$CIGB)|sc dates.txt
The $CIGB is neccessary for me because my local date separator overrides the /
If your short date format 'd' returns dd/MM/yyyy the first line and the ,$CIGB can be removed.
01/07/2018, 31/07/2018
This can be wrapped in a single (albeit quite long) line.
powershell -nop -c "$CIGB=New-Object System.Globalization.CultureInfo('en-GB');'{0}, {1}' -f (Get-Date -Day 1).AddMonths(1).ToString('d',$CIGB),(Get-Date -Day 1).AddMonths(2).AddDays(-1).ToString('d',$CIGB)">>dates.txt
> type dates.txt
01/07/2018, 31/07/2018
Strings can be passed to Get-Date. The -Format parameter also accepts strings/variables.
# Get the previous month
$LastMonth = (Get-Date).AddMonths(-1)
# Format the first day of the month
$FirstDayOfMonth = $LastMonth | Get-Date -Format "yyyy/MM/01"
# Calculate the number of days (last day) in the month
$LastDay = [DateTime]::DaysInMonth($LastMonth.Year, $LastMonth.Month)
# Use it in the format parameter
$LastDayOfMonth = $LastMonth | Get-Date -Format "yyyy/MM/$lastDay"

Get-Date formatting/culture

How do I specify what part of my input string is the date and month?
If the input is 01/10/2017, this can be read as 1st Oct 2017 and 10th Jan 2017. Both are correct.
I want to be explicit that 01 is date and 10 is month, so that irrespective of locale and time format I can get a consistent result.
Sample code:
get-date -Date '01/10/2017'
The output is:
Tuesday, January 10, 2017 12:00:00 AM
The desired output is:
Sunday, October 01, 2017 12:00:00 AM
I have a solution for you. It requires that the culture as one of the arguments.
([datetime]::ParseExact($date,"dd/MM/yyyy",[Globalization.CultureInfo]::CreateSpecificCulture('en-GB')))
A culture does not have to be specified. However, the argument for it does, otherwise you will get an error:
Cannot find an overload for "ParseExact" and the argument count: "2".
[cultureinfo]::InvariantCulture or $null can be used as the third argument:
$date = "01/10/2017"
[datetime]::ParseExact($date, "dd/MM/yyyy", [cultureinfo]::InvariantCulture)
[datetime]::ParseExact($date, "dd/MM/yyyy", $null)
Output in all three cases
01 October 2017 00:00:00
Try this:
Get-Date(Get-Date -Date $date -Format 'dd/MM/yyyy')
You can enforce the culture for single commands (or command blocks). This should help avoiding that date chaos.
PS C:\> [System.Threading.Thread]::CurrentThread.CurrentUICulture = "en-US" ; [System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US"; get-date -Date '01/10/2017'
Tuesday, January 10, 2017 12:00:00 AM
PS C:\> [System.Threading.Thread]::CurrentThread.CurrentUICulture = "en-GB" ; [System.Threading.Thread]::CurrentThread.CurrentCulture = "en-GB"; get-date -Date '01/10/2017'
01 October 2017 00:00:00

PowerShell date time conversion issue

When I run the below two PowerShell statements, I expect them to return the same result, but in fact they return different results:
New-TimeSpan $(Get-Date) $(Get-Date -month 12 -day 31 -year 2016)
New-TimeSpan $(Get-Date) $(Get-Date "2016-12-31")
The results are:
Days : 751
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 1
Ticks : 648864000010001
TotalDays : 751.000000011575
TotalHours : 18024.0000002778
TotalMinutes : 1081440.00001667
TotalSeconds : 64886400.0010001
TotalMilliseconds : 64886400001.0001
Days : 750
Hours : 6
Minutes : 50
Seconds : 13
Milliseconds : 67
Ticks : 648246130673175
TotalDays : 750.284873464323
TotalHours : 18006.8369631437
TotalMinutes : 1080410.21778863
TotalSeconds : 64824613.0673175
TotalMilliseconds : 64824613067.3175
What's going on?
I'm pretty sure the answer is in the different parameter sets you are using. Referring to the TechNet article. There are two different parameter sets: net and uformat
Get-Date "2016-12-31" is is being detected as net
(Get-Date -month 12 -day 31 -year 2016) is being detected as uformat
In the latter, since you are not specifying the time components, it is defaulting them to the current time. Looking at the documentation for -Hour
-Hour<Int32>
Specifies the hour that is displayed. Enter a value from 1 to 23. The default is the current hour.
When the string "2016-12-31" is cast to a datetime midnight, it is used in the absence of a value. In the other case no time is specified, so it is using the current time in its place.
PS C:\Users\Cameron> (Get-Date -month 12 -day 31 -year 2016)
Saturday, December 31, 2016 5:14:32 PM
PS C:\Users\Cameron> $(Get-Date "2016-12-31")
Saturday, December 31, 2016 12:00:00 AM
I might be slightly wrong on the terms or cause, but I have to be close. Even when specifying hour for example the other time values still need to come from somewhere. The time when the code was run was 5:24 pm EST.
PS C:\Users\Cameron> (Get-Date -month 12 -day 31 -year 2016 -Hour 12)
Saturday, December 31, 2016 12:24:43 PM