Tweet

What Week Is It ?

Scott Penrose

So you have your user group meeting on the 2nd Wednesday of the month, and you want to work out what week and day of the month that day falls on.

Modules

There are literally a dozen modules that can help you with this. The ones I'll cover here can all be found on http://datetime.perl.org/.

The Code

	#!/usr/bin/perl
	use strict;
	use DateTime;

	my ($day, $week) = @ARGV;

	my $dt = DateTime->today->set(day => 1);
	$dt->add(
		days => ( $day - $dt->day_of_week + 7 ) % 7,
		weeks => $week - 1,
	);

	print $dt->day . "\n";

Let us say that you are trying to work out the second Wednesday of the month. To do that you will need to pass two arguments in on the command line: the number 3 (where Monday = 1, Tuesday = 2, Wednesday = 3, etc), and the number 2 (representing the 2nd Wednesday of the month).

So if you were to save the code above in a file called week.pl, and run it as follows:

    week.pl 3 2

the output would be something like:

    13

Or you can change $day and $week manually...

	my $day = 3;
	my $week = 2;

What is happening

Let us look at what is happening.

"use *"

	use strict;

We tend to start our code with "use strict".

	use DateTime;

This is the primary DateTime module, and one that contains most of the code. You will need to install this as it is not yet standard Perl. datetime.perl.org is fast becoming the standard in all things date, time and Perl and I would strongly recommend you visit the site.

Start of the month

	my $dt = DateTime->today->set(day => 1);

You could easily break this down into stages,

	my $dt = DateTime->today();
	my $newdt = $dt->clone;
	$newdt->set(day => 1);

but there is no advantage in doing it that way.

I'm demonstrating two principals in this example:

1) Avoid temporary variables. You can see this further down when I get the day of the week from the first day of the month.

2) If you are not going to check the error results from each return, then don't try and do things in stages that you do not need to. This also demonstrates one of the great advantages of this style OO.

What is that day ?

	$dt->add(
		days => ( $day - $dt->day_of_week + 7 ) % 7,
		weeks => $week - 1,
	);

We are going to take the first day of the month and add to it the number of weeks away our event is, plus the number of days away.

The End

And there you have it. In 12 lines of code, including spaces you can work out complicated references such as the 3rd Wednesday of the Month.

If you want to do more complicated things with events, then rather than extending the sample code above, consider modules like DateTime::Event::ICal, where you can do what we did above for the whole year in the same amount of code.

	#!/usr/bin/perl
	use strict;
	use DateTime::Event::ICal;
	my $dt = DateTime->today();
	my $set = DateTime::Event::ICal->recur(
		dtstart => $dt,
		freq => 'monthly',
		byday => '2we',
		count => 10,
	)->iterator();
	while (my $next = $set->next) {
		print $next->day . " " . $next->month_name . "\n";
	}

The code above shows the day and month of the next 10 events.

    13 October
    10 November
    8 December
    12 January
    9 February
    9 March
    13 April
    11 May
    8 June
    13 July

Reference

There are many examples of this style of date manipulation on the web. This example comes from my own code but originally

See also

    DateTime-0.22
    datetime.perl.org

Scott Penrose

[Top]