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

Hi Monks!
Question of a better way of doing this. I need to build dynamically, new file names based on the year-month format, but noticing that the first date has to be the last month of the previous year or “file_name_201212”, and the last date needs to be the current year till November or “file_name_201311” . My code works but I am not sure if I am over doing it or if there would be a better and more straight forward way to accomplish the same thing more efficiently.
The results expected is this (also from the code I am posting ).
file_name_201212 file_name_201301 file_name_201302 file_name_201303 file_name_201304 file_name_201305 file_name_201306 file_name_201307 file_name_201308 file_name_201309 file_name_201310 file_name_201311

Here is my code:
#!/usr/bin/perl use strict; use warnings; use POSIX qw/strftime/; my $this_year = strftime('%Y',localtime); my $dates = build_file_names(); foreach my $new_file_names (@$dates) { print " $new_file_names\n"; } sub build_file_names { my $last_year = $this_year-1; my $stop_date = $this_year."12"; my @db_date; for my $year ($this_year..$this_year) { for my $month (1..12) { my $db_date = sprintf "%d%02d", $year,$month; last if ($db_date eq "$stop_date"); push @db_date, "file_name_".$db_date; } } unshift (@db_date, "file_name_".$last_year."12"); return (\@db_date); } # End sub build_file_names
Thanks for looking!

Replies are listed 'Best First'.
Re: Year-month for file names
by hdb (Monsignor) on Nov 26, 2013 at 16:37 UTC

    Are you looking for a rolling 12 month window? Ie, if we were in October now, would you be looking for the last two months in 2012?

    sub filenames { my( $base, $year, $month ) = @_; return ( ( map { sprintf $base, $year-1, $_ } $month+1..12 ), ( map { sprintf $base, $year, $_ } 1..$month ) ); } print filenames "file_name_%04d%02d\n", 2013, 11;

    Pls see the trailing "\n" in the filename template which is there only for the printing.

Re: Year-month for file names
by BrowserUk (Patriarch) on Nov 26, 2013 at 14:45 UTC
    My code works but I am not sure if I am over doing it or if there would be a better and more straight forward way to accomplish the same thing more efficiently.

    Your subroutine takes no parameters, so no variation is possible. In other words, why waste time generating this at runtime, the returned array is constant, so make it so:

    use constant DB_DATES => [ qw[ file_name_201212 file_name_201301 file_name_201302 file_name_201303 file_name_201304 file_name_201305 file_name_201306 file_name_201307 file_name_201308 file_name_201309 file_name_201310 file_name_201311 ] ]; print for @{ DB_DATES() };; file_name_201212 file_name_201301 file_name_201302 file_name_201303 file_name_201304 file_name_201305 file_name_201306 file_name_201307 file_name_201308 file_name_201309 file_name_201310 file_name_201311

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Downvote, the sub is not invariant because of the $this_year variable in higher scope.
        the sub is not invariant because of the $this_year variable in higher scope.

        Correct. Now what was my point?


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      It needs to generate the file names when it runs, and there is no parameters that needs to be passed to the sub, I don't understand your comments.
      "Your subroutine takes no parameters, so no variation is possible. In other words, why waste time generating this at runtime, the returned array is constant...".

        Seems my prompt was too obscure. See if this makes sense:

        use constant DATE_TEMPLATE => "file_name_%4d%02d"; sub buildEm{ my $year = shift; my @dates = sprintf DATE_TEMPLATE", $year-1, 12; push @dates, sprintf DATE_TEMPLATE, $year, $_ for 1 .. 11; return \@dates; };; $dates = buildEm( substr localtime, -4 );; print for @{ $dates };; file_name_201212 file_name_201301 file_name_201302 file_name_201303 file_name_201304 file_name_201305 file_name_201306 file_name_201307 file_name_201308 file_name_201309 file_name_201310 file_name_201311

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Year-month for file names
by kcott (Archbishop) on Nov 27, 2013 at 06:54 UTC
    "My code works but I am not sure if I am over doing it or if there would be a better and more straight forward way to accomplish the same thing more efficiently."

    Using the core module Time::Piece, I think you'd agree this is more straightforward:

    #!/usr/bin/env perl -l use strict; use warnings; use Time::Piece; my $this_year = localtime->year; my @filenames = ('file_name_' . ($this_year - 1) . 12); push @filenames, "file_name_$this_year$_" for '01' .. '11'; print for @filenames;

    Output:

    file_name_201212 file_name_201301 file_name_201302 file_name_201303 file_name_201304 file_name_201305 file_name_201306 file_name_201307 file_name_201308 file_name_201309 file_name_201310 file_name_201311

    Whether it's "better" is somewhat subjective; however, I think I'd prefer to maintain the three lines I use to generate the array of filenames to all the code you posted.

    Use Benchmark (also a core module) to compare the running times.

    -- Ken

Re: Year-month for file names
by taint (Chaplain) on Nov 26, 2013 at 17:40 UTC

    Wouldn't simply sorting against columns be easier/simpler, than adding the DateTime module, or using Date specific routines?

    --Chris

    #!/usr/bin/perl -Tw
    use Perl::Always or die;
    my $perl_version = (5.12.5);
    print $perl_version;
Re: Year-month for file names
by Laurent_R (Canon) on Nov 26, 2013 at 23:13 UTC

    A three code line solution demonstrated step by step under the Perl debugger:

    DB<1> $year = (localtime time)[5] + 1900; DB<2> print $year 2013 DB<3> @filenames = map {"file_name_$year" . sprintf "%02d", $_} (1. +.11); DB<4> x @filenames 0 'file_name_201301' 1 'file_name_201302' 2 'file_name_201303' 3 'file_name_201304' 4 'file_name_201305' 5 'file_name_201306' 6 'file_name_201307' 7 'file_name_201308' 8 'file_name_201309' 9 'file_name_201310' 10 'file_name_201311' DB<5> unshift @filenames, "file_name_" . ($year -1) . "12"; DB<6> x @filenames 0 'file_name_201212' 1 'file_name_201301' 2 'file_name_201302' 3 'file_name_201303' 4 'file_name_201304' 5 'file_name_201305' 6 'file_name_201306' 7 'file_name_201307' 8 'file_name_201308' 9 'file_name_201309' 10 'file_name_201310' 11 'file_name_201311' DB<7>

    Done!