Don’t treat your date like just another number

There’s more than one type of date that can prove awkward, but this is Perl, and so I’m talking calendar dates. And when I say awkward, I mean the interpretation of how a date should be treated.

It’s very tempting when we see something like this, to think we can always get away with comparing dates as we see them.

10/12/1994
11/12/1994
01/01/1995
02/01/1995
01/01/1996

Surely, it’s a simple case of comparing by means of greater than / less than? That is to say, if we can do this…

#!/usr/bin/perl
use strict;
use warnings;

# if 4 is greater than 2 - which it is
if ( 4 > 2 ) {
  print "Four is greater than two" , "\n";
  }
    else {
      print "Four is not greater than two";
      }

Which, as you might expect, outputs…

Four is greater than two

… we can do something similar with a date?

# if 1995 comes before 1996 - which it does
if ( 01/01/1996 > 10/01/1995) {
  print "1996 is a later date than 1995 " , "\n";
  }
    else {
      print "Soemthing not quite right" , "\n";
      }

Which produces…

Something not quite right

The short answer is, we can’t treat these as dates… yet. We’re just treating them as strings or numbers, depending how you use the operator that is doing the comparing. And if we are treating them as numbers, we’re doing unwanted procedures with the / character, that is creating divisional calculations.

So, here’s something more robust.

#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
use feature 'say';

# create a date format - British style

my $format = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' );

# create a date to use to compare against what's in __DATA__

my $compare_date = DateTime->new(year   => 1994, 
                                 month  => 12, 
                                 day    => 31, 
                                 formatter => $format
                                 );
            
while (<DATA>) {
	chomp;
	my ($id,$name,$date_text) = split (/,/,$_);
	
	# set the text in data to Date objects
    my $date = $format->parse_datetime($date_text);
    
    # set the formatting style
    
    $date->set_formatter($format);
    $format = $date->formatter();
    
    # if 31/12/1994 is a later date than the string-to-date object
     
    if ( $compare_date > $date) {
		say "$id date $date comes before " . $compare_date;
	}
	
	# if 31/12/1994 is an earlier date than the string-to-date object
	  else {
		say "$id date $date comes after " . $compare_date;
	  }
}


close DATA;

__DATA__
ID1,bar,10/12/1994
ID2,baz,11/12/1994
ID3,foobar,01/01/1995
ID4,foobaz,02/01/1995
ID5,foofoo,01/01/1996

We create a formatting style for dates – date of month, month and year using DateTime::Format::Strptime and assign it to $format.

We set a date object $compare_date with DateTime. This is used to compare the dates parsed in __DATA__.

If we don’t set the format for $date (taken from $date_text in __DATA__) on lines 28 and 29, then $date will be output using ISO 8601 format.

The output is…

ID1 date 10/12/1994 comes before 31/12/1994
ID2 date 11/12/1994 comes before 31/12/1994
ID3 date 01/01/1995 comes after 31/12/1994
ID4 date 02/01/1995 comes after 31/12/1994
ID5 date 01/01/1996 comes after 31/12/1994

Until the next time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: