JonesyJones has asked for the wisdom of the Perl Monks concerning the following question:

I have to write a date to a file, and then read it back in later, and there is no problem with that, outside of fact that the date is not human readable - Time::tm=ARRAY(0x7ee918) for example. I would like to write the date out in a human readable format, then read it back in and make it a localtime. The bad news is that I can't use Time::Piece and I can't use Date::Parse. I am using 5.10.1 but the Time::Piece module was not installed and it takes an act of Congress to get that done. Is there a function that can do this for me, or will I have to do it on my own?

Replies are listed 'Best First'.
Re: Converting a date to a string and back
by hippo (Archbishop) on Jul 13, 2016 at 12:42 UTC

    It would help immeasurably if you could provide some code showing how you originally create the time object. You might be using Time::localtime but that's only a guess.

    Once it becomes clear quite how you are creating the time object it should be pretty simple to explain how to convert it to a string and back again.

      Yes, it's with localtime
      use 5.10.1; use strict; use Time::Local; use Time::localtime; use IO::File; my $ti = localtime; my $tf; my ($logFile, $logFileH); my $basePath = "c:\\las\\dump"; my $processName = "dummy process"; my $startState = "enabled"; my $deaths = 4; my $diff; my $processNameOut; my $startStateOut; my $deathsOut; my $deathFile = "$basePath\\itrsDeaths.dat"; my $deathFileH = new IO::File(">$deathFile") or logit("Can't open fi +le: $deathFile for output.\n"); printf $deathFileH ("%-35s%-9s %-5d %s\n", $processName, $startState +, $deaths,$ti); if ( -f "$deathFile") { open(INIFILE,'<',"$deathFile") or logit( "Could not open death fil +e $deathFile: $!"); my @records = <INIFILE>; foreach my $record (@records) { my ($processNameOut, $startStateOut, $deathsOut, $ti) = $record +=~ /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?/; } close INIFILE; } else { open(INIFILE,'>',"$deathFile") or logit( "Could not create death f +ile $deathFile: $!"); close INIFILE; } sleep(2); $tf = localtime; $diff = getTimeDifferenceInSeconds($ti,$tf); say "The time difference in seconds is $diff"; sub getTimeDifferenceInSeconds { my ($t1,$t2) = @_; my $sec1 = $t1->sec; my $sec2 = $t2->sec; my $min1 = $t1->min; my $min2 = $t2->min; my $hour1 = $t1->hour; my $hour2 = $t2->hour; my $mday1 = $t1->mday; my $mday2 = $t2->mday; my $month1 = $t1->mon; my $month2 = $t2->mon; my $year1 = $t1->year; my $year2 = $t2->year; my $diff; my $es1 = timegm($sec1,$min1,$hour1,$mday1,$month1-1,$year1); my $es2 = timegm($sec2,$min2,$hour2,$mday2,$month2-1,$year2); $diff = $es2-$es1; return $diff; } sub logit { print @_; # print $logFileH @_ if ($ENV{ENABLE_ITRS_LOGGING}); }

        Thanks for this code - that makes it all a good deal clearer. So, if all you are after is the time difference in seconds, why not just use epoch times throughout? You could even save both the epoch time and the localtime-as-string in the file if you want the file times to be easily understood by a non-machine reader.

Re: Converting a date to a string and back
by perlfan (Parson) on Jul 13, 2016 at 17:52 UTC
    I've been able to do some interesting things with POSIX::strftime; what do you consider a "human readable" format?
Re: Converting a date to a string and back
by FreeBeerReekingMonk (Deacon) on Jul 14, 2016 at 18:23 UTC
    If you need the timediff's only then why not create a separate marker file and with -M you can get the age of the file in seconds? note, that "age" is actually the age in seconds from the moment the perl script started, so if you use a daemon, it will not work, however, if your script starts regularly or on-demand, this works:

    #!/usr/bin/perl use strict; use warnings; my $TESTFILE='/tmp/x'; unless (-f $TESTFILE){ open(TF, '>',$TESTFILE) or die $!; close(TF); } my $AGE_seconds = -r $TESTFILE ? int( (-M _) *60*60*24) : -1; print "the file $TESTFILE is $AGE_seconds seconds old.\n";

    As for the timelocal(), roll your own, with a simple regular expression you are all set. Just be careful to not match a date in the other fields.

      > if you use a daemon, it will not work,

      Fortunately, there's $^T to compensate:

      $ touch 1 $ sleep 2 $ perl -wE ' say 24 * 60 * 60 * -M "1"; sleep 2; say time - $^T + 24 * 60 * 60 * -M "1"; ' 2 4

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
        Thank you choroba, very insightful (you got my vote)... adding (time - $^T) to my snippets files...