Broad Network


Arbitrary Date and Date Formatting in Perl

Date and Time in Perl – Part 3

Perl Course

Foreword: In this part of the series, I explain how to code an arbitrary date in Perl and how to format date-time.

By: Chrysanthus Date Published: 5 Nov 2015

Introduction

This is part 3 of my series, Date and Time in Perl. In this part of the series, I explain how to code an arbitrary date in Perl and how to format date-time. You should have read the previous parts of the series before coming here, as this is a continuation.

Arbitrary Date

In one of the previous parts of the series, I talked about localtime and GMT time all generated from the computer or server. Imagine that you are narrating a story and you have to quote a time. I answer that below.

Remember, in Perl, date and/or time is referred to, just as, Time. I use the complete time for illustration in this tutorial. In this part of the series I explain how to create and use your own time class and corresponding instantiated object.

A Time Class
I use the following properties, with the same meanings as they have in the previous part of the series: sec, min, hour, mday, mon, year, wday, yday, and isdst. The class is:


    {package Time;

        #constructor
        sub new
            {
                my $class = $_[0];

                $self->{'sec'} = $_[1];
                $self->{'min'} = $_[2];
                $self->{'hour'} = $_[3];
                $self->{'mday'} = $_[4];
                $self->{'mon'} = $_[5];
                $self->{'year'} = $_[6];
                $self->{'wday'} = $_[7];
                $self->{'yday'} = $_[8];
                $self->{'isdst'} = $_[9];

                bless {}, $class;
            }

        #methods
        sub sec
            {
                return $_[0]->{'sec'};
            }

        sub min
            {
                return $_[0]->{'min'};
            }

        sub hour
            {
                return $_[0]->{'hour'};
            }

        sub  mday
            {
                return $_[0]->{'mday'};
            }

        sub mon
            {
                return $_[0]->{'mon'};
            }

        sub year
            {
                return $_[0]->{'year'};
            }

        sub wday
            {
                return $_[0]->{'wday'};
            }

        sub  yday
            {
                return $_[0]->{'yday'};
            }

        sub isdst
            {
                return $_[0]->{'isdst'};
            }

    }


A class is a package. It has a hash. The reference to the hash is held in the variable, $self. In Perl, you can create an empty hash and add in the key/value pairs later. The hash holds the properties of the class.

When the constructor method is called, the first argument is the name of the class, in this case, Time. It is copied to the variable, $class. After the first statement in the constructor method, you have the initialization of the properties of the class instance. Remember, the constructor is only called, when you want an instance (object) of the class. In this case, initialization, is giving values to the keys of the hash. Actually, the keys and values are created at the same time, in this case.

The names of the properties are the keys of the hash whose reference is held in $self. Note that the property name is not preceded by a $ symbol. Also, if you input year as the normal four digits, you would have the normal four digits returned. Each method returns the value that is inputted of the key/value pair in the hash.

The last statement of a Perl function (method or subroutine) returns its result. The last statement of the constructor method should be the bless statement. It is this statement that effectively instantiates the class, after the values of the hash keys have been assigned. It does so by returning a reference to the hash created. It also relates the hash created with the class description (definition). The class description in this case is the description of the package called, Time.

Instantiating the Class
A statement to instantiate the class can be:

    my $myTime = Time->new(10, 59, 17, 22, 1, 2013, 5, 52, 0);

The values of the time components are the arguments of the constructor method, new(). In the argument list, you can type the single digit values, preceded by zero, if you like. The reference of the hash created in the constructor method is now held in the variable, $myTime.

In my writings, I prefer to use the phrase “instantiated object” to “instantiated class”, in order to differentiate instantiated classes from fundamental objects, like integers.

Using the Class and Object
In the following code, the first segment reads the values of the Time class properties by calling the methods, and the second segment displays the values.

    my $sec = $myTime->sec();
    my $min = $myTime->min();
    my $hour = $myTime->hour();
    my $mday = $myTime->mday();
    my $mon = $myTime->mon();
    my $year = $myTime->year();
    my $wday = $myTime->wday();
    my $yday = $myTime->yday();
    my $isdst = $myTime->isdst();

    print $sec . "\n";
    print $min . "\n";
    print $hour . "\n";
    print $mday . "\n";
    print $mon . "\n";
    print $year . "\n";
    print $wday . "\n";
    print $yday . "\n";
    print $isdst . "\n";

Remark
The procedure outlined above defines a class and instantiates it for an arbitrary time or time you imagine. It is not local time or GMT time. Local time is time read from the computer. GMT time is time read from the computer and adjusted by the time zone difference, relative to the time in Britain. This adjustment is done automatically by the computer.

Complete Code
The complete code for the above program is:

use strict;

    {package Time;

        #constructor
        sub new
            {
                my $self = {};
                my $class = $_[0];

                $self->{'sec'} = $_[1];
                $self->{'min'} = $_[2];
                $self->{'hour'} = $_[3];
                $self->{'mday'} = $_[4];
                $self->{'mon'} = $_[5];
                $self->{'year'} = $_[6];
                $self->{'wday'} = $_[7];
                $self->{'yday'} = $_[8];
                $self->{'isdst'} = $_[9];

                bless $self, $class;
            }

        #methods
        sub sec
            {
                return $_[0]->{'sec'};
            }

        sub min
            {
                return $_[0]->{'min'};
            }

        sub hour
            {
                return $_[0]->{'hour'};
            }

        sub  mday
            {
                return $_[0]->{'mday'};
            }

        sub mon
            {
                return $_[0]->{'mon'};
            }

        sub year
            {
                return $_[0]->{'year'};
            }

        sub wday
            {
                return $_[0]->{'wday'};
            }

        sub  yday
            {
                return $_[0]->{'yday'};
            }

        sub isdst
            {
                return $_[0]->{'isdst'};
            }

    }

    my $myTime = Time->new(10, 59, 17, 22, 1, 2013, 5, 52, 0);

    my $sec = $myTime->sec();
    my $min = $myTime->min();
    my $hour = $myTime->hour();
    my $mday = $myTime->mday();
    my $mon = $myTime->mon();
    my $year = $myTime->year();
    my $wday = $myTime->wday();
    my $yday = $myTime->yday();
    my $isdst = $myTime->isdst();

    print $sec . "\n";
    print $min . "\n";
    print $hour . "\n";
    print $mday . "\n";
    print $mon . "\n";
    print $year . "\n";
    print $wday . "\n";
    print $yday . "\n";
    print $isdst . "\n";

Formatting Time
Remember, date and/or time in Perl is simply, Time. Below, I explain how to precede a single digit time component with zero and how to have words or abbreviations in place of month numbers and day numbers of the week, in a Perl time string. The number for the day of the month and the month of the year and the hour , minute or second is normally one digit if it is less than 10. Under this condition, it is fashionable to present the number as two digits, the actual digit preceded by zero. The second, minute, hour, day of the week, day of the month, month and year are each a time component. You should have read the previous parts of this series as this is a continuation.

Strategy
Before, I explained how to produce a Perl time string consisting of only figures (in character forms). To achieve the aim of this section, you would have to use the same code. However, you will have to use the if-construct to precede the single digits with zero and you will have to have arrays with names or abbreviations of months and days of the week. The words in an array correspond to numbers of a particular time component.

So, as soon as the gmtime or localtime object reads the time components, for the components of interest, an if-construct will check if the value is less than 10. If it is, the construct precedes the value with zero, resulting in a string of two characters. To replace a number with a word in a time string, you need arrays with words corresponding to the possible values of the components; one array for one component.

The gmtime and localtime objects are handled in the same way, so I will use only the localtime object for illustration in this tutorial.

Preceding Single Digits
Time components are the object properties. The properties are: sec, min, hour, mday, mon, year, wday, yday, and isdst. The meanings of theses properties where given in the previous part of the series. The value of isdst is 1 or 0 and indicates if the daylight saving scheme is in effect. The value of this property is not used in this tutorial.

The properties of interest, whose values can have single digits during display are: sec, min, hour, mday and mon. So you need five if-constructs. Read and try the following program, which displays the complete time in USA format:

use strict;

    use Time::localtime;
    my $locTim = localtime();

    my $sec = $locTim->sec();
    if ($sec < 10)
        {
            $sec = "0" . $sec;
        }
    my $min = $locTim->min();
    if ($min < 10)
        {
            $min = "0" . $min;
        }
    my $hour = $locTim->hour();
    if ($hour < 10)
        {
            $hour = "0" . $hour;
        }
    my $mday = $locTim->mday();
    if ($mday < 10)
        {
            $mday = "0" . $mday;
        }
    my $mon = $locTim->mon();
    my $localMonth = $mon + 1;
    if ($localMonth < 10)
        {
            $localMonth = "0" . $localMonth;
        }
    my $year = $locTim->year();
    my $localYear = $year + 1900;

    my $localTime = $localMonth . "-" . $mday . "-" . $localYear . " " . $hour . ":" . $min . ":" . $sec;

    print $localTime;

Note: with the string dot concatenation operator, if one operand is a number and the other is a string (or character) the result is a string, not a number. The statement that forms the overall string is:

    my $localTime = $localMonth . "-" . $mday . "-" . $localYear . " " . $hour . ":" . $min . ":" . $sec;

Note how the characters ‘–‘ and ‘:’ have been inserted. A space has also been inserted between the actual (conventional) date and the actual (conventional) time with " ".

Replacing Week Day and Month with Abbreviation
In the above code the day of the week e.g. Monday was not considered. There are times when you need to include it in a date and it is normally included as its full word or abbreviation. There are times when you want to include the month in full word or abbreviation. Whether you are including a date property value in full word or abbreviation, the technique is the same. In this tutorial I illustrate the technique only with abbreviations.

In the case of days of the week, the following array will do (suffices):

    my @week = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");

Array element counting begins from zero. In Perl the numbers are: 0, 1, 2, 3, 4, 5 and 6. Sunday is 0, Monday is 1, Tuesday is 2, etc. So the indices of the array just correspond to the Perl numbers of the days of the week. There is no need to add 1 to obtain the ordinary man’s day number of the week in the code.

In the case of months of the year, the following array suffices:

    my @mYear = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");

Again, array element counting begins from zero. In Perl the numbers are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 and 11. January is 0, February is 1, March is 2, etc. So the indices of the array just correspond to the Perl numbers of the months of the year. There is no need to add 1 to obtain the ordinary man’s month number of the year in the code.

An example of a complete local time format that the following program will produce is:

    Fri, 21 Nov 2013 9:55:13

The program is:

use strict;

    use Time::localtime;
    my $locTim = localtime();

    my $wday = $locTim->wday();
    my @week = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
    my $sec = $locTim->sec();
    if ($sec < 10)
        {
            $sec = "0" . $sec;
        }
    my $min = $locTim->min();
    if ($min < 10)
        {
            $min = "0" . $min;
        }
    my $hour = $locTim->hour();
    if ($hour < 10)
        {
            $hour = "0" . $hour;
        }
    my $mday = $locTim->mday();
    if ($mday < 10)
        {
            $mday = "0" . $mday;
        }
    my $mon = $locTim->mon();
    my @mYear = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
    my $year = $locTim->year();
    my $localYear = $year + 1900;

    my $localTime = $week[$wday] . ", " . $mday . " " . $mYear[$mon] . " " . $localYear . " " . $hour . ":" . $min . ":" . $sec;

    print $localTime;

Read and try the code if you have not already done so. The program produces the same format for GMT.

The statement that produces the string for the complete time is:

    my $localTime = $week[$wday] . ", " . $mday . " " . $mYear[$mon] . " " . $localYear . " " . $hour . ":" . $min . ":" . $sec;

In this statement, $week[$wday] is effectively something like, $week[2] where 2 is from $wday. Also, $mYear[$mon] is effectively something like, $mYear[3] where 3 is from $mon. The single space has been included by, " ". Comma is included by ", " and the colon is included by ":"

So, after obtaining the components from the instantiated object, you form a string by joining the bits (modified components) with the concatenating string dot operator.
Use of Forward Slash in Dates
You can have an American date like:

    08/25/2013

instead of

    08-25-2013

To have the forward slashes is simple, just replace ‘–‘ in the time string formation with ‘/’.

That is it for this part of the series. We stop here and continue in the next part.

Chrys

Related Links

Perl Basics
Perl Data Types
Perl Syntax
Perl References Optimized
Handling Files and Directories in Perl
Perl Function
Perl Package
Perl Object Oriented Programming
Perl Regular Expressions
Perl Operators
Perl Core Number Basics and Testing
Commonly Used Perl Predefined Functions
Line Oriented Operator and Here-doc
Handling Strings in Perl
Using Perl Arrays
Using Perl Hashes
Perl Multi-Dimensional Array
Date and Time in Perl
Perl Scoping
Namespace in Perl
Perl Eval Function
Writing a Perl Command Line Tool
Perl Insecurities and Prevention
Sending Email with Perl
Advanced Course
Miscellaneous Features in Perl
Perl Two-Dimensional Structures
Advanced Perl Regular Expressions
Designing and Using a Perl Module
More Related Links
Perl Mailsend
PurePerl MySQL API
Perl Course - Professional and Advanced
Major in Website Design
Web Development Course
Producing a Pure Perl Library
MySQL Course

BACK NEXT

Comments

Become the Writer's Fan
Send the Writer a Message