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

I have some dates in the format scalar localtime() which I want to convert to create a timestamp.

I thought this would be quite simple, as the scalar localtime() is automatic and so, I thought, would be the re-conversion. However much reading left me with the impression that I had to do a little more work to make this conversion.

I came up with the following script:

#!/usr/bin/perl -wT use strict; use CGI::Carp qw(fatalsToBrowser warningsToBrowser); use CGI ':standard'; use Time::Local; my $input = param('date'); print "Content-type: text/html\n\n"; my $ILLEGAL_CHARS = qr/[^\w:]/; if ($input =~ /$ILLEGAL_CHARS/;) { print "You do not have the right to enter that information"; } my @date = split (/ /, $input); my ($day,$mon,$mday,$hms,$year) = @date; my @date1 = split (/:/, $hms); my ($hour,$min,$sec) = @date1; my %mon_writ = ( Jul => '6', Aug => '7', Sept => '8', Oct => '9', ); $mon = $mon_writ{key}; ($sec, $min, $hour, $mday, $mon, $year) =~ s/^0+//; $year = $year - 1900; my $TIME = timegm($sec, $min, $hour, $mday, $mon, $year); print $TIME;
which appears to give me the correct results. I just thought that I'd ask the question - did I miss something, is there a one or two liner which would do this job?

If there are improvements I could make to this I'd also be grateful to know of them

Replies are listed 'Best First'.
Re: scalar localtime() to timestamp
by Zaxo (Archbishop) on Oct 09, 2003 at 04:56 UTC

    You're relying on your users to give you a date in a pretty specific format. They're likely not to oblige.

    You can either write the form to give the pieces of the date in separate fields, maybe with selections or js validation, or else generate the timestamp yourself with a call to scalar gmtime. If that format doesn't suit you, consult 'man strftime' and call POSIX::strftime $fmt, gmtime;

    After Compline,
    Zaxo

      This is just a personal script so the input is just for me to use. In fact it's just a first step - the next one is to extract all the scalar localtime() dates from a file and convert them to timestamp, but I can handle that side so I wanted to check that I was on the right lines with this code before I went further.

      Thanks for the info on strftime - I'll read up on that.

Re: scalar localtime() to timestamp
by EdwardG (Vicar) on Oct 09, 2003 at 07:11 UTC

    I use this function to create "timestamp" names suitable for backup filenames - names that are easily sorted, and unique.

    The full script can be found here.

    sub newname { my @t = reverse((localtime)[0..5]); $t[0]+=1900; $t[1]++; my $newbackup = sprintf("%4u-%02u-%02u-%02u-%02u-%02u_000",@t).'.zip'; $newbackup =~ s/(\d\d\d)\.zip$/substr('00'.($1+1),-3).'.zip'/e while (-e $newbackup); return $newbackup; }

    HTH

    Update: Minor code tidy for sake of clarity

Re: scalar localtime() to timestamp
by graff (Chancellor) on Oct 09, 2003 at 05:25 UTC
    You might try er -- I mean it seems right that you are using Time::Local -- granting that you are actually going to be reading date/time strings from a file, and it'll be easy for you to parse that into separate scalars (without worrying so much about checking for correctness of the input).
    NAME
    Time::Local - efficiently compute time from local and GMT time

    SYNOPSIS
    $time = timelocal($sec,$min,$hour,$mday,$mon,$year);
    $time = timegm($sec,$min,$hour,$mday,$mon,$year);

    DESCRIPTION
    These routines are the inverse of built-in perl functions localtime() and gmtime()...

    update: OOPS. Sorry I didn't look more closely at your code before posting. Anyway, I think there's nothing wrong with using Time::Local -- it does exactly what you want in this case.

    another update: One nice thing I learned about Time::Local -- you can give it scalar values that equate to things like "Feb 30 2001", and it does the "right" thing, in the sense of returning the time in terms of "two days after Feb 28 2001". This came in very handy when I had to do some date arithmetic -- e.g. determine month and day of month for "day before" or "day after" a given date, or some number of hours before or after a given time. (This was some years ago, before I learned about Date::Manip -- or maybe before that module even existed.)

Re: scalar localtime() to timestamp
by Aragorn (Curate) on Oct 09, 2003 at 06:50 UTC
    Apart from your question, it's much easier and better (in terms of security) to check if the user has entered valid characters than to check for invalid characters. Your regex matches the string %()#^ which is not what you want. Valid characters in this case are whitespace, digits and colons:
    my $LEGAL_CHARS = qr/[\s\d:]/;

    Arjen

      I tried using the string %()#^ as my input, and the string was rejected. Because I know the exact format of the string I want to use I haven't used \s white space but simply a space.

      As far as I can see from my testing I've got this aspect pretty much right and I can't see the argument for it being wrong. Perhaps you could explain?

        The double negation escaped my attention (I shouldn't post before 9:00 :-)
      I think you got that sideways :)

      You always check for invalid characters. All he did was get the wrong character set, and all you have to do is negate the character class (otherwise, your answer is incomplete/wrong).

        I screwed up with the regex, but I still maintain the assertion that you should check for the valid characters in a string. The class of invalid input is infinitely greater than that of valid input. If you check for invalid input and you forget something, you potentially open a security hole. If you check for valid input and forget something, that's inconvenient, but not potentially dangerous.

        In this case, I got the double negation wrong, which is stupid. Also, the input set is very small, so easy to get right. In more complex cases the chance of forgetting something that is not allowed is much greater than forgetting something that is allowed. And in the latter case, it's merely inconvenient, and not dangerous.

        Arjen

Re: scalar localtime() to timestamp
by jeffa (Bishop) on Oct 09, 2003 at 21:33 UTC
    There are two C time.h functions that make parsing dates fairly easy and straightforward: strftime() and strptime(). Time::Piece gives you access to both of these, i would use strptime() to get your date back. Here is a test script:
    use strict; use warnings; use Time::Piece; my @str = ( 'Thu Oct 9 16:58:28 2003', 'Mon Nov 10 06:08:08 2003', 'oops', ); for (@str) { my $time; eval { $time = Time::Piece->strptime($_,'%a %b %d %T %Y'); }; warn "bad time: '$_'\n" and next if $@; print join(',', map $time->$_, qw(second minute hour fullday fullmonth year) ); }

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)