Code:
#!/usr/bin/perl
use POSIX;
my $cmdstr="%Y-%m-%d %H:%M:%S";
my ($input, $arg, $sign)=(undef, undef, 0);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime();
# Commandline parsing stuff
while(defined($arg=shift)) {
if($arg =~ /^--date=/) { $input=substr($arg, 7); }
elsif($arg =~ /^-d$/) { $input=shift; }
elsif($arg =~/^\+/) { $cmdstr=substr($arg,1); }
else { print STDERR "unknown $arg\n"; }
}
# Put the date string back into argv, split on spaces
unshift(@ARGV, split(/[ \t]+/, $input));
while(defined($arg=shift))
{
# Need to split +1 into +1
if($arg =~ /^[+]/) { $sign=1; $arg=substr($arg,1); }
elsif($arg =~ /^-/) { $sign=-1; $arg=substr($arg,1); }
################## DATE FORMAT DETECTION ########################
# @1234 means seconds in epoch time
if($arg =~ /^@[0-9]+$/)
{
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($1+0);
next;
}
# Checks for YYYYMMDD or YYYY/MM/DD time
# TODO: Check for YYMMDD dates
# TODO: Check for YYYYDDMM dates (ugh)
if($arg =~ /^([0-9]{4})(\/?)([0-9]{2})\2([0-9]{2})/)
{
($year,$mon,$mday)=($1-1900,$3-1,$4+0);
($sec,$min,$hour)=(0,0,0);
next;
}
# HH:MM:SS times
if($arg =~ /([0-2][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?$/)
{
($sec,$min,$hour)=($3+0, $2+0, $1+0);
next;
}
# As last resort, assume its a pure number.
if($arg =~ /^([0-9]+)$/) {
if($sign == 0)
{
print STDERR "offset without unit";
exit(1);
}
$offset=$1+0;
next;
}
if($arg =~ /^seconds?$/) { }
elsif ($arg =~ /^years?$/) {
$year += ($offset*$sign);
$sign=0;
$offset=0;
}
elsif($arg =~ /^minutes?$/) { $offset *= 60; }
elsif($arg =~ /^hours?/) { $offset *= 60*60; }
elsif($arg =~ /^days?/) { $offset *= 60*60*24; }
elsif($arg =~ /^weeks?/) { $offset *= 60*60*24*7; }
elsif($arg =~ /^months?$/) {
$mon += ($offset*$sign);
while($mon > 12)
{
$mon-=12;
$year++;
}
while($mon < 0)
{
$mon+=12;
$year--;
}
$sign=0;
$offset=0;
}
elsif($arg =~ /^now$/) {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime();
}
elsif(length($arg) == 0){ } # Empty string? Ignore
else {
print STDERR "Unknown argument $arg\n";
exit(1);
}
}
# Convert the altered year, month, etc back into epoch time.
my $ref=mktime($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
# Add the seconds offset calculated above.
$ref += ($sign * $offset);
# Convert back into list.
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($ref);
print strftime($cmdstr."\n",
$sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);