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

I'm comparing 2 file date time stamps to decide if 1st file is newer than the file in the staging areas. The copy works correctly if I comment out the stat 9 test.
sub cftsain { my ($xxfn1, $xxfn2) = @_; my @dd = (); $dd[7] = 0; $dd[8] = 0; if ( defined (( stat "$xxfn1" )[9]) ) { $dd[7] = (( stat "$xxfn1" )[9]); } if ( defined (( stat "$xxfn2" )[9]) ) { $dd[8] = (( stat "$xxfn2" )[9]); } # Copy the image file if not there or changed. $dd[0] = 0; if (!-e $xxfn2) { copy "$xxfn1", "$xxfn2"; } else { # Database image is newer than staging space image. if ( (( stat "$xxfn1" )[9]) > (( stat "$xxfn2" )[9]) ) { #if ( -M "$xxfn1" > -M "$xxfn2" ) { copy "$xxfn1", "$xxfn2"; $dd[0] = 1; } } $dd[1] = $xxfn1; $dd[2] = $xxfn2; $dd[3] = (( stat "$xxfn1" )[9]); $dd[4] = (( stat "$xxfn2" )[9]); my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($d +d[3]); $year = $year+1900; $mon = $mon+1; $dd[5] = $sec.' '.$min.' '.$hour.' '.$mday.' '.$mon.' '.$year.' '.$wda +y.' '.$yday; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($dd[ +4]); $year = $year+1900; $mon = $mon+1; $dd[6] = $sec.' '.$min.' '.$hour.' '.$mday.' '.$mon.' '.$year.' '.$wda +y.' '.$yday; $dd[9] = -M $xxfn1; $dd[10] = -M $xxfn2; if ( index(lc($xxfn1),'ky2.gif') > -1 ) { out_exclusive('c:/usr/www/test.txt', @dd); } }
Results are

0
C:/Steep/USA Data/State/KY/ky2.GIF
C:/usr/www/steepusa/stage/KY/KY2.GIF
1415033875
1415033875
55 57 11 3 11 2014 1 306
55 57 11 3 11 2014 1 306
1415033875
1415033875
-0.035775462962963
-0.035775462962963

The 2nd file has the same stat 9 as the first. The 2nd should be 11/2.

I did try the -M and the test failed with the 2 large negative numbers (???) that are the same. I also tried the defined tests at the top of the subroutine and captured the stat 9 values if defined. They were defined and are the same. Also, I do use strict and -w flag.

Original code restored below by GrandFather

sub cftsain { my ($xxfn1, $xxfn2) = @_; my @dd = (); # Copy the image file if not there or changed. $dd[0] = 0; if (!-e $xxfn2) { copy "$xxfn1", "$xxfn2"; } else { # Database image newer than staging space image. if ( ( stat "$xxfn1" )[9] > ( stat "$xxfn2" )[9] ) { copy "$xxfn1", "$xxfn2"; $dd[0] = 1; } } $dd[1] = $xxfn1; $dd[2] = $xxfn2; $dd[3] = ( stat "$xxfn1" )[9]; $dd[4] = ( stat "$xxfn2" )[9]; my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($d +d[3]); $year = $year+1900; $mon = $mon+1; $dd[5] = $sec.' '.$min.' '.$hour.' '.$mday.' '.$mon.' '.$year.' '.$wda +y.' '.$yday; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($dd[ +4]); $year = $year+1900; $mon = $mon+1; $dd[6] = $sec.' '.$min.' '.$hour.' '.$mday.' '.$mon.' '.$year.' '.$wda +y.' '.$yday; if ( index(lc($xxfn1),'ky2.gif') > -1 ) { out_exclusive('c:/usr/www/test.txt', @dd); } }

Replies are listed 'Best First'.
Re: comparing 2 file time date stamps
by GrandFather (Sage) on Nov 04, 2014 at 02:03 UTC

    Are you sure both stat calls succeed? If you use strictures (use strict; use warnings;) you'll be getting "Use of uninitialized value" warnings. Given that you reprise the stat calls later why not do them up front and check success? Something like:

    sub cftsain { # Copy the image file if not there or changed. my ($xxfn1, $xxfn2) = @_; my @dd = (0, $xxfn1, $xxfn2, (stat "$xxfn1")[9], (stat "$xxfn2")[9 +]); die "Can't stat '$xxfn1'. Maybe it's missing?" if ! defined $dd[3] +; if (!-e $xxfn2) { ...
    Perl is the programming world's equivalent of English
Re: comparing 2 file time date stamps ( Path::Tiny File::stat Time::Piece )
by Anonymous Monk on Nov 04, 2014 at 03:27 UTC
    This is bad $year+1900; :) use File::stat through Path::Tiny, use Time::Piece , the convenience is very convenient :) and the error checking exeptions are free
    sub cftsain { use Time::Piece qw/ localtime /; use Path::Tiny qw/ path /; my( $source, $destination, $testxt ) = @_; my $sourceStat = path( $source )->stat; my $destStat = eval { path( $destination )->stat }; if( not $destStat ) { path( $source )->copy( $destination ); } else { my $sourceMtime = $sourceStat->mtime; my $destMtime = $destStat->mtime; if( $sourceMtime > $destMtime ) { path( $source )->copy( $destination ); } } if( index( lc( $source ), 'ky2.gif' ) > -1 ) { out_exclusive( $testxt, localtime( $sourceStat->mtime ), localtime( $destStat->mtime ), ); } } ## end sub cftsain

      Thank you anonymous_monk. Its been a real pleasure to browse through the archives of this place and be able to ask questions of knowledgeable people. I really like this language. I'll work with your suggestion and get back.

        anonymous_monk, I could not get that code to work. The Time-Piece was not available in the repositories PPM checked. I tried with File-Stat and got several PM dependency messages.

        I apologize for not using these facilities as I should sometimes. My lack of experience is showing.

        I tried reversing the file order in the diagnostics. The stat 9 values for both tests were still the values of the file not in the staging directory, in this case now the 2nd file in the diagnostic order. I don't seem to be able to see the file in the staging area.

Re: comparing 2 file time date stamps
by Cristoforo (Curate) on Nov 04, 2014 at 01:59 UTC
    Have you considered using the -M file test operator to determine the newest file?
Re: comparing 2 file time date stamps
by Corion (Pope) on Nov 06, 2014 at 11:02 UTC

    From the discussion, it seems that for some weird reason, you get different results in the mtime field of stat than you expect.

    How are you building your expectation of what is correct?

    The following program should output the correct mtime for each file, which should be identical with what the OS thinks, as verified via dir:

    use strict; for my $file (@ARGV) { print "Checking '$file'\n"; if( -f $file ) { system("dir $file"); my $mtime= (stat($file))[9]; print "Mtime: $mtime\n"; print "As string: " . localtime($mtime); } else { print "File '$file' does not exist, skipping\n"; }; }; __END__ Checking 'tmp.pl' Volume in Laufwerk Q: hat keine Bezeichnung. Volumeseriennummer: 5A02-C2B6 Verzeichnis von Q:\ 06.11.2014 12:01 336 tmp.pl 1 Datei(en), 336 Bytes 0 Verzeichnis(se), 956.154.372.096 Bytes frei Mtime: 1415271660 As string: Thu Nov 6 12:01:00 2014

    Ideally, you should always find that the output of the timestamps as reported by dir are identical to the output of the timestamp as found via $mtime and output via localtime.

      Corion, Below is the code I ran.
      #!C:/PERL/bin/perl.exe -w use strict; my $file = 'c:/Steep/USA Data/State/KY/KY2.gif'; print "Checking '$file'\n"; if( -e $file ) { system "dir $file"; my $mtime= (stat($file))[9]; print "Mtime: $mtime\n"; print "As string: " . localtime($mtime); } else { print "File '$file' does not exist, skipping\n"; } $file = 'c:/usr/www/steepusa/stage/KY/KY2.gif'; print "\n\r\n\rChecking '$file'\n"; if( -e $file ) { system "dir $file"; my $mtime= (stat($file))[9]; print "Mtime: $mtime\n"; print "As string: " . localtime($mtime); } else { print "File '$file' does not exist, skipping\n"; }
      The output follows.
      Checking 'c:/Steep/USA Data/State/KY/KY2.gif'
      Parameter format not correct - "Steep"
      Mtime: 1415235120
      As string: Wed Nov  5 19:52:00 2014
      
      Checking 'c:/usr/www/steepusa/stage/KY/KY2.gif'
      Invalid switch - "usr"
      Mtime: 1415235120
      As string: Wed Nov  5 19:52:00 2014
      

      The system command doesn't seem to like the file name as I've formed it.

        Ah - if you specify the path names with backslashes instead of forward slashes, the Windows built-in tools will understand them from the command line:

        my $file = "c:\\Steep\\USA Data\\State\\KY\\KY2.gif";
Re: comparing 2 file time date stamps
by GrandFather (Sage) on Nov 05, 2014 at 21:56 UTC

    In several replies you say "stamp of the file not in the staging directory". What do you mean by that?

    Maybe you should write a little test app that shows the problem you have? Create two files. Wait a few seconds. Rewrite one of them, then perform your modify test. That way we can see and run the failing code and find a solution."

    Perl is the programming world's equivalent of English
      GrandFather, please review the thread before yours by GotToBTru. I've posted 12 file set comparisons. In each pair, 1 file was in a base directory and the other was in a staging directory, really just a way of referring to the 2 locations. Please review.

        Run:

        use strict; use warnings; my $test1 = 'test1'; my $test2 = 'test2'; open my $fOut, '>', $test1; close $fOut; open $fOut, '>', $test2; close $fOut; print "$_: ", (stat $_)[9], "\n" for $test1, $test2; sleep 5; open $fOut, '>', $test2; close $fOut; print "$_: ", (stat $_)[9], "\n" for $test1, $test2;

        and tell us what you get.

        Perl is the programming world's equivalent of English
Re: comparing 2 file time date stamps
by Loops (Curate) on Nov 07, 2014 at 15:23 UTC

    Hi there,

    It's frustrating to deal with problems like this, and i'm sure you're pulling your hair out a bit. ;o) But it seems that this is not a Perl problem. Trying to look for a Perl solution may be part of the problem.

    From what I gathered from your results of the tests suggested by the monks above, Perl mtime agrees with what you get when you use DIR from the command prompt. It's Windows Explorer itself that disagrees with the DIR command prompt. Take a look at this MSDN article that mentions Windows Explorer has changed the algorithm it uses to display dates, while the command line (and other mtime users presumably) have not.

    This is really a question for Microsoft, no?

    P.S. This thread has been very confusing to catch up on because your tests are not minimal, there is no need to compare pairs of files, and definitely not 12 pairs. Just pick a file to work with.

      Loops, GrandFather, and Corion, I'm embarrassed. I't is me. You all could not see my screen, so you could not see what the problem turned out to be.

      I don't know why, but the explorer.exe was showing different dates for the 2 directories and I did not notice it. Maybe I changed these dates and forgot it. The creation date was being shown for the stage directory and the modified date for the KY directory. I changed the date shown on explorer window showing the creation date to the modified date and all became clear. I reran all diagnostics and everything is OK.

      I should have noticed this because explorer.exe showed 'date' for the creation date and 'modified date' for that date as explorer file list headers. I leave the monastery with drooped shoulders and ask your forgiveness for wasting your time. I'm going to stand in the corner for awhile.

        Well the other monks put much more time into helping you than I did, but my guess is that they too will understand. Often when you're in these situations your mind is racing looking for solutions; you're too distracted to notice simple things. If you can catch yourself in these moments, and recheck your assumptions, i've found it's often helpful.

        In any case, glad you can put this one behind you. Chin up and carry on. ;o)

      Loops,

      I went to the command line and listed the 2 directories. The file stamps of like-named files in the 2 directories were the same. In explorer.exe, The file stamps of like-named files in the 2 directories were different.

      I think you have pointed to heart of the matter. I can't believe that there was not a lot of app cries for help on this one. Comparing stamps is a fairly common thing to do in an app.

      I'm so relieved to find this. Loops, is there a language avenue that does not use the cmd.exe stamp, but only the explorer.exe stamp?

      This could be the beginning of a long journey. I'm going to try to enjoy the trip, but I hope that the destination is a better place. ct

Re: comparing 2 file time date stamps
by soonix (Abbot) on Nov 05, 2014 at 22:00 UTC
    what happens if you do it the other way 'round, I mean: stat $xxfn2 first, and then $xxfn1?
      soonix, I did reverse the order, getting the ctime for the 2nd file first, and the result was the same.