Date/Time operations

Since I am not very fanatic of software homogeneity, when I write perl scripts and I need some function that performs certain task I use commands from console whenever it’s available even knowing that could be an equivalent Perl module available out there.

When your main goal is to get things done in the least amount of time, you cannot afford the time wasted in searching a library/module when the tools are just as far as calling a external program. This doesn’t mean that your code has to look horrible, it means that there’s no need to search for a (long) piece of code to attach it to yours in order to make your program homogeneous. After all, if you know how to write clean code, you will do it even if you mix 2323423423 languages inside your perl script.

Date/Time arithmetic using Perl.

I am aware of the existence of DateTime.pm but I have no experience using it. This was not the case with date command which finally led me to skip the learning curve and pass directly to the coding job.

The problem.

From a CDR entry containing end-datetime and duration, calculate the start-time, and transform the output using the YYMMDD/HHMMSS format.

[perl]

use strict;
use warnings;

sub main()
{
my $startTime = “02/01/2011 12:02:00”;
my $secs = 3650;

print “$startTime – $secs secs (YYMMDD HHMMSS) = @{ [ CalculateDate(“$startTime”, $secs) ] }”;
print “$secs secs in HHMMSS format is = @{ [ FormatTime($secs) ] } n”;
}

sub CalculateDate($$)
{
my ($date, $secs) = @_;

$date = FormatDateTime(`date –date “$date $secs seconds ago”`);

return $date;
}

sub FormatDateTime($)
{
return `date –date “$_[0]” +”%y%m%d %H%M%S”`;
}

sub FormatTime($)
{
my ($seconds, $hours, $mins, $secs) = shift;

$hours = padLeft(int($seconds / 3600));

$mins = padLeft($hours == 0 ? int($seconds / 60) : int(($seconds – ($hours * 3600)) / 60));

$secs = padLeft($hours == 0 && $mins == 0 ? $seconds : $seconds % 60);

return “$hours$mins$secs”;
}

sub padLeft($)
{
my $value = shift;
return (length “$value” == 1) ? “0$value” : $value;
}

main();
[/perl]

And the output is

[bash]
$ perl convert.pl
02/01/2011 12:02:00 – 3650 secs (YYMMDD HHMMSS) = 110201 110110
3650 secs in HHMMSS format is = 010050
[/bash]

Now, what I did not found searching the web was an easy method to convert seconds to a hour:minute:second format. This forced me to write my own algorithm which, hopefully, is bug free 😀
[perl]
sub FormatTime($)
{
my ($seconds, $hours, $mins, $secs) = shift;

$hours = padLeft(int($seconds / 3600));
$mins = padLeft($hours == 0 ? int($seconds / 60) : int(($seconds – ($hours * 3600)) / 60));
$secs = padLeft($hours == 0 && $mins == 0 ? $seconds : $seconds % 60);
return “$hours$mins$secs”;
}
[/perl]

What would a portability freak say?

It would probably say that my solution ignores the portability features of Perl. Yes, it is true but I don’t really care since my target is, and will always be, Unix based machines.

 

Merging PDF files with Linux

Almost everything I write here is related to problems I face daily and this time I came with something new and not very common :D.

A client of mine asked me to find a solution which allow him to combine several PDFs files into a single one without the “complicated” steps of Windows software. I think there is no free solution to do that and the one I know, Adobe Reader, comes with this feature only with paid licence.

The physical scenario involve a Linux file server reachable by a network of Windows machines acting as SMB/CIFS clients and the procedure to merge the files looks like the following:

– The file server shares, with read/write permissions, a directory (folder) called zip2pdf.
– If a user wants to combine a series of files he just need to zip the files and copy the compressed file into the shared directory.
– After a certain time, proportional to the size of the documents to be merged, a PDF file will “appear” in the shared directory containing the PDFs combined.

How I did this?

– I used a filesystem watcher which notifies me every change on a target directory, in my case, file creation.
– I unzipped the file, sorted the output and merged the PDFs with ghostscript.
– I put it all in a bash script and ran it in background.

[bash]
#!/bin/bash
inotifywait –monitor –event CREATE –format “%w%f” $1 | while read file
do
MATCH=`echo $file | grep -P “.zip$”`
if [ “$MATCH”!=”” ] && [ -e $file ];
then
sleep 3 # wait an arbitrary value to “ensure” the file was closed.
# There are another ways to check it using lsof for instance,
# but it would complicate the script a lot

STAMP=`date +”%Y-%m-%d_%N”`
DIR=”uncompressed_$STAMP/”

mkdir -p $DIR

unzip $file -d $DIR

FILES=`find $DIR -type f -iname *.PDF | sort`
#echo “LIST: $FILES”
gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=$STAMP.pdf -dBATCH $FILES

mv $STAMP.pdf $1
rm -rf $DIR
else
echo NOOOOOOOOOOO
fi
done
[/bash]

[bash]
$ ./z2p.sh /home/carlos/Desktop/zip2pdf/
[/bash]

It works and it was pretty simple 😀