Get the number of Days in the current month using powershell - powershell

I have the need to retrieve the number of days in the current month, and despite my research, I have yet to find anything in powershell that does it. The following is what I have currently built to get the result I want. is there a better way to do it?
Please note that I am limited to Powershell
#check to see if this is a leap year
function LYC
{
if ([System.DateTime]::isleapyear((Get-Date).Year))
{
$Global:LY = True
}
}
#Get the number of days in current month
function fNOD
{
$MNum = (Get-Date).Month
switch ($MNum)
{
1 {$Global:DaysInMonth=31}
2 {
LYC
if (LY)
{
$Global:DaysInMonth=29
} else {
$Global:DaysInMonth=28
}
}
3 {$Global:DaysInMonth=31}
4 {$Global:DaysInMonth=30}
5 {$Global:DaysInMonth=31}
6 {$Global:DaysInMonth=30}
7 {$Global:DaysInMonth=31}
8 {$Global:DaysInMonth=31}
9 {$Global:DaysInMonth=30}
10 {$Global:DaysInMonth=31}
11 {$Global:DaysInMonth=30}
12 {$Global:DaysInMonth=31}
}
}

http://msdn.microsoft.com/en-us/library/system.datetime.daysinmonth.aspx
# static int DaysInMonth(int year, int month)
[DateTime]::DaysInMonth(2013, 3)

Assuming you want it for any date stored in $date:
((get-date $date -Day 1 -hour 0 -Minute 0 -Second 0).AddMonths(1).AddSeconds(-1)).Day

This seems to me like it might be deceptively easy:
$numDays = ((Get-Date -Month 3) - (Get-Date -Month 2))
28 days in February, July minus June gives me 30 days.
As mentioned below, that apparently sometimes does some weird integer rounding that gives off 29d, 23h, 59m or something else not right.
This seems to be consistent:
$monthLess = Get-Date -Month 4
$NumDays = (Get-Date -Month 5).Subtract($monthLess)

Related

Get Lotus Notes calendar entries for a time range in powershell

I try to track the time I use for projects by adding the project id as a category to a lotus notes calendar entry.
Now I want to select all appointments over a time range (i.e. the last 7 days), group them by category and sum up the time.
Except for the time range thingy it works fine. The solution seams to be the method GetAllDocumentsByKey (https://help.hcltechsw.com/dom_designer/9.0.1/appdev/H_GETALLDOCUMENTSBYKEY_METHOD.html)
I tried to define a time range, a string (subject or category) or an array (values: subject or category) as keyArray but nothing seams to work.
Any idea?
$notesINI = Get-IniContent $env:LOCALAPPDATA\IBM\Notes\Data\notes.ini
$InputNotesMailBox = $notesINI.Notes.MailFile
$InputNotesServer = $notesINI.Notes.MailServer
$DomSession = New-Object -ComObject Lotus.NotesSession
$DomSession.Initialize()
$DomDatabase = $DomSession.GetDatabase($InputNotesServer,$InputNotesMailBox)
$DomView = $DomDatabase.GetView('Calendar')
# This works fine but is really slow because it processes all the documents in my calendar (5Min for 6k documents)
$DomDocRange = $DomView
$DomDoc = $DomDocRange.GetFirstDocument()
$date_s = $(get-date -Year 2022 -Month 4 -Day 7)
$date_e = $(get-date -Year 2022 -Month 4 -Day 14)
while($DomDoc -ne $null){
if($DocCategory -like "proiject-*"){
$Termin_StartDate = $DomDoc.getItemVAlue('StartDateTime')[0]
if(IsBetweenDates2 $date_s $date_e $(get-date $Termin_StartDate)){
# add time and project id to multidimensional array
}
}
}
# does not work because I don't know how to filter getAllDocumentsByKey
$date_s = $(get-date -Year 2022 -Month 4 -Day 7)
$date_e = $(get-date -Year 2022 -Month 4 -Day 14)
$DomDateRange = $DomSession.CreateDateRange()
$DomDateRange.StartDateTime = $DomSession.CreateDateTime($date_s)
$DomDateRange.EndDateTime = $DomSession.CreateDateTime($date_e)
$DomDocRange = $DomView.getAllDocumentsByKey($DomDateRange, $true)
$DomDoc = $DomDocRange.GetFirstDocument()
while($DomDoc -ne $null){
if($DocCategory -like "proiject-*"){
$Termin_StartDate = $DomDoc.getItemVAlue('StartDateTime')[0]
if(IsBetweenDates2 $date_s $date_e $(get-date $Termin_StartDate)){
# add time and project id to multidimensional array
}
}
}
GetDocumentByKey is a function of a view that needs to be sorted by the key you are searching for. The "Calendar"- view is not suitable for this function.
You need to get away from NotesView and get your document collection from the database itself without using the view.
$DomDocRange = $DomDatabase.search( 'Form = "Appointment" & StartDateTime >= [InjectYourStartDateHere] & StartDateTime <= [InjectYourEndDateHere]', Nothing, 0 )
$DomDoc = $DomDocRange.GetFirstDocument()
The constructed #Formula needs to look like this in the end:
Form = "Appointment" & StartDateTime >= [04/01/2022] & StartDateTime <= [04/12/2022]
The brackets are important as they mark the given value as a date. The date needs to be in your local format (MM/DD/YYYY or DD.MM.YYYY or...).
Unfortunately I did not use the interface with Powershell yet, so I can't tell you, how the insert the LotusScript variable "Nothing" here, you could try omit it (use double comma) or use $null...

Finding the Sunday between the 1st and 2nd Tuesday of the month

Fairly new to PS, I want to batch file on Sunday between the 1st and the 2nd Tuesday of the month.
I know how to find the the 1st and 2nd Tuesdays I am looking for, cannot figure out the rest.
$FindNthDay = 1
$WeekDay = 'Tuesday'
[datetime]$Today = [datetime]::NOW
$todayM = $Today.Month.ToString()
$todayY = $Today.Year.ToString()
[datetime]$StrtMonth1 = $todayM + '/1/' + $todayY
while ($StrtMonth1.DayofWeek -ine $WeekDay ) { $StrtMonth1 = $StrtMonth1.AddDays(1) }
$StrtMonth1.AddDays(7 * ($FindNthDay - 1))
#
$FindNthDay = 2
$WeekDay = 'Tuesday'
[datetime]$Today = [datetime]::NOW
$todayM = $Today.Month.ToString()
$todayY = $Today.Year.ToString()
[datetime]$StrtMonth = $todayM + '/1/' + $todayY
while ($StrtMonth.DayofWeek -ine $WeekDay ) { $StrtMonth = $StrtMonth.AddDays(1) }
$StrtMonth.AddDays(7 * ($FindNthDay - 1))
I know how to find the the 1st and 2nd Tuesdays
Since there's only one Sunday in between, you only need to find the first one:
# Get-Date -Day 1 will give us the 1st of the current month
$firstTuesday = Get-Date -Day 1
while($firstTuesday.DayOfWeek -ne 'Tuesday') {
$firstTuesday = $firstTuesday.AddDays(1)
}
And then add another 5 days:
$sundayAfterFirstTuesday = $firstTuesday.AddDays(5).Date
Which (in January 2021) gives us:
PS ~> $sundayAfterFirstTuesday
Sunday, January 10, 2021 12:00:00 AM
In addition to Mathias's fine answer, I got hung up on this. Given that .DayOfWeek is an [enum] that's easily converted to a [Int] I was looking for a mathematically concise way to derive the first Tuesday. Since it's fairly obvious how to then find the following Sunday by just doing .AddDays(5) .
Honestly, I was stumbling a bit because While .DayOfWeek is 0 - 6 how many days to add depends on if the current day, in this case the first of the month, is less than or greater than Tuesday (2). It was worth playing around; here are 2 alternate approaches I came up with:
Example 1: A switch statement that's not at all concise but is very readable:
$Day1 = Get-Date "1/1/2021"
Switch ( $Day1.DayOfWeek )
{
'Sunday' { $Sunday = $Day1.Adddays(2).AddDays( 5 ); Break }
'Monday' { $Sunday = $Day1.Adddays(1).AddDays( 5 ); Break }
'Tuesday' { $Sunday = $Day1.AddDays( 5 ); Break }
'Wednesday' { $Sunday = $Day1.Adddays(6).AddDays( 5 ); Break }
'Thursday' { $Sunday = $Day1.Adddays(5).AddDays( 5 ); Break }
'Friday' { $Sunday = $Day1.Adddays(4).AddDays( 5 ); Break }
'Saturday' { $Sunday = $Day1.Adddays(3).AddDays( 5 ); Break }
}
$Sunday
This is also easy to adjust. For example, if you wanted to switch to 1st Sunday between 1st & 2nd Monday etc...
For the mathematical / logic approach it came out a little more crude:
$Day1 = Get-Date "1/1/2021"
If( [Int]$Day1.DayOfWeek -gt 2 ) { $Interval = 7 - ([Int]$Day1.DayOfWeek - 2) }
Else { $Interval = 2 - [Int]$Day1.DayOfWeek }
$Sunday = $Day1.AddDays( $Interval ).AddDays( 5 )
$Sunday
The above example can be more concise in PowerShell 7+ using the ternary operator:
$Day1 = Get-Date "1/1/2021"
$Interval = $Day1.DayOfWeek -gt 2 ? 7 - ([Int]$Day1.DayOfWeek - 2) : 2 - [Int]$Day1.DayOfWeek
$Sunday = $Day1.AddDays( $Interval ).AddDays( 5 )
$Sunday
Note: all of the examples user 1/1/2021 as the starting date, but I did test across multiple 1st days of the month, For example, if the first day was a Monday, Sunday, Thursday etc...
Note: Some of the [Int] casting can probably be removed if one is careful about PowerShell type conversion system, but I wanted to get this out there. If I have time I'll cleanup further.
Or a slightly different approach:
$BaseDate = (Get-Date 3/1/2021)
$BaseDate.AddDays( (& {if ([int]$BaseDate.DayOfWeek -gt 2) {14}
else { 7 } }) - [int]($BaseDate).DayOfWeek)
Sunday, March 7, 2021 12:00:00 AM

Find 3rd Saturday of the month

I need to find the date of the third saturday of the month.
I've got the following function, which finds me the last saturday of the month
function Get-3rdSaturdayOfMonth {
$Date = Get-Date
$lastDay = new-object DateTime($Date.Year, $Date.Month, [DateTime]::DaysInMonth($Date.Year, $Date.Month))
$diff = ([int] [DayOfWeek]::Saturday) - ([int] $lastDay.DayOfWeek)
if ($diff -ge 0) {
return $lastDay.AddDays(- (7-$diff))
}
else {
return $lastDay.AddDays($diff)
}
}
However, I don't know how to edit it to find the third saturday of the month.
Right now the function goes from last date of the month to the saturday that comes before it. But if I want the third saturday i think i need to calculate from the first day of the month, not the last.
Based on the solution from Brandon, since the third Saturday can't possibly occur before the 15th of the month, we can increment from the 15. until we find a saturday:
$thirdSaturday = [DateTime]::new((Get-Date).Year,(Get-Date).Month,15)
while ($thirdSaturday.DayOfWeek -ne [DayOfWeek]::Saturday)
{
$thirdSaturday = $thirdSaturday.AddDays(1)
}

Powershell - Getting a persons age

I'm trying to get a person age in Years,Months,Days,Hours,Minutes and Seconds.
This is what I got so far (you can tell I'm a total powershell beginner):
$now = [datetime]::now
[datetime]$birthday = "12/22/2012 03:22:00"
$age = [datetime]$now - $birthday
Write-Host "My daughter's age is:" $age.Days "days" ($age.Hours) "hours" ($age.Minutes) "minutes" ($age.Milliseconds) "seconds"
The output is:
My daughter's age is: 59 days 10 hours 27 minutes 76 seconds
It's ok, but it would be more awesome have the output more 'human readable':
1 Month 19 Days 10 hours 28 minutes 16 seconds
This is actually way more difficult than I initially expected. The code must know how many days has each month in order to split days into months and days. And also consider that this year is leap year!
Maybe PowerShell can help here with some of its magic!
Thank you!
I believe this is what you're after.
[datetime]$birthday = "12/22/2012 03:22:00"
$span = [datetime]::Now - $birthday
$age = New-Object DateTime -ArgumentList $Span.Ticks
Write-Host "My daughter's age is:" $($age.Year -1) Years $($age.Month -1) Months $age.Day "days" ($age.Hour) "hours" ($age.Minute) "minutes" ($age.second) "seconds"
Check it with the day after your birthday. There is 1 day to much!
Correct are:
[datetime]$birthday = "12/22/2012 03:22:00"
$span = [datetime]::Now - $birthday
$age = New-Object DateTime -ArgumentList $Span.Ticks
Write-Host "My daughter's age is:" $($age.Year-1) Years $($age.Month-1) Months ($age.Day-1) "days" ($age.Hour) "hours" ($age.Minute) "minutes" ($age.second) "seconds"

Formatting PowerShell Get-Date inside string

I can't get my head around how formatting a datetime variable inside a string works in PowerShell.
$startTime = Get-Date
Write-Host "The script was started $startTime"
# ...Do stuff...
$endTime = Get-Date
Write-Host "Done at $endTime. Time for the full run was: $( New-TimeSpan $startTime $endTime)."
gives me the US date format while I want ISO 8601.
I could use
$(Get-Date -Format u)
but I want to use $endTime to make the calculation of the timespan correct.
I have tried all permutations of $, (, ), endTime, -format, u, .ToString(...) and .ToShortDate(), but the one that works.
"This is my string with date in specified format $($theDate.ToString('u'))"
or
"This is my string with date in specified format $(Get-Date -format 'u')"
The sub-expression ($(...)) can include arbitrary expressions calls.
Microsoft Documents both standard and custom DateTime format strings.
You can use the -f operator
$a = "{0:D}" -f (get-date)
$a = "{0:dddd}" -f (get-date)
Spécificator Type Example (with [datetime]::now)
d Short date 26/09/2002
D Long date jeudi 26 septembre 2002
t Short Hour 16:49
T Long Hour 16:49:31
f Date and hour jeudi 26 septembre 2002 16:50
F Long Date and hour jeudi 26 septembre 2002 16:50:51
g Default Date 26/09/2002 16:52
G Long default Date and hour 26/09/2009 16:52:12
M Month Symbol 26 septembre
r Date string RFC1123 Sat, 26 Sep 2009 16:54:50 GMT
s Sortable string date 2009-09-26T16:55:58
u Sortable string date universal local hour 2009-09-26 16:56:49Z
U Sortable string date universal GMT hour samedi 26 septembre 2009 14:57:22 (oups)
Y Year symbol septembre 2002
Spécificator Type Example Output Example
dd Jour {0:dd} 10
ddd Name of the day {0:ddd} Jeu.
dddd Complet name of the day {0:dddd} Jeudi
f, ff, … Fractions of seconds {0:fff} 932
gg, … position {0:gg} ap. J.-C.
hh Hour two digits {0:hh} 10
HH Hour two digits (24 hours) {0:HH} 22
mm Minuts 00-59 {0:mm} 38
MM Month 01-12 {0:MM} 12
MMM Month shortcut {0:MMM} Sep.
MMMM complet name of the month {0:MMMM} Septembre
ss Seconds 00-59 {0:ss} 46
tt AM or PM {0:tt} ““
yy Years, 2 digits {0:yy} 02
yyyy Years {0:yyyy} 2002
zz Time zone, 2 digits {0:zz} +02
zzz Complete Time zone {0:zzz} +02:00
: Separator {0:hh:mm:ss} 10:43:20
/ Separator {0:dd/MM/yyyy} 10/12/2002
Instead of using string interpolation you could simply format the DateTime using the ToString("u") method and concatenate that with the rest of the string:
$startTime = Get-Date
Write-Host "The script was started " + $startTime.ToString("u")