Date Time day of the week comparison logic in PowerShell - powershell

Date Time objects allow us to perform actions like this:
$CurrentDate = Get-Date
$TextDate = get-date -date "02/10/2016"
if ($TextDate -lt $CurrentDate){
Write-Host "True"
}
else {
Write-Host "False"
}
This outputs "True" because $TextDate is less than $CurrentDate.
Following the same logic, why does the following code output false?
$CurrentDate = Get-Date -UFormat %V
$TextDate = Get-Date -date "02/10/2016"
$TextDate = Get-Date -date $TextDate -UFormat %V
if ($TextDate -lt $CurrentDate){
Write-Host "True"
}
else {
Write-Host "False"
}
The only difference is that we are comparing the week of the year. If you change the comparison to -gt, the code returns True.

Formatted dates are strings, not integers. The string "6" is after the string "11".
This would be the most correct way to do this:
First, decide what the "first week of the year" actually means:
$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstDay;
#$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstFourDayWeek;
#$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstFullWeek;
Then, decide which day of the week is the first day of the week:
$FirstDayOfWeek = [System.DayOfWeek]::Sunday;
#$FirstDayOfWeek = [System.DayOfWeek]::Monday;
#Any day is available
Then you can get your correct week number:
$Today = (Get-Date).Date;
$TodayWeek = [cultureinfo]::InvariantCulture.Calendar.GetWeekOfYear($Today, $CalendarWeekRule, $FirstDayOfWeek);
$TargetDate = Get-Date -Date "2016-02-10";
$TargetWeek = [cultureinfo]::InvariantCulture.Calendar.GetWeekOfYear($TargetDate, $CalendarWeekRule, $FirstDayOfWeek);
if ($TargetWeek -lt $TodayWeek) { $true } else { $false }
Note that if you want a full ISO 8601 week, it's somewhat more complicated.

Because you are comparing string-objects.
(Get-Date -UFormat %V).GetType().FullName
System.String
When comparing strings using -gt and -lt it sorts the strings and because 6 comes after 1, your 6 -lt 11-test returns false.

Both $TextDate and $CurrentDate are of type [string] so what you are evaluating is '6' -lt '11' which will return false. Operators are based on the left side type in PowerShell. So in order to force an integer comparison modify your expression as under
if ([int]$TextDate -lt $CurrentDate)
{
Write-Host "True"
}
else
{
Write-Host "False"
}

Related

Powershell how to check if friday is the last day of the month , returning True from a Function

I have tried to make a function in Powershell that produces a True if the last day of the month is friday.
function Get-LastFridayOfMonth([DateTime] $d) {
$lastDay = new-object DateTime($d.Year, $d.Month,[DateTime]::DaysInMonth($d.Year, $d.Month))
$diff = ([int] [DayOfWeek]::Friday) - ([int] $lastDay.DayOfWeek)
if ($diff -gT 0) {
return $lastDay.AddDays(- (7-$diff))
} else {
return $lastDay.AddDays($diff)
}
}
$testdate = Get-LastFridayOfMonth (Get-Date)
But how to check if that friday is the last day of the month ?
#Theo's answer reframes your question and gives a nice all-in-one solution, but to address your specific question:
"how to check if [a date] is the last day of the month ?"
you can just add one day to the date and see if the month changes. If it does change then the original date must be the last one in the month…
$testdate = [datetime] "2023-01-31"
$isLastDayOfMonth = $testdate.AddDays(1).Month -ne $testdate.Month
$isLastDayOfMonth
# True
$testdate = [datetime] "2023-01-30"
$isLastDayOfMonth = $testdate.AddDays(1).Month -ne $testdate.Month
$isLastDayOfMonth
# False
$testdate = Get-LastFridayOfMonth (Get-Date)
$isLastDayOfMonth = $testdate.AddDays(1).Month -ne $testdate.Month
$isLastDayOfMonth
# depends on if the month ends on a friday
I would change that function to just return the last days weekday so after calling it you can decide what weekday you get for the given date.
function Get-LastWeekDayOfMonth {
param (
[datetime]$Date = (Get-Date)
)
# .AddDays(-$Date.Day+1) sets the given date to the 1st of that month
$Date.AddDays(-$Date.Day+1).AddMonths(1).AddDays(-1).DayOfWeek
}
switch (Get-LastWeekDayOfMonth) {
'Friday' { "It's a Friday !" }
default { $_ }
}
Using the current date (February 2023) it would yield Tuesday
If you specify for instance March 2023
$d = Get-Date -Year 2023 -Month 3 -Day 1
switch (Get-LastWeekDayOfMonth -Date $d) {
'Friday' { "It's a Friday !" }
default { $_ }
}
The outcome will be It's a Friday !
If however you want a function to simply return $true or $false when the month end in a Friday or not, do this instead:
function Test-LastDayOfMonthIsFriday {
param (
[datetime]$Date = (Get-Date)
)
# .AddDays(-$Date.Day+1) sets the given date to the 1st of that month
$Date.AddDays(-$Date.Day+1).AddMonths(1).AddDays(-1).DayOfWeek -eq 'Friday'
}
Test-LastDayOfMonthIsFriday # --> $false
Test-LastDayOfMonthIsFriday -Date (Get-Date -Year 2023 -Month 3 -Day 1) # --> $true
Special thanks to mklement0 for the $Date.AddDays(-$Date.Day+1) part which always sets the date to the first day of that month

Powershell validate textbox for dates

I'm trying to validate a textbox in Powershell. It should only allow the format dd.MM.yyyy (f.e 22.11.2022). Yet if I type some random characters (f.e 20.2), I get erros instead of a MessageBox.
I've tried something like this:
if($Starttextbox.Text -as [DateTime] -or $Endtextbox.Text -as [DateTime]){
"do something"
}else{
[System.Windows.MessageBox]::Show('Type in correct format','format','Ok','Error')
}
You could create a small function and use a combination of RegEx and Get-Date commandlet, like below.
$StartDate = '22.12.2022' #Good
$EndDate = '22.19.2022' #Bad
function Get-ValidDate { param($DateToCheck)
$DateToCheck -match '(\d{2})\.(\d{2})\.(\d{4})' | Out-Null
if($matches.count -eq 4) {
$ValidDate = $(Get-Date -Date "$($matches[2])-$($matches[1])-$($matches[3])" -Format 'dd.MM.yyyy') 2>> $NULL
}
if($DateToCheck -eq $ValidDate) {
return "GoodDate"
}
}
if((Get-ValidDate $StartDate) -and (Get-ValidDate $EndDate)) {
Write-Host "These are Good Dates!" # DO STUFF
} else {
Write-Host "These are Bad Dates!" # MESSAGEBOX
}
2>>$NULL will remove your Get-Date error messages as all you're looking for is a valid datetime from Get-Date. Function will only return on RegEx match and a valid date.
Here is the regex for dates in the format of dd.mm.yyyy:
^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

Modifying a Date variable in PowerShell

I'm looking to create a schedule type check.
I want to check today's date and if it's not the correct Day of the week for a task to run it continues.
Once the day is correct, I will then create a timer based on the difference between the expected execution time (let's say 01:00) and now. I have had a few ideas on how to achieve this, one of them being below. The problem I am facing is I am unsure of how to create a CountDown timer from the NEW-TIMESPAN output and how to dynamically change the $EndDate time value to meet the relevant schedule value. Any pointers would be appreciated.
$date = Get-Date -DisplayHint Date
if ($date.DayOfWeek -eq 'Friday')
{
$StartDate = (GET-DATE)
# I am unsure of how to dynamically change the $EndDate variable time value and create the 'CountDown variable' from the New-TimSpan output.
$EndDate = [datetime]"11/13/2020 01:00"
$countdown = NEW-TIMESPAN -Start $StartDate -End $EndDate
}
Write-Host $date
EDIT
With some help from #AdminOfTHings I have come up with the following solution.
if ($date.DayOfWeek -eq $schedule.Day)
{
$StartDate = (GET-DATE)
$tempDate = (GET-DATE).ToString()
$tempDate, $tempTime = $tempDate.Split(' ')
[datetime]$DateTime = $tempDate + " $($schedule.Time)"
$Timer = NEW-TIMESPAN -End $DateTime
$CountDown = $Timer.TotalSeconds
while ($CountDown -gt 0)
{
sleep 1
$CountDown--
}
else
{
#START SERVICE
}
}
New-Timespancreates a TimeSpan object regardless of the parameter set being used. If you know how long a timespan should be, then you can statically create that combination of days, hours, minutes, and seconds, making end time irrelevant.
$date = Get-Date -DisplayHint Date
if ($date.DayOfWeek -eq 'Friday') {
$countdown = New-Timespan -Hours 8
}
You could have a situation where you know you want the task to span 2 days but want it to end at 01:00. This would make the total time variable. You can make adjustments based on start time:
$date = Get-Date -DisplayHint Date
if ($date.DayOfWeek -eq 'Friday') {
$end = Get-Date -Day $date.AddDays(2).Day -Month $date.AddDays(2).Month -Hour 1 -Minute 0 -Second 0
$countdown = New-TimeSpan -End $end
}
Edit:
If you reach a target day of week and want to create a timer that lasts until the next 01:00 hour from that point in time, you can do the following:
$date = Get-Date
if ($date.DayOfWeek -eq 'Friday') {
if ($date.Hour -lt 1) {
# dynamic end date - start date
$countdown = (Get-Date $date -Hour 1 -Minute 0 -Second 0) - $date
} else {
# dynamic end date - start date
$countdown = (Get-Date $date.AddDays(1) -Hour 1 -Minute 0 -Second 0) - $date
}
}
$countdown.TotalSeconds # total seconds of the time span
As an aside, if you expect the starting time to be now, you can skip the -Start parameter. Leaving off -Start assumes the starting time is now.
Thanks for the help, I have no idea why I didn't think of it before but I have come up with
if ($date.DayOfWeek -eq 'Friday')
{
$StartDate = (GET-DATE)
$tempDate = (GET-DATE).ToString()
$tempDate, $tmpTime = $tempDate.Split(' ')
datetime]$DateTime = $tempDate + " $($schedule.Time)"
$Timer = NEW-TIMESPAN -End $DateTime
}
Just need to understand how to use the timer now (all in seconds)

Compare dates from a string in PowerShell [duplicate]

This question already has answers here:
Compare Get-Date to Date as String
(1 answer)
How to parse (French) full month into datetime object in PowerShell?
(1 answer)
Closed 4 years ago.
$Deldate = "19-06-2018"
$Newdate = "04-06-2018"
I need to check which date is bigger.
if ($Deldate -ge $NewDate) {
write-host "NewDate is bigger"
}
else {
write-host "Deldate is bigger"
}
This is not working for me, and it looks like the format is not "System.DateTime". I'm getting the date values are from an external CSV file. How do I find a solution for this?
You should be able to cast the strings that you have created to the "datetime" type like so:
$Deldate = "19-06-2018"
$Newdate = "04-06-2018"
$Deldate = [datetime]::ParseExact("$Deldate", 'dd-MM-yyyy', $null)
$Newdate = [datetime]::ParseExact("$Newdate", 'dd-MM-yyyy', $null)
if ($Deldate -ge $NewDate) {
write-output "NewDate is bigger than or equal to"
}
else {
write-output "Deldate is bigger"
}
This returns the correct result. You can't simply use the Get-Date cmdlet, since the -Date required parameter also requires that the parameter be of type "DateTime", so you first have to cast the strings to the DateTime type.
Originally Proposed...
I am going to change the format of your date just a hair from DD-MM-YYYY to MM-DD-YYYY:
$Deldate = Get-Date "06-19-2018"
$Newdate = Get-Date "06-04-2018"
if ($Deldate -gt $Newdate) {
'Deldate is larger'
}
else {
'Newdate is larger or equal'
}
I'm creating two date objects based on the respective dates you gave. I'm comparing the two objects; PowerShell knows how to do the date math.
It works fine for U.S. style dates.
After much discussion...
However, for non-US style dates, consider calling datetime's constructor:
$Deldate = New-object 'datetime' -ArgumentList 2018, 6, 19, $null, $null, $null
$Newdate = New-object 'datetime' -ArgumentList 2018, 6, 4, $null, $null, $null
if ($Deldate -gt $Newdate) { 'Deldate is larger' } else { 'Newdate is larger or equal' }
Or, as proposed the [datetime]::ParseExact() method; documented here.
PowerShell is good with dates; it just has to know it's a date...
$Deldate = get-date "19-06-2018"
$Newdate = get-date "04-06-2018"
if ($Deldate -ge $NewDate) {
write-host "NewDate is bigger"
}
else {
write-host "Deldate is bigger"
}
Note: You could cast [datetime]$Deldate ="19-06-2018", but as explained in comments to PowerTip: Convert String into DateTime Object, it's valid only for US date format.

Date variable still contains todays date after assigning it the value of upcoming Friday

I have a little powershell script to find the date of the upcoming Friday. However after assigning the value of the Friday date, my date variable still prints out todays date.
$date = Get-Date
for($i=1; $i -le 7; $i++)
{
if($date.AddDays($i).DayOfWeek -eq 'Friday')
{
$date.AddDays($i)
break
}
}
Write-Host "$date"
AddDays seems to return new date object and not update the date object in $date. Try assigning $date to the new date inside the if statement as follows:
$date = $date.AddDays($i)
$date = Get-Date
for($i=1; $i -le 7; $i++)
{
if($date.AddDays($i).DayOfWeek -eq 'Friday')
{
$date = $date.AddDays($i)
break
}
}
Write-Host "$date"
You have to return the value you're assigning to $date back to itself.
You probably tested it yesterday (Wednesday) because it works today.
The problem in your code is that it reuses the same $Date each time and probably step over the expected date:
Date + 1
Date + 3 (1 + 2)
Date + 6 (1 + 2 + 3)
...
In other words, the $date = Get-Date should be in your loop.
(Get-Date).AddDays((1..7 | Where {(Get-Date).AddDays($_).DayOfWeek -eq 'Friday'}))