Perl: Calculate time difference in human readable way

Perl function to return a human readable string for a time difference in seconds.

my $str = human_time_diff(320);  # "5 minutes"
my $str = human_time_diff(3700); # "1 hour"
sub human_time_diff {
    my $seconds = int(shift());
    my $num     = 0;
    my $unit    = "";
    my $ret     = "";

    if ($seconds < 300) {
        $ret = "just now";
    } elsif ($seconds < 3600) {
        $num  = int($seconds / 60);
        $unit = "minute";
    } elsif ($seconds < 86400) {
        $num  = int($seconds / 3600);
        $unit = "hour";
    } elsif ($seconds < 86400 * 30) {
        $num  = int($seconds / 86400);
        $unit = "day";
    } elsif ($seconds < (86400 * 365)) {
        $num  = int($seconds / (86400 * 30));
        $unit = "month";
    } else {
        $num  = int($seconds / (86400 * 365));
        $unit = "year";
    }

    if ($num > 1) { $unit .= "s"; }
    if ($unit) { $ret = "$num $unit"; }

    return $ret;
}

See also: PHP version

Leave A Reply

PHP: Calculate time difference in human readable way

function human_time_diff(int $seconds) {
    $num  = 0;
    $unit = "";

    if ($seconds < 300) {
        $ret = "just now";
    } elseif ($seconds < 3600) {
        $num  = intval($seconds / 60);
        $unit = "minute";
    } elseif ($seconds < 86400) {
        $num  = intval($seconds / 3600);
        $unit = "hour";
    } elseif ($seconds < 86400 * 30) {
        $num  = intval($seconds / 86400);
        $unit = "day";
    } elseif ($seconds < (86400 * 365)) {
        $num  = intval($seconds / (86400 * 30));
        $unit = "month";
    } else {
        $num  = intval($seconds / (86400 * 365));
        $unit = "year";
    }

    if ($num > 1) {
        $unit .= "s";
    }

    if ($unit) {
        $ret = "$num $unit";
    }

    return $ret;
}

See also: Perl version

Leave A Reply

Perl: Convert a date string to unixtime

It's common to come across date strings in log files that you want to convert to a Unixtime. Perl has Data::Parse which offers a str2time() function to do this.

use Date::Parse;

my $ut = str2time("Thu, 13 Oct 94 10:13:13 +0700") # 782017993;

I wrote a version of strtotime() in a function that may be more portable. It has the limitation that it does not support timezone strings, but if you don't need them then it is a valid alternative.

Leave A Reply

Perl: Extract a column from a hashref

I have an array full of hash references and I need to extract a column and build an array from that.

my @x = ( {'ip' => '127.0.0.1'}, {'ip' => '10.10.10.10'}, {'ip' => '192.168.5.6'} );
my @y = hash_column('ip', @x); # ["127.0.0.1", "10.10.10.10", "192.168.5.6"]
sub hash_column {
    my $col = shift();
    my @arr = @_;

    my @ret;
    foreach my $x (@arr) {
        push(@ret, $x->{$col});
    }

    return @ret;
}
Leave A Reply

Perl: Find the longest string in an array

I need a Perl way to find the maximum string length in an array so here is a function to do that:

my @words = qw(Apple Pear Watermelon Banana Cherry);
my $max   = max_length(@words); # 10
sub max_length {
    my $max = 0;

    foreach my $item (@_) {
        my $len = length($item);
        if ($len > $max) {
            $max = $len;
        }
    }

    return $max;
}
Leave A Reply

Telling time using words

Inspired by Qlock I designed an HTML5 version to show you the time using words.

Leave A Reply

PHP: Determine if an IP address is part of a given subnet

Given an IP address I need to determine if it is part of a subnet for whitelist/blacklist purposes.

$allowed = ip_in_subnet('65.182.224.40','65.182.224.0/24');
// Borrowed from http://php.net/manual/en/function.ip2long.php#82397
function ip_in_subnet($ip, $cidr) {
    list ($net, $mask) = explode ('/', $cidr);
    return (ip2long ($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net);
}

I also ported this function to Perl:

sub ip_in_subnet {
    my ($ip, $cidr)  = @_;
    my ($net, $mask) = split('/', $cidr);

    my $ret = (ip2long ($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net);

    return int($ret);
}

Note: You will need the ip2long function.

Leave A Reply

Perl: Read a text file backwards by lines

I needed to read through a log file looking for certain entries backwards (newest entries first). Perl has a File::ReadBackwards module that does exactly this:

use File::ReadBackwards;

my $file = "/var/log/message";
my $fh   = File::ReadBackwards->new($file) or die "can't read $file";

while (my $line = $fh->readline()) {
    print $line;
}
Leave A Reply

Perl: array_chunk() to split arrays into smaller chunks

I have an large array in Perl that I need in smaller chunks to make iteration easier. I borrowed a concept from PHP and implemented array_chunk() in Perl.

my @orig = qw(foo bar baz one two three red yellow green donk);
my @new  = array_chunk(3, @orig);
sub array_chunk {
    my ($num, @arr) = @_;
    my @ret;

    while (@arr) {
        push(@ret, [splice @arr, 0, $num]);
    }

    return @ret;
}
Leave A Reply

List of The Dresden Files books

Quick list of the The Dresden Files books.

Number Title Paperback release date
1 Storm Front April 1, 2000
2 Fool Moon January 1, 2001
3 Grave Peril September 1, 2001
4 Summer Knight September 3, 2002
5 Death Masks August 5, 2003
6 Blood Rites August 2, 2004
7 Dead Beat May 2, 2006
8 Proven Guilty February 6, 2007
9 White Night February 5, 2008
10 Small Favor May 3, 2009
11 Turn Coat March 3, 2010
12 Changes March 11, 2011
13 Ghost Story August 7, 2012
14 Cold Days September 3, 2013
15 Skin Game March 5, 2015
16 Peace Talks July 14, 2020
17 Battle Ground September 29, 2020
Leave A Reply

Console release dates

Nintendo

System NA Release Years between
NES 1985-10-18
SNES 1991-08-23 5.8
N64 1996-09-29 5.1
Gamecube 2001-11-18 5.1
Wii 2006-11-19 5.0
WiiU 2012-11-18 5.9
Switch 2017-03-03 4.3

Microsoft

System NA Release Years between
Xbox 2001-11-15
360 2005-11-22 4.0
XB1 2013-11-22 8.0
XBSX 2020-11-10 6.9

Sony

System NA Release Years between
PS1 1995-09-09
PS2 2000-10-26 5.1
PS3 2006-11-17 6.0
PS4 2013-11-15 6.9
PS5 2020-11-12 6.9
Leave A Reply

Perl: Natural sort part deux

If you want to sort an array naturally (the way a human would) you can use Perl's sort() function, but use a custom sort method:

my @input  = qw(foo foo250 foo12 foo23 bar999 bar7 bar17 bar99 18);
my @sorted = sort { &natural } @input;

print join(", ", @sorted);
sub natural {
    # Separate the word and numeric parts
    my ($word_a, $num_a) = $a =~ /(.*?)(\d+|$)/;
    my ($word_b, $num_b) = $b =~ /(.*?)(\d+|$)/;

    #print "$a / $b: $word_a, $num_a, $word_b, $num_b\n";

    # If the words are diff it's an alpha sort on the words
    if ($word_a ne $word_b) {
        return $word_a cmp $word_b;
    # Words are the same, numeric sort the number part
    } else {
        return ($num_a || 0) <=> ($num_b || 0);
    }
}

See also: Natural Sort

Leave A Reply

Perl: Simple .ini parser

I wrote a simple .ini parsing function in Perl.

my $hash_ref = parse_ini("/tmp/config.ini");
sub parse_ini {
    open (my $INI, "<", $_[0]) or return undef;

    my $ret     = {};
    my $section = "_";

    while (my $line = readline($INI)) {
        if ($line =~ /^\[(.+?)\]/) { # Section heading
            $section = $1;
        } elsif ($line =~ /^(\w.*?)\s*=\s*"?(.*?)"?\s*$/) { # Key/Value pair
            $ret->{$section}->{$1} = $2;
        }
    }

    return $ret;
}
Leave A Reply

PHP: Serve file for download

If you want to a simple way to serve a file for download in PHP you can use this function:

function serve_file($filepath) {
    $filename = basename($filepath);

    if (headers_sent()) {
        die("Cannot output file because output already started");
    }

    $mime_type = mime_content_type($filepath);
    header("Content-type: $mime_type");
    header("Content-Disposition: attachment; filename=\"$filename\"");

    readfile($filepath);

    exit(0);
}
Leave A Reply

Perl: Loop through an array and extract pairs of variables

I had an array that I wanted to iterate through and extract pairs of variables. I found this pretty neat way to do that:

Perl:

my @arr = ("red", "green", "blue", "yellow", "orange", "purple");

while (@arr) {
    my ($x, $y) = splice(@arr, 0, 2);
    print "$x:$y\n";
}

I found a bunch of different ways to do this, and benchmarked them.

PHP:

$arr = ["red", "green", "blue", "yellow", "orange", "purple"];

while ($arr) {
    [$x, $y] = array_splice($arr, 0, 2);
    print "$x:$y<br />";
}

Note: You need to be careful you have an even number of elements or you will get undefined variable errors.

Leave A Reply