#!/usr/bin/perl -w use strict; use Time::Local; # Color bitmasks. use constant CURRENT_MONTH => 1; use constant CURRENT_DAY => CURRENT_MONTH | 2; # Color palette, indexed by bitmask. my @palette = ( "\e[90;40m", "\e[37;40m", # CURRENT_MONTH undef, "\e[30;47m", # CURRENT_DAY ); # Get midnight of previous day. We can't simply subtract 24 hours since # number of hours in each day might be different due to daylight savings. sub PreviousDay($) { my ($t) = @_; # Assuming that input timestamp is already aligned to midnight, # going back 12 hours is guaranteed to put us in the previous day. my ($sec, $min, $hour, $mday, $mon, $year) = localtime($t - 43200); return timelocal(0, 0, 0, $mday, $mon, $year); } # Get midnight of next day. sub NextDay($) { my ($t) = @_; my ($sec, $min, $hour, $mday, $mon, $year) = localtime($t + 86400 + 43200); return timelocal(0, 0, 0, $mday, $mon, $year); } # Get first Sunday on or before first day of month. sub GetMonthStart($) { my ($t) = @_; # Go back to first day of the month. my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($t); $t = timelocal(0, 0, 0, 1, $mon, $year); # Go back to first Sunday. for(;;) { ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($t); last if $wday == 0; $t = PreviousDay($t); } return $t; } # Decide how to color each day of the calendar. sub GetColors($$$) { my ($t, $current_month, $current_day) = @_; my @colors = (); for(my $day = 0; $day < 6 * 7; $day++) { my ($sec, $min, $hour, $mday, $mon) = localtime($t); my $bits = 0; if( $mon == $current_month ) { $bits = CURRENT_MONTH; if( $mday == $current_day ) { $bits = CURRENT_DAY; } } push @colors, $bits; $t = NextDay($t); } for(my $pad = 0; $pad < 7; $pad++) { push @colors, 0; } (scalar @colors) == 7 * 7 or die; return @colors; } # Draw month heading. sub Heading($$) { my ($year, $month) = @_; printf "\e[97;40m\e[4m %04d-%02d" . (" " x 26) . "\e[0m", $year, $month; } # Draw space between rows. sub OddRow($$) { my ($index, $colors) = @_; for(my $day = 0; $day < 7; $day++, $index++) { my $bits = $$colors[$index] | $$colors[($index + 6 * 7) % (7 * 7)]; print $palette[$bits], " " x 4; if( $day < 6 ) { print "\e[37;40m "; } else { print "\e[0m"; } } } # Draw date numbers. sub EvenRow($$$) { my ($t, $index, $colors) = @_; for(my $day = 0; $day < 7; $day++, $index++) { my $bits = $$colors[$index]; my ($sec, $min, $hour, $mday) = localtime($t); printf '%s %2d ', $palette[$bits], $mday; if( $day < 6 ) { print "\e[37;40m "; } else { print "\e[0m"; } $t = NextDay($t); } return $t; } my $now = time; my ($sec, $min, $hour, $current_day, $current_month, $current_year) = localtime($now); my $t = GetMonthStart($now); my @colors = GetColors($t, $current_month, $current_day); Heading($current_year + 1900, $current_month + 1); print "\n"; for(my $week = 0; $week < 6; $week++) { OddRow($week * 7, \@colors); print "\n"; $t = EvenRow($t, $week * 7, \@colors); print "\n"; } OddRow(6 * 7, \@colors); print "\n";