views:

416

answers:

5

I extracted year, month, day, hour, minute, second, and millisecond data from human readable text (it wasn't in a timestamp format, but rather something like "X started at HH:MM:SS.SSS on DD MMM YYYY and ended at HH:MM:SS.SSSS on DD MMM YYYY"), so for each recorded event, I have each of the values.

However, I need to turn those into some kind of timestamp so I can do math on it - I want to determine how long the event lasted (end time - start time). I was hoping the time function would take parameters so I can create two arbitrary times, but that doesn't appear to be the case.

If possible, I would like to stick with functions available in the core Perl libraries or scripts that I can add to the project, since getting CPAN modules installed on the target machines would just make a headache for everyone, if it is even possible to get the modules through the security restrictions.

+1  A: 

You can use POSIX::mktime to turn broken-up time into a timestamp. Be aware that the month is 0-based, and the year is 1900-based, so adjust accordingly. :-)

use POSIX qw(mktime);
$timestamp = mktime($sec, $min, $hour, $day, $month - 1, $year - 1900);
Chris Jester-Young
Although my target platform is Solaris, is this method also available on Windows? It would make my testing significantly easier, although I suppose now is as good a time as any to start using Solaris for testing and debugging of these scripts.
Thomas Owens
`mktime` is a standard C function, so it should be available on Windows too.
Chris Jester-Young
OK. That's what I thought, but when I see POSIX, I get worried when I am dealing with Windows. Although (according to the requirements, anyway), I don't need to run on Windows machines.
Thomas Owens
+3  A: 

You can do it with Time:Local. It's basically the reverse of the built in "localtime" function, so you can generate a timestamp from a standard date.

Satanicpuppy
Huh, I didn't know that `Time::Local` was bundled with Perl! Learn something new every day. +1
Chris Jester-Young
Time:Local looks good, but it unfortunately only has second granularity. Although I do need to look into if sec can be decimal, since I could combine sec and milliseconds into sec.milliseconds.
Thomas Owens
Well, you can always add the fractional part to the timestamp "after the fact". My testing with `mktime` also indicates a second granularity too. :-)
Chris Jester-Young
Yes, I could do that. Either way, this looks extremely promising. I'm going to experiment with this now and if it works, come back to accept.
Thomas Owens
One thing to be aware of, when using `Time::Local` versus using mktime, is that `Time::Local` interprets years differently to mktime. (Month is still 0-based though, i.e., 0 == January, 11 == December.) IMHO, the year handling in `Time::Local` is "too automagic", but this is a matter of personal taste. :-)
Chris Jester-Young
+7  A: 

You want the CPAN module DateTime. Here's an introduction.

On a Debian GNU/Linux or Ubuntu system, simply run:

apt-get install libdatetime-perl

to install the module.

Stefan Kangas
No. I want to avoid installing as not all of these machines can have random CPAN modules installed on them due to security restrictions.
Thomas Owens
The DateTime module isn't exactly a "random" CPAN module. You might want to rethink either your security policy or your deadlines.
innaM
When it comes to CPAN, it has it's highs and lows. The modules that are recommended by Perl hackers themselves are often pieces of software that can be considered "trustworthy" to Perl developers on a level analogue with a peer-reviewed scientific report.Therefore, while it is true you should be careful with CPAN, DateTime is *not* a "random" CPAN Module.See, for example:http://www.perlfoundation.org/perl5/index.cgi?pbp_module_recommendation_commentaryhttp://www.perlfoundation.org/perl5/index.cgi?recommended_datetime_moduleshttp://perl.net.au/wiki/Recommended_Perl_Modules#Date.2FTime
Stefan Kangas
DateTime is certainly a module that is worth the effort to install. If you have many hoops to jump through, you may wish to include some formatters (which can parse as well as format date time data). DateTime::Format::Strptime is a good one to start with.
daotoad
+2  A: 

In terms of built-ins these may be helpful:

  1. POSIX (for mktime and strftime)
  2. Time::Piece, Time::Local and Time::Seconds. These are all standard in Perl 5.10, but may not be available by default on earlier systems.

That said, time/date calculations are complex. If the only obstacle is a few headaches installing modules (rather than a company policy forbidding them), I would really recommend looking at CPAN.

Edit: I see from your comment on another post that there are company restrictions. You should update your original post, since there's a big difference between "headaches" and "security restrictions." In any case, DateTime and Date::Manip are worth looking at. Even if you don't install them, you can get a lot out of reading their source.

Telemachus
To be honest, I'm not sure what the exact policy is, but I was told to avoid CPAN modules as it would delay rolling out to some machines, at the very least, and prevent rolling out in the worst case. Security and all with unvetted software. Perl and it's core libs are vetted, so there's no problem to get Perl updated, if it needs to be.
Thomas Owens
Ok, well then definitely take a look at `Time::Piece` which has a `strptime` function that you may have use for.
Telemachus
@Thomas Owens: That is silly. They trust the code you give them, right? What is preventing you from copying and pasting the code in the CPAN module? What is you bundled all the libraries you wanted into a PAR file and included that with your script?
Sinan Ünür
@Thomas Owens: See also http://perldoc.perl.org/perlfaq8.html#How-do-I-keep-my-own-module%2flibrary-directory%3f
Sinan Ünür
+2  A: 

If you were only interested in comparing times,

my $ts1 = sprintf( '%4.4d%2.2d%2.2d%2.2d%2.2d%3.3d', 
                   $year1, $month1, $mday1, $hour1, $min1, $sec1, $ms1 );

to

my $ts2 = sprintf( '%4.4d%2.2d%2.2d%2.2d%2.2d%3.3d', 
                   $year2, $month2, $mday2, $hour2, $min2, $sec2, $ms2 );

using cmp would be sufficient.

To do arithmetic on these times, use Time::Local to get seconds since epoch and then add the $ms1/1000 to that value.

my $time1 = timelocal($sec1, $min1, $hour1, $mday1, $mon1, $year1) + $ms1/1000;
Sinan Ünür
But, `cmp` won't tell you how many milliseconds elapsed between `t1` and `t2`....
Chris Jester-Young
That will teach me not to post an answer based solely on the title and the first paragraph. Clearly, calculating elapsed time is not a *comparison*.
Sinan Ünür
Elapsed time could be considered a comparison if you look at the result. For example, a negative elapsed time means that something happened before something else.
Thomas Owens
@Thomas Owens and `cmp` will return `-1` if `$ts1` refers to a time before `$ts2`.
Sinan Ünür
Title edited to make it more clear the OP wants more than a <=>-style comparison.
Ether