Quick Learn – Get All 13 Months in a Year

I started a little, pet project recently and it’s all based around how I store my pictures and video files. I have a base directory – C:\Users\tommymaynard\Documents\Media – that contains a subdirectory for each year: 2012, 2013, etc. Inside each of those, I have 12 other directories – one for each month. These each use the naming convention 01 – January, 02 – February, etc. Inside each of those directories, I have at least two other directories: pictures and videos. Here’s an image that may help this structure make more sense.

Get All 13 Months in a Year01

I don’t always sort my photos and videos right away. Instead, I’ll often procrastinate and just drop them into a ‘Pics to Sort’ folder on my desktop – that’s literally the directory’s name. I wondered if I would procrastinate any less, if I had Windows PowerShell build out the desired directory structure for me each year. As an aside, if you consider that I always add my pictures and videos to the same I’ll-sort-you-later directory, then I could easily build a solution to do the sorting, based on file extension and creation date, from this directory into the proper subdirectories in the media directory. I’ll save this one for another day, but thanks for thinking of it.

For this Quick Learn, let’s only concern ourselves with capturing the month’s names. While I could have created a hard-coded array of the month names, I decided to see what I could get return using Get-Date – not what I wanted. I could return the current month’s name using Get-Date -Format MMMM, or the current month’s numeric representation using Get-Date | Select-Object Month, but neither of these return all of the months. The system knows the names of the months and so I opted to look for a .NET way to get them.

So, here it is, the System.Globalization.DateTimeFormatInfo .NET class. When you enter this as the value of the New-Object’s -TypeName parameter, it will return a great deal of information, to include a property called MonthNames. In the example below, you can see the code used to store the month names in a variable. You would think I would be done here, but I wasn’t.

PS C:\> $MonthNames = (New-Object System.Globalization.DateTimeFormatInfo).MonthNames
PS C:\> $MonthNames
January
February
March
April
May
June
July
August
September
October
November
December

PS C:\>

Instead of creating directories, like my project does, the example below simply echos the month’s numeric value, a space-dash-space, and then the month’s name. I’ve added a for statement example as well, just in case someone were to wonder why I didn’t include one, since I was incrementing a counter variable and knew how many looping iterations I had to do.

PS C:\> $i = 1
PS C:\> $MonthNames | foreach {Write-Output "$i - $_";$i++}
1 - January
2 - February
3 - March
4 - April
5 - May
6 - June
7 - July
8 - August
9 - September
10 - October
11 - November
12 - December
13 -
PS C:\>
PS C:\> for ($i=1; $i -le $MonthNames.Count; $i++) {echo "$i - $($MonthNames[$i-1])"}
1 - January
2 - February
3 - March
4 - April
5 - May
6 - June
7 - July
8 - August
9 - September
10 - October
11 - November
12 - December
13 -
PS C:\>

Based on these results, the MonthNames property has a thirteenth entry, and that’s a problem, since there’s no thirteenth month. I proved to myself that there was a problem a couple different ways, as seen below. Remember that the first index, or element, of an array is index zero, making January $MonthNames[0] and December $MonthNames[11].

PS C:\> $MonthNames.Count
13
PS C:\> $MonthNames[0]
January
PS C:\> $MonthNames[11]
December
PS C:\> $MonthNames[12]

PS C:\> $MonthNames[13]
PS C:\>

I needed to ensure this extra, blank month wasn’t making its way into my code. While I could have done my filtering when I was actually creating new directories, it is a better practice to only store what I need, and to only store what’s correct. As can be seen below, I only returned twelve months by adding a pipeline and some filtering.

PS C:\> $MonthNames = (New-Object System.Globalization.DateTimeFormatInfo).MonthNames | Where-Object -FilterScript {$_ -notlike ''}
PS C:\> $MonthNames
January
February
March
April
May
June
July
August
September
October
November
December
PS C:\> $MonthNames.Count
12

Since I was already here, I checked out another property. DayNames didn’t have a blank entry, and had I needed to use it, I wouldn’t have had to do any filtering on the returned results – something I incorrectly assumed about MonthNames. Hope this is helpful to someone, and thank you for reading this post.

PS C:\> $DayNames = (New-Object System.Globalization.DateTimeFormatInfo).DayNames
PS C:\> $DayNames
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
PS C:\> $DayNames.Count
7
PS C:\>

One thought on “Quick Learn – Get All 13 Months in a Year

  1. Dirk

    Hi Tommy,

    thanks for sharing, I never came across that one but it will definitely same me some time in case I do. “Googling” a bit around I found that this is done for the purpose of consistency accounting for the fact that in some calendars (like Hebrew) there are years with 13 months (like in Gregorian 2014):
    $cal = New-Object Globalization.HebrewCalendar
    $cal.GetMonthsInYear($cal.GetYear((Get-Date -Year 2014)))

    Reply

Leave a Reply

Your email address will not be published.