How To Convert Date To Unix Timestamp Without Using A Built In Function – Perl

For this tutorial, I will talk about how to convert a date string into a Unix Timestamp format. A Unix Timestamp is a time record of a particular time instance of how far that instance in milliseconds is away from the 0:0:0 of January 1st, 1970 in GMT+0 timezone. A positive timestamp is how far the time instance is after the 0:0:0 of January 1st time instance, 1970. A negative timestamp is how far the time instance is before the 0:0:0 of January 1st, 1970 time instance.

A Unix Timestamp consists of a whole number which represents seconds and three digits behind the decimal of which represents milliseconds. Most of us do not include millisecond into timestamp calculation. Thus the digits behind the decimal in a timestamp are usually removed. For the purpose of this demonstration, I will only use seconds and not milliseconds. For simplicity, we are going to only calculate the day as if we are at the 0:0:0 instance of that day.

For every type of programming language, there will most likely be a function that will convert a timestamp to date format or vice versa that built into the programming language. However, sometimes they are limited in function. For example, Perl has a timestamp converter if you import the timelocal function from the Time::Local library. Nevertheless, as the time of this writing, the timelocal function is limited to only being able to convert timestamps that are above the year 1000. That wouldn’t have much affection in our daily life since we might never need a timestamp below the year 1000. Nevertheless, we can encounter situations where we are working inside a very strict programming environment that do not give us the ability to import an external library. That event, in fact, did happen to me. This is why I wrote my own timestamp converter.

From that event, I learn one thing for certain. As programming language innovate to become better and better, sometimes we rely mostly on external library codes. Those additional libraries that we use in our program can help us efficient our programming process. However, sometimes it can make us become a little bit lazy to try to understanding the basic structure of how to solve our problems in principle. In my opinion, yes I do rely on the additional library when I program but when I have the time to learn, I will try to learn how that library solved my problem. Sometimes it sharpens my skill and knowledge.

The procedures for converting a timestamp without aid from another function can be a challenge. This is due to the fact that you have to keep track of leap year, century leap and quad century leap year. Keeping track of the leap counts is not the only challenge we have. We also have to know that they only occur after or before February the 29 depends on which direction we are to 1970.

This tutorial will only discuss in regard to converting date as in the zero hours of the day. For converting timestamp with hours, minutes and seconds. We first convert the date to a timestamp. If the time instance is after 1970, we can use this formula for calculating time: seconds + (minutes* 60) + (hours * 60 * 60). After that, we would add the previous time value to our timestamp. If the time instance is before 1970, we would still calculate the timestamp for the date first. After that, we would use this formula for calculating the hours, minutes and seconds time of the date: 86400 – ( seconds + (minutes* 60) + (hours * 60 * 60) ). Then we would take our timestamp value and minus off the previous equation result.

As for much, the code for this article was written in Perl. Most of the explanation can be found within the script through commenting. The source code for this article is available in other programming languages.

In the future, I might incorporate the explanations into this article and remove the comments from the source code. Therefore this article and its source code may change.

For a Perl’s built-in function that will convert a date to a timestamp. The code lines below can be utilized.

use Time::Local 'timelocal';  # This is to import the time library
$time = timelocal($sec, $min, $hour, $day, $month - 1, $year); # The variable name corresponding to what value they will take

Start Of Tutorial Script



Advertisement

use strict;

package dateToTimeStamp;
# dateToTimeStamp function work on yyyy-mm-dd
# This function feature is to convert a date string in the format of yyyy-mm-dd or yyyy/mm/dd to a Unix timestamp.
# To read the entire tutorial please follow kevinhng86 blog @ http://kevinhng86.iblog.website .
# There are other versions of this timestamp converter available on my website.
# Without this function you can use the built in Perl function library. The draw back of Perl library is you can't convert anything below the year 1000.
# At the time of this writing, Perl's time local will spit out positive timestamps for year below 1000.
# This function will work from the year 50 to 5500 due to how much a 64 bits long integer can hold.
# Perl built in library code: 
#                            use Time::Local 'timelocal';
#                            $time = timelocal(0, 0, 0, $day, $month - 1, $year);

sub convert {
    # This is the input value.
    my ($value) = @_;
    # This is the output value.
    my $out = 0;
    # An array for splitting input.
    my @datearray = ();
    
    # Without an input value, the script will end.
    if (!($value)){
        die "There is not an input value";
    }
    # First, check for the format of yyyy-mm-dd
    if ($value =~ m/^\d{4}-{1}\d{1,2}-{1}\d{1,2}$/){   
        # Split the digits into chunks and store into an array.
        @datearray = split /-/, $value;
    # Second, evaluate date in the format of yyyy/mm/dd
    } elsif ( $value =~ m/^\d{4}\/{1}\d{1,2}\/{1}\d{1,2}$/){
        @datearray = split /\//, $value;
    # If the input value does not match the previous date format, the program will exit with an error.
    } else {
        die "Incorrect format";
    }

    # Convert the date values that stored inside the datearray into an integer value that corresponding to year, month and date.
    my $inyyyy = int($datearray[0]); 
    my $inmm = int($datearray[1]);
    my $indd = int($datearray[2]);
    
    # Evaluate if the year is a leap year.
    my $isLeap = ($inyyyy % 4) == 0 ? 1 : 0;
    # Evaluate if the year is a century leap year.
    my $isCenturyLeap = ($inyyyy % 100) == 0 ? 1 : 0;
    # Evaluate if the year is a quad century leap year.
    my $isQuadCenturyLeap = ($inyyyy % 400 ) == 0 ? 1 : 0;

    # Month value can't be greater than 12.
    if($inmm > 12){
        die "Month cannot be greater than 12.";
    }
    # Date value can't be larger than 31.
    if($indd > 31){ 
        die "Day cannot be great than 31.";
    } 
    # Date value can't be larger than 29 if the month is February.
    if($inmm == 2 && $indd > 29){
        die "February can't have more than 29 days";
    }
    # For the month of April, June, September and November, the date value can't be greater than 30.
    if ($inmm eq 4 && $indd > 30 || $inmm eq 6 && $indd > 30 || $inmm eq 9 && $indd > 30 || $inmm eq 11 && $indd > 30){
        die "April, June, September and November can't have more than 30 days";
    }
    # Year, date or month's values can't be less than one.
    if ($inmm < 1 || $indd < 1 || $inyyyy < 1){
        die "Month date and years input can't be less than 1";
    }
    # The maximum support for this timestamp converter is a 64 bits long integer. Therefore, I safety net the below year to the year 50.
    if ($inyyyy < 50){
        die "Memory doesn't allow us to convert year below 50";
    }
    # The maximum support for this timestamp converter is a 64 bits long integer. Therefore I safety net the above year to the year 5500.
    if ($inyyyy > 5500){
        die "Memory doesn't allow us to convert year above 5500";
    }
    # If this is not a leap year then February can't have more than 28 days. 
    if ($isLeap ne 1 && $inmm eq 2 && $indd > 28){
        die "This is not a leap year, you can't have 29 days in Feburary";
    }
    # If this is a century leap year but is not a quad centuary leap year then February can't have more than 28 days. 
    if ($inmm eq 2 && $isCenturyLeap eq 1 && $isQuadCenturyLeap ne 1 && $indd > 28){
        die "This February can't have 29 days. Although it is a leap year, leap year is skipped on years that are divisible 100 years but will not skip if the year is divisible by 400";
    }

    # This array store the amount days that each month have. We count February as a constant of 28 days because we will modify our equation to match the leap year value.  
    my @dateinmonth = (31,28,31,30,31,30,31,31,30,31,30,31);
    # Variable for storing how many leap days occur since input year to 1972 or to 1968
    my $leap2v = 0;            
    # This is the index we would use to get the days from the dateinmonth array.
    my $aridx2 = $inmm - 1;
    # Variable for storing the total date since input year to 1972 or 1968.
    my $totaldate = 0;         
    # Variable for storing the year from.
    my $yeardate = 0;          
    # Variable for storing how many days left in the current year of the input date.
    my $dateleftinyear = 0;
    # Variable for storing how days left in the current month of the input value. 
    my $dateleftinmonth = 0 ;  

    # What is a timestamp? A timestamp is a number string that contains a time value with the format of how many second since the 0:0:0 time of January 1, 1970.  
    # Timestamps are actually measured in milliseconds, However, for this tutorial, we only use the second for measurement.
    # Negative timestamp is how far a time is below 1970. For instance, any date in 1969 and below will generate a negative timestamp.
    # Positive timestamp is how far a time is above 1970. For instance, any date in 1970 and above will generate a positive timestamp. 1970 1 1 in this tutorial will generate a 0 timestamp.
    # The first challenge we meet is the leap year.
    # Timestamp takes into account leap years, century leaps and quad century leaps.
    # What does leap years mean?
    # We get the 29th day in February if the year is divisible by four. We don't get the 29th day if the year is divisible by 100 but is not divisible by 400.

    # The method I prefer to use for calculating leap is if we are above 1970, we will use the closet below leap year. Which would be the year 1968 for calculating leap year value. 
    # This is the fact that we only need to round down our number after we subtract the year value to 1968 then divide by four.
    # If we use 1970 every time we hit a decimal .5 or .75 we have to round up.
    
    # My formula for calculating time values that are above the 0:0:0 time of January 1st, 1970 is as follow: 
    # Since we use leap to calculate to 1968, we will calculate to the 1st day of 1968 and then subtract off the result value a value of two 365 days years.
    # y = (input year value - 1968) * 365
    # d = date from the beginning of year = 365 - ((total date in input month - input date) + (How many day left in the year since one month after the input month).
    # l = How many times leap year has occurred since 1968. Take input year - 1968 / 4. The whole number here is what we want not the decimal. If the value contained a decimal point, leap year had not happened yet for the decimal part of the value.
    # c = How many times century leap has occurred since 1968. Input year - 1968 / 100. The whole number here is what we want and not the decimal. 
    # q = How many times quad century leap has occurred since 1968. Input year - 1968 / 400. The whole number here is what we want and not the decimal. 
    # totaldate = y - d + l - c + q ;
    # timestamp = (totaldate * 86400) - 63158400   // 86400 is how many seconds that is in a day. and 63158400 is the amount of second that contains within two years that is 365 days each.
    # Since we are calculating to 1968 we have to subtract the amount of second in two years from the result value.
  
    # For the purpose of this tutorial I divide the code into what happen if the time value is above the 0:0:0 time of 1970 and what happen if it is below.
    # It is possible to combine the equation and modify the equation as desired.

    if ($inyyyy >= 1970){
        
        my $leapv = sprintf "%d", ($inyyyy - 1968)/4;
        my $centuryleapv = sprintf "%d", (($inyyyy - 2000) / 100);
        my $quadcenturyleapv = sprintf "%d", (($inyyyy - 2000) / 400);
        
        my $len = scalar(@dateinmonth);
        
        $dateleftinmonth = $dateinmonth[$aridx2] - $indd;

        # Get how many date left in a the year since after the input month.             
        for (my $i = $inmm ; $i < $len; $i++){
            $dateleftinyear = $dateleftinyear + $dateinmonth[$i]; 
        }                                                         
        # Get how many days occurred since the begining of year to input date by subtracting 365 to (dateleftinmonth + dateleftinyear)
        my $datefrombeginingofyear = 365 - ($dateleftinmonth + $dateleftinyear);

        # The real challenge we have for calculating leap is.
        # On the year that it is a leap year, we do not have the extra day until we have passed the 29th of February.
        # Hence, although in a leap year, if we have not passed the 29th day, we can't add leap values to our equation.
        # However, the automatic formula has already taken into account the values for leap year. 
        # Therefore those values, have to be subtract off if we has not passed the 29 day of Feburary.
        # Each if loop below is associate with a type of leap calculation.
             
        if ($isLeap eq 1 && $inmm < 3){
            $leapv = ($inmm < 2) || ($inmm eq 2 && $indd <= 29)?  $leapv - 1: $leapv ;
        }
        if ($isCenturyLeap eq 1 && $inmm < 3){
            $centuryleapv = ($inmm < 2) || ($inmm eq 2 && $indd <= 29)? $centuryleapv - 1 : $centuryleapv;
        }
        if ($isQuadCenturyLeap eq 1 && $inmm < 3){
            $quadcenturyleapv = ($inmm < 2) || ($inmm eq 2 && $indd <= 29)? $quadcenturyleapv - 1: $quadcenturyleapv;
        }

        # After evaluate and obtains all necessary value for the formula, we would calculate the result.
        $yeardate = ($inyyyy - 1968) * 365;
        $totaldate = $yeardate + $datefrombeginingofyear + $leapv - $centuryleapv + $quadcenturyleapv;
        $out = ($totaldate * 86400) - 63158400; 
    } else {
        # My formula for calculating time values that are before the 0:0: time of January 1st, 1970 is as follow: 
        # The method I prefer to use for calculating leap values is, if we are below the year of 1970, we will use the closet above leap year, which would be the year 1972 for leap values calculation. 
        # Since we use the year 1972 for calculating leap values, we will calculate the second value to the 1st day of 1972, then we subtract two 365 days years from the equation.
        # y = (input year value - 1972 + 1) * 365   # We will have a negative value of how far we are away from 1972, but we have to add one year here.
        #                                           # This is because 1971 can be considered to be one year away from 1972.
        #                                           # However it is not. We are still within the time frame of 365 days away but not really one year away from 1972.
        # Because we are calculating how far we are below. 
        # We simply just calculating how many days left in the year since the input date value.
        # The previous procedure will let us know how far we are away from the end of the year.
        # d = day left in the month = total day in input month - input date.
        # e = day left in the year = total day left in the year after the input month.
        #    
        # We want all the number below to be positive now.    
        # l = How many times leap year has occurred since 1972. 1972 - input year / 4. The whole number here is what we want and not the decimal value. The decimal values are leap year that has not occurred.
        # c = How many times century leap has occurred since 1972. 1972 - input year / 100. The whole number here is what we want and not the decimal value. 
        # q = How many times century leap occur since 1972. 1972 - input year / 400. The whole number here is what we want and not the decimal value. 
        # The number now are in positive so that mean the further negative the further it is away.        
        # totaldate = y - d - e - l + c - q
        # timestamp = (totaldate * 86400) + 63158400 - 172800  # 86400 is how many seconds that is in a day. and 63158400 is the amount of second that contained within a time frame of two 365 days years.
        #                                                      # Since we calculate to 1972 we have to give back this value.
        #                                                      # We have to also subtract two days from the equation which would be 172800 seconds.
        #                                                      # In this formula, if we are on the 31st day of December 1969 to 1970 1 1.
        #                                                      # We will not have any day left in the month or any day left in the year.
        #                                                      # Hence that is a 0 value, but in true reality, we are one day away if we are counting from the zero hour.
        #                                                      # Thus we have to subtract one day from the equation.
        #  
                                                               
        my $leapv = sprintf "%d", (1972 - $inyyyy)/4;
        my $centuryleapv = sprintf "%d", ((2000 - $inyyyy)  / 100);
        my $quadcenturyleapv = sprintf "%d",  ((2000 - $inyyyy) / 400);
        my $len = scalar(@dateinmonth);

        # There is a difference when we are evaluating leap calculation for a time value that is before the time 0:0:0 of January 1st, 1970.
        # Leap values will not be added to the equation unless we have passed the first day of March.
        if ($isLeap eq 1 && $inmm > 2){
            $leapv = (($inmm > 2) || ($inmm eq 3 && $indd >= 1))?  $leapv - 1 : $leapv;
        }
        if ($isCenturyLeap eq 1 && $inmm > 1 ){
            $centuryleapv = (($inmm > 2) || ($inmm eq 3 && $indd >= 1) )? $centuryleapv - 1 : $centuryleapv;
        }
        if ($isQuadCenturyLeap eq 1 && $inmm > 1 ){
            $quadcenturyleapv = (($inmm > 2) || ($inmm eq 3 && $indd >= 1) )? $quadcenturyleapv - 1 : $quadcenturyleapv;
        }


        $dateleftinmonth = $dateinmonth[$aridx2] - $indd ;
        for ( my $i = $inmm; $i < $len; $i++) {
            $dateleftinyear = $dateleftinyear + $dateinmonth[$i];
        }
        $yeardate = ($inyyyy - 1972 + 1 ) * 365;
        $totaldate = $yeardate - $dateleftinmonth - $dateleftinyear - $leapv + $centuryleapv - $quadcenturyleapv ;

        $out = ($totaldate * 86400) + 63158400 - 172800;
    }
    return $out;
}

print dateToTimeStamp::convert("0800-3-1")

This post was written by Kevin and was first post @ http://kevinhng86.iblog.website.
Original Post Name: "How To Convert Date To Unix Timestamp Without Using A Built In Function – Perl".
Original Post Link: http://kevinhng86.iblog.website/2017/01/20/howto-convert-date-to-unix-timestamp-without-using-a-built-in-function-perl/.

Advertisement
Rank Tracker


Random Article You May Like

30 thoughts on “How To Convert Date To Unix Timestamp Without Using A Built In Function – Perl

    1. The “my” declaration is for declaring a global variable. In my opinion I favour declaring function variable as local variable. Therefore I uses the keyword “our”. Those variable that are declared with the “our” keyword can’t be call outside f the function or their class. It is also safe to handle them as they are not global and the variables will be erase from memory once the function is finish with it’s task.

      1. You’ve got that the wrong way around. “my” will declare a lexically scoped variable to the block, whereas “our” will declare a lexically scoped variable to the *package* and given this code reads like ancient perl 4 style you’re stuffing main:: full of variables that you shouldn’t be.

      2. > The “my” declaration is for declaring a global variable

        I’m not sure where you picked that up from, but it’s completely wrong. “my” declares variables that can only be seen within the innermost enclosing scope (i.e. within the subroutine).

        1. I think I got that wrong about two months ago when I first learn Perl, it’s this Unix time converter was one of my first program I wrote. I ported the code from Javascript to Java and then to PHP and then to Perl. I probably got it mixed up from reading too fast in regard to the “my” and the “our” keyword.

          Nevertheless I really appreciate you for giving me the info, it help me change the way how I can implement my script. As I do not like to declare global variable unless it is absolutely necessary to.

  1. Thank you for the information, I always thought the global variable is “my” so that is not a problem. The code can be fix quite quickly since I declare a uniform syntax.

    1. Can i tell you that there are many more subtle issues with this code? I count at least 5 within the first ten lines of the function and that’s before we even get onto the issue of handling dates, which is an absolute minefield in programming terms. Given that you really shouldn’t be putting this up as an example for others to use.

  2. Please do tell me, it is always better to exchange information, since this was the first script I wrote in Perl, it might need some updating. Nevertheless the concept behind this script is the most important.

    Programming can be seen as looking at example of procedure and fix other people syntax. No program is perfect the first day. Even developer with twenty years still produce bugs. Why would it’s be difference in this case. Nevertheless if you understand the procedure call behind the function, you can make it better on your own.

    1. Feel free to email me (your blog engine has my email address) and I’ll be happy to help you improve this program.
      But until you have fixed it, please take down this blog post.

  3. DateTime already handles this sort of conversion with ease.
    Also:
    ‘eq’ should not be used to compare numbers.
    ‘sprintf “%d”, $integer’ is a complete no-op, integers do not need to be “cast” to strings before they can be used.
    ‘@dateinmonth[$idx]’ should not use the ‘@’ sign. The sigil indicates what kind of value you want to *return*, not what type the variable is.
    ‘for ( our $i = $inmm; $i 86400;’ and so on.
    Also, your comments mention a “memory allocation problem” preventing the code from working outside of the range 55 AD to 5000 AD, but I don’t see where you’re allocating anything larger than an array of 12 integers.

    1. Well, you’ve fixed that one problem. There are plenty more. For example, I’m pretty sure that:

      @datearray = [];

      doesn’t do what you think it does. What do you think you’ll get if you print @datearray immediately after executing that line?

      And on a wider point – have you considered the difference between the Julian and Gregorian calendars at all?

      1. It can’t be the calendar problem because time local and the epoch converter agree their value all the way from the year 1970 to 5500….. Nevertheless they do not agree before the year 1000. I also calculated it’s by hand too. It have to do something with number handling. Not all program can handle calculating the below years. This is not limited to Perl function.

        For the @datearray problem if there is, I always declare variable before I use them, but I would not print them until I assign a value to them. Nevertheless, are we exchanging information because you want improvement or you don’t like the fact that I discuss a bug in the Perl structure. There is a lot of bug everywhere don’t feel bad about it.

        1. You misunderstand me. I’m very happy for you to declare variables before you use them. My point is that you are using the wrong syntax to declare an array. What you wanted was:

          my @datearray = (); # Note: round brackets

          What you used was:

          my @datearray = []; # Square brackets

          The first (correct) version. Declares an array and immediately stores an empty list in it. That’s pointless, because Perl arrays are always empty when they are first created, but it’s not wrong.

          The second version, the one that you use, is wrong. [] is not an empty list. It is the anonymous array constructor. It creates an empty array and returns a reference to it. You then store the reference to that array in your array. If you were to print $datearray[0] after running that code, you would see something like “ARRAY(0x55a640575f30)”. So you don’t have an empty array there.

          Perl syntax can be tricky. I know that beginners often make mistakes like that. And, of course, it’s fine to make mistakes in your code. But publishing your code without labelling it clearly as the unreviewed work of a beginner is a bad idea. People will find your code and assume it is a good example to copy. When it really isn’t. You code still contains both bad syntax and bad algorithms. Please take it down until you have fixed it.

          1. If you refer to this article that I wrote at http://kevinhng86.iblog.website/2017/01/18/the-basic-of-perl-1-variable-declaration-perl/ . I did mention how to properly declare the correct array, whether if it is empty or not.

            I have my own reason why I am declaring it’s like that.

            Nevertheless as for beginner or not, as long as the code does what it said it does without error, than it is a good code. I didn’t claim on top of the code that it’s will be free from error either. I clearly stated it is an example of how you can convert the date to unix timestamp. I even show the correct syntax for using the built in function. I do not think beginner can do that. Even without stating it, I did test the code inject automatic date, and patch the data to get reply back from sources. The code did not fail after 100,000 timestamp conversion. Did you test your code like that? Nevertheless I don’t think “beginner” can understand how to test it like that ether.

            For second, I do take the liberal to answer your question on my blog. I could have just deny all your comment. You only attack this unix timestamp converter and not anything else? Is there a reason to that?

            For syntax wise, perl syntax is not even tricky at all. In fact it is really easy, you don’t even have to convert number to string for concentrating the number to a string, you can just use a dot. You know what is a tricky syntax? Those programming language that you do not have object, or in perl case would be a hash. Those programming language that you have to manage your own variable type and memory. Those are tricky, in fact I would recommend learning Perl for beginner. It’s syntax is similar to Javascript, share some common with PHP and have other common with Ruby.

            If this was C, C++, Erlang, you can tell me the syntax is tricky. This program was wrote when I first learn Perl, why not read one of my newest post? Is there a reason why this timestamp converter? Did you write the time local? Because if you did, it is really bad rep for you. Try to attack me on my blog because of your error.

            Nevertheless let be liberal and have this up. Remember that if you going to send 100,000 date data into my function it will give you the correct answer 100,000 times? Is there a reason to take it’s down? I have this in another seven language too why not check it? I also have this feed posted in a lot of place. there is nothing to hide and in fact plenty of people have this code, ran it and very happy about it. The only problem was the global variable. In the end the moral is, the algorithm for mathematical calculation is not wrong, the only thing was wrong is the global declaration of the variable. The end of the story.

          2. I wasn’t referring to your other article, I was referring to line 18 of the code on this page.

            my @datearray = []; # This array is use to split the input

            It is wrong for the reasons I’ve explained above. In fact, looking at the other article you mention, I see that you have the correct version there.

            our @array = () ; # Declaring an empty global array variable.

            Do you see the difference? Round brackets are right; square brackets are wrong.

            “You only attack this unix timestamp converter and not anything else? Is there a reason to that?”

            I’m not attacking your program, I’m offering constructive criticism. I’ve even offered to discuss it over email so we can correct all of the errors in it.

            And the reason why I’m only commenting on this article is because it’s the only article I’ve seen so far. Your article appeared in a newsfeed that I follow, so I read it and decided to point out some of the problems with your code. Perhaps I’ll look at some more recent articles later.

          3. Well Dave, it is a coincident that all your friend comment on this post at the same time. That is one thing, the second thing is if you saw that I have the correct syntax and why not ask why I declare the array like that?

            Have you ever though that after a split, that split will just expand into that variable and that array which now carry the array from the split anyway? Why don’t you think that I did that on purpose to know which array I use for pushing value on, and which is declare just to become something else after? If you want to talk beginner and expert, apply that to your source code.

            Thirdly, please don’t lie, all my articles in this feed is really small for Perl at currently. There is only about less than 10 articles. Let see, on the Ironman blog which you are also at they are all publish at the same time. 🙂 But thank you for the constructive criticism which happen to be the oldest article that went onto Ironman blog. I don’t deny learning something from you today, and we may be friend in the future. However if the function does what it said it does, that is the story of that.

            I seen programs that was made seven years ago. People paying hundreds thousand of dollar to use it for one year. I looked at their code, and what do you know? Three words, “Riddle with Error”. Both programming and mathematical equation. Is my function that bad, consider you still haven’t tell me that it’s produce an error yet. Knowing that you attack me like this, you probably testing it out right now. The bad side about this is you are trying to attacking the syntax without telling me what number you input in the function that produce the wrong result.

        2. The epoch calculator site also returns Tuesday, Sept. 12 1752 when given -6857367296 for an epoch timestamp. September 12, 1752 never actually happened. In fact, September 3rd through the 13th of that year don’t exist, because Pope Gregory XII declared that he was removing 11 days of that year to introduce the new Gregorian calendar.

          This may also be why your tests for the year 1000 were failing, because your code just counts days. Type ‘cal 1752’ into your UNIX terminal and look at September of that year, if you don’t believe me.

          Date/Time conversion problems are hard, and this is why most people use modules to handle these conversion issues. I’m pleased (as most of the people commenting on this are, I’m sure) that you’re writing and blogging about Perl, it’s just that the code shows some outdated practices. And yes, this *did* get linked from another site, as several other people have pointed out.

          1. I posted this down below already but I just want to reply to you in the event where you don’t subscribe to the comment feed. Use time local vs my function for these date and you will understand. If you need the correct syntax check the below comment.

            Date: 1752-9-12
            Time Local: -6857395200
            My Time: -6857395200

            Date: 1652-9-12
            Time Local: -10013068800
            My Time: -10013068800

            Date: 1552-9-12
            Time Local: -13168828800
            My Time: -13168828800

            Date: 1000-9-12
            Time Local: -30588278400
            My Time: -30588278400

            Date: 0999-9-12
            Time Local: 29338416000
            My Time: -30619814400

            Date: 0952-9-12
            Time Local: 27855273600
            My Time: -32102956800

          2. You miss my point. 1752 only had 355 days, not 365. September 3rd through September 13th never happened, ergo any attempt to convert September 12th, 1752 into an epoch should fail just like trying to convert February 30th should fail. epochconverter.com does not take this into account, therefore it too is inaccurate before 1753. UNIX time facilities (therefore Perl localtime() as well) take this into account, and in order to be correct your algorithm needs to return an error when attempting to convert dates in that range. There are probably other date issues lurking even further back, but the Julian to Gregorian calendar conversion is the most important one.

          3. Dr Forr, you program a timestamp converter and you don’t even know how a timestamp work. You need to know that all unix timestamp below the year 1970 is negative, and all unix timestamp above the year 1970 is positive. If you converter miss by like a hundred day in negative, you can argue that it is the calendar. However below the year 1000, your converter turn from negative to positive. You know why it’s happen like that? Because the mathematical operation memory probably over flow, the integer problem that is what they call it.

  4. Can you explain further why you limit the year to between 50 and 5500?

    Also you appear to not have read the documentation for Time::Local. It is not restricted to only years above 1000. Where did that come from? Time::Local handles daylight savings time, leap seconds and calendar oddities that your code cannot. This isn’t a reason not to try out your own solution so long as you intend that your solution is unlikely to ever be better than the standard library provides. Certainly I’d advise against recommending your solution over a solution provided in the standard library.

  5. This is a reply to all the above comment. I tested out time local it can’t handle the year below 1000. You can go try convert a year below 1000, bring it’s value to http://www.epochconverter.com/ and convert it and see if the number make sense.

    You can’t possible convert a timestamp that is beyond an integer value unless you combine that with my other tools that I am currently writing. Than yes you can convert timestamp from the time this planet was born in one shot.

    1. My script also mentioned right at the start of it, is that this is an example to show you how to convert date to timestamp only, in case you haven’t read it carefully. The hour will always be 0:00 midnight. If you want to know how leap second can be handle, I will show a tutorial on that after I finish with my current project.

    2. Kevin – Could you please show us the code you used to find the bug in localtime() so that we can improve Perl? Dates earlier than 1752 (in Britain and most of the world) or 1912 (in Russia) are affected by the changeover from Julian to Gregorian calendars where we “skipped” a few days in September to account for the fact that the old Julian calendar lost 11 minutes per year. It’s why George Washington’s birthday, for example, is hard to understand.

      Don’t take my word for it, try ‘cal 1752’ in your UNIX shell and look at how many days September has. Date and time conversions are tricky problems to solve, and this is why most people use modules that solve this problem for us.

      Some other points that don’t appear to be addressed are that your code uses ‘eq’ and ‘gt’ for numeric comparisons. Those operators are meant for *strings*, not for numbers. If you don’t believe me, please read http://perldoc.perl.org/perlop.html#Relational-Operators and note where it says “>=” is for numbers, and “ge” is a stringwise comparison, not numeric.

      Also, in another thread you commented on a “coincidence” by “all your friends”. You’re correct, this article got linked on Facebook, and some of us read it. I’m by no means on a “campaign” to “clean up Perl code worldwide”, I’m just trying to help out a fellow Perl hacker to improve their code.

  6. Thank you for being polite,

    First to reply to the subject the place where the timestamp I use for verifying is http://www.epochconverter.com/ . Else that I used other timestamp conversion method within ruby versus my timestamp since I coded this in eight language I test the production version to most of them.

    I can rest assure you that, it is not a calendar problem. If it was the differentiate in calendar, your Perl timestamp versus the epoch converter timestamp would be a lot difference before the year 1700 if that is what you mean. It would not wait until the year 1000 or below to start affecting the calculation. Nevertheless in my opinion I do not believe plenty of people need time below the year 1000, it is more of a how to get one. If I was to write a program to print a timestamp for the birthday of the universe, I don’t even think any of us would use it. However some might read how it’s made just for fun. Also in my opinion, the Unix timestamp is uniformly convert throughout programs. Everyone seem to be using the same formula and it is also the same formula that I uses. Except everyone convert to 1970 where I used 1968 or 1972 to calculate leap day.

    For the eq option on integer value, in my opinion I used it through out my programs. I tested a lot of integer using the eq option and it does not produce any errors in mathematical equation. So in my opinion that is just whom prefers to use which syntax. As you can see my code still producing fine with the eq option.

    I like using eq on my program because the instant I see eq anywhere in the code it’s tell me I am working with Perl. Just like how when I work with ruby the variable name start with the underscore. I can use lower case too, but I rather it’s be underscore. Or when I work with R I can use the equal sign but I use the <- for variable declaration. Or when I work in Groovy, I used .concat instead of the plus sign to combining two strings together.Nevertheless I hope you don't misunderstand that I tried to look for every bug that Perl have. What my articles mainly about is how you can utilise mathematical equation to get a value through programming. There are many methods to apply a mathematical equation, some could be efficient some are not and some could be in the middle. No two code are the same, so in my opinion if both code can produce the correct same result and we use difference writing format then each of us have our own perspective of how our code should be write on the eq or equal sign subject.If you do find a bug in any of my script contain within the Perl subject for any articles I wrote, please comment on here in kind regard the input and the result you got from the script.

    1. but there is indeed a difference between gt and > and lt and perl -wE ‘ my $a = 199; my $b = 99; say “a smaller b” if $a lt $b’
      a smaller b

      vs:

      > perl -wE ‘ my $a = 199; my $b = 99; say “a smaller b” if $a < $b'

      1. Thank you Martin for your comment,

        Yes there is indeed a difference in lt & gt , nevertheless I do not use lt and gt in my formulation currently. I use the eq and ne because it is a way pointer for me. In fact I used to use == but I figured they are the same so therefore it is a way point for me when I translate my code between language. Kind of like a reminder that you are in a Perl environment.

  7. To clarify all the time stamp suggestion on this post I will put some sample data that I got from both the Perl built in timestamp and my timestamp. These are verified by http://www.epochconverter.com/. You can test it if you like.

    Date: 1752-9-12
    Time Local: -6857395200
    My Time: -6857395200

    Date: 1652-9-12
    Time Local: -10013068800
    My Time: -10013068800

    Date: 1552-9-12
    Time Local: -13168828800
    My Time: -13168828800

    Date: 1000-9-12
    Time Local: -30588278400
    My Time: -30588278400

    Date: 0999-9-12
    Time Local: 29338416000
    My Time: -30619814400

    Date: 0952-9-12
    Time Local: 27855273600
    My Time: -32102956800

    Do you notice how time local now become a positive number below the year 1000, where it should had been a negative? I don’t think swapping the number from negative to positive have anything to do with difference calendar time.

    By the way you can test this. For time local below year 1000 you do not need to put the leading zero, you can too, it’s will produce the same result. For my function however you need to add the leading zero as if it is “0999-1-1”.

  8. For one more comment, sorry I should had mentioned the test data earlier. Nevertheless I tested this against eight difference programming language. I know which have bug and which not, but I couldn’t remember a specific bug.

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*