#!/usr/bin/perl # # Copyright 2009 Abhijit Menon-Sen # Use, modification, and distribution of this code is allowed without # any limitations. There is no warranty, express or implied. use POSIX; sub is_leap { my ($y) = @_; return ($y % 4) == 0 && (($y % 100) != 0 || ($y % 400) == 0); } my $year = $ARGV[0] || 1900+(localtime)[5]; my $first = (localtime(mktime(1,0,0,1,0,$year-1900)))[6]; my ($nowd,$nowm,$nowy) = (localtime)[3,4,5]; $nowy += 1900; my @months = ( ["January", 31], ["February", is_leap($year) ? 29 : 28 ], ["March", 31], ["April", 30], ["May", 31], ["June", 30], ["July", 31], ["August", 31], ["September", 30], ["October", 31], ["November", 30], ["December", 31] ); my @days = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday); # We'll step through every day in the year, figuring out what day of the # week it is (and keeping track of which month we're in), and record the # results in @w. my $d = 1; my $sum = 0; my $month = 0; my $ydays = 337+$months[1]->[1]; my @w; while ( $d <= $ydays ) { my $w = ($d-1+$first)%7; push @w, [ $d-$sum, $w ]; $d++; # (Are we past the end of the current month?) my $mdays = $months[$month]->[1]; if ( $d-$sum > $mdays ) { $sum += $mdays; $month++; } } # And now for the messy details of formatting the output. # # We'll extract each month's dates from @w, find the first weekend in # the month, and use that to align the output: if the first day of the # month is a Sunday, then the first full weekend would be in column 6; # and that's the furthest right it can go, so we always put it there. my $i = 0; while ( @w ) { my @row; my $firstw; my @r = splice( @w, 0, $months[$i]->[1] ); my $j = 0; foreach ( @r ) { my ($v, $w) = @$_; # Record the position of the first full weekend in the month. if ( !defined $firstw && $w == 6 && $r[$j+1]->[1] == 0 ) { $firstw = $j; } $v = sprintf "%2d", $v; # Today's date is green. if ( $year == $nowy && $i == $nowm && $_->[0] == $nowd ) { $v =~ s/^(.*)$/\x1B[32m$1\x1B[39m/; } # Weekend dates are red. if ( $w == 0 || $w == 6 ) { $v =~ s/^(.*)$/\x1B[31m$1\x1B[39m/; } push @row, $v; $j++; } unshift( @row, " " ) for 1..6-$firstw; print join( " ", @row ); print "\n"; $i++; }