How to get 'milliseconds' as a part of time in perl? [duplicate] - perl

This question already has an answer here:
Get time in milliseconds without an installing an extra package?
(1 answer)
Closed 8 years ago.
I need to get the time in the format "20130808 12:12:12.123" i.e., "yyyymmdd hour:min:sec.msec".
I tried
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$mon++;
if ($mon<10){$mon="0$mon"}
if ($mday<10){$mday="0$mday"}
if ($hour<10){$hour="0$hour"}
if ($min<10){$min="0$min"}
if ($sec<10){$sec="0$sec"} but this doesn't provide the `msec` as a part of time.
How can i do that ?

Here's a complete script. As proposed before, it is using Time::HiRes::time for microsecond support, and it's also using POSIX::strftime for easier formatting. Unfortunately strftime cannot deal with microseconds, so this has to be added manually.
use Time::HiRes qw(time);
use POSIX qw(strftime);
my $t = time;
my $date = strftime "%Y%m%d %H:%M:%S", localtime $t;
$date .= sprintf ".%03d", ($t-int($t))*1000; # without rounding
print $date, "\n";
If you don't mind to use a CPAN module, then I would propose the excellent Time::Moment module:
use Time::Moment;
print Time::Moment->now->strftime("%Y%m%d %T%3f"), "\n";
And if it may be formatted as an ISO8601 date including a time zone offset and microseconds instead of milliseconds, then it's simply:
print Time::Moment->now->to_string, "\n";

use Time::HiRes
Looking at this briefly, it can provide milliseconds since epoch fairly
easily but didn't seem to extend localtime(), so there's probably a bit of work
involved in using it in a full calendar context.
Here's a working example:
use strict;
use warnings;
use Time::Format qw/%time/;
use Time::HiRes qw/gettimeofday/;
my $time = gettimeofday; # Returns ssssssssss.uuuuuu in scalar context
print qq|$time{'yyyymmdd hh:mm:ss.mmm', $time}\n|;

Related

How do I get the date in MM/DD/YYYY format in perl. I am using perl 5.8

Hi I am trying to store the date in a variable $date. I will then use Excel::Writer::XLSX to print the date into a cell. I am using perl 5.8. I know a lot of the modules used for getting the date such as TimePiece were installed in later versions of perl.
use POSIX qw( strftime );
strftime('%m/%d/%Y', localtime)
You are correct that Time::Piece is only core since Perl 5.10. But you can install it from CPAN. You could then use its strftime method:
use strict;
use warnings;
use Time::Piece;
my $date = localtime->strftime('%m/%d/%Y');
Without it, you can use the built-in localtime function, which also has a nicer wrapper Time::localtime (even in 5.8). You just have to be careful because the values returned by POSIX localtime aren't exactly what you'd expect.
use strict;
use warnings;
use Time::localtime;
my $now = localtime;
my $date = sprintf '%02d/%02d/%04d', $now->mon + 1, $now->mday, $now->year + 1900;

Convert 12 hr time format to 24 hr format in perl?

How do I convert "11am" and "10pm" into "11:00:00" and "22:00:00"? Is there a simple way in perl to convert this?
Time::Piece has been a standard part of Perl since Perl 5.10 in 2007.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Time::Piece;
for (qw[11am 10pm]) {
my $time = Time::Piece->strptime($_, '%H%p');
say $time->strftime('%H:%M:%S');
}
Time::Piece's documentation claims that the definition of %p is based on your locale. So, according to the documentation, Time::Piece's %p can't reliably be used to handle am and pm, so you shouldn't use it.
On the other hand, Time::Piece behaves differently than documented, and %p will reliably handle am and pm, so it could technically be used to solve your problem despite documentation to the contrary.
I'd personally avoid that giant mess (and all of Time::Piece's other problems) and use the following lighter, simpler and clearer code:
my ($h, $ampm) = /^([0-9]+)(am|pm)\z/;
$h = 0 if $h == 12;
$h += 12 if $ampm eq 'pm';
my $hms = sprintf("%d:00:00", $h); # or %02d if you want 00:00:00

How to convert a time format to seconds in solaris

I have a time of format 2013-04-29 08:17:58 and I need to convert it into seconds.
In UNIX, we can use date +%s. Is there anyway to do it in Solaris?
Use Time::Piece. It has been part of the standard Perl 5 distribution since version 9.5 and shouldn't need installing.
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $t = '2013-04-29 08:17:58';
$t = Time::Piece->strptime($t, '%Y-%m-%d %H:%M:%S');
say $t->epoch;
output
1367223478
With a little more effort, you can do this with your horribly outdated version of Perl.
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
my $str = '2013-04-29 08:17:58';
my #dt = split /[- :]/, $str;
$dt[0] -= 1900;
$dt[1] -= 1;
print timelocal reverse #dt;
Time::Local has been included with Perl since the first release of Perl 5 (in 1994).
But please do what you can to get your ancient version of Perl updated.
Update: Getting a few downvotes on this. But no-one has bothered to explain why.

In Perl, how can I parse a date string and subtract days from the date it represents?

I have a date in string as in $str1="20120704". I want to subtract 1 day from that date, and store the value of date as a string in $str2. How can i do it?
This is very similar to another question you asked a couple of days ago. So, unsurprisingly, the solution is also very similar.
Time::Piece and Time::Seconds have been part of the standard Perl distribution since version 5.10.0. You should use them.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
use Time::Seconds;
my $format = '%Y%m%d';
my $str1 = '20120704';
my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = $dt1 - ONE_DAY;
my $str2 = $dt2->strftime($format);
say $str2;
Perl stores dates and times in an internal format that can easily be manipulated. What you have is a date in YYYYMMDD format. So, what you need to do is:
Convert your date (which is in YYYYMMDD format) into Perl's date/time storage format.
Use Perl to manipulate this date and time.
When you want to output the results, you have to convert it back into the format you want.
Convert your date (which is in YYYYMMDD format) into Perl's date/time storage format.
The best module for doing this is Time::Piece which comes with Perl. It's pretty simple:
my $date = Time::Piece->strptime($str1, '%Y%m%d');
$date will now be your date and time, but stored in a format Perl can understand and manipulate. The %Y%m%d is a description of your format, so Perl knows where to find the year, month, and day of the month. You can look at strftime to see the various format parameters. In your case:
%Y - represents the year with the century, such as 2012.
%m - Represents the month as a two digit number such as 03 or 12.
%d - Represents the date of the month as a two digit number from 01 to 31 if there are that many days in the month.
Next: Manipulate your date.
You can use another module called Time::Seconds that will take care of this for you.
Time::Seconds defines a bunch of constants like ONE_DAY which makes thing easier:
my $date = $date - ONE_DAY;
Finally: Convert the date back to the format you want.
Again, Time::Piece has a nifty, easy way to do this for you:
$date->ymd("");
This converts $date into a string in the Year-month-day format. By default, this will put a - between each part. However, you can pass it the character you want to use as the divider. In this case, nothing.
All together:
use Time::Piece # For manipulating and storing the date
use Time::Seconds # For the nice constants such as ONE_DAY and ONE_WEEK
my $date = Time::Piece->strptime($str1, '%Y%m%d');
my $date = $date - ONE_DAY;
my $str2 = $date->ymd('');
That's pretty simple.
Dave Cross gave you an excellent answer. I'd normally just up vote him, and leave it at that. However, he also mentioned you asked a similar question a few days ago. To me, it means that you might have used Dave Cross' previous answer, but you didn't understand it. That's not good.
Look at the documentation of Time::Piece and Time::Seconds. Take a look at strfdate and play around with that. Learn it and understand it. If you have any questions about these, ask them on Stackoverflow. People on Stackoverflow are happier answering questions like "How does this work?" rather than "Can you do this for me?". They'll take the time and effort to explain the first while most will either ignore the latter or give you a cursory answer.
This will make you a better programmer which means you're more valuable with your company and that translate into higher pay. It is worth your time and effort.
Try to understand it. Play around with it.
Addendum
Was using a older perl version 5.8 and thought of using the existing modules in the system. Also not sure of how time::piece works
That's a pretty old version of Perl, but it's common on Solaris.
In this case, we'll do it the very old fashion way.
There are two Perl function called localtime and gmtime. These take the number of seconds since January 1, 1970 and convert it into an array of values with each value representing a particular part of the time (month, year, day, hours, minutes, etc.).
What you need are inverse functions -- something that can take an array of values and convert it into the number of seconds since 1970. Since Perl 3.0, there has been such a module that's included in each version of Perl. In Perl 5.x, tt's called Time::Local. It gives you two functions called timelocal and timegm. These are the inverse functions we need.
First, we need to split up your string into separate year, month, and day, put that into an array for either timegm or timelocal to turn into the number of seconds since January 1, 1970.
Next, we'll subtract the number of seconds in a day. This is 60 * 60 * 24 or 86,400.
Finally, we'll convert that new date into an array that you can use to display the date in YYYYMMDD order.
Two important caveats!
The function assumes that the month is from 0 to 11 and not 1 to 12. This allows you to create an array to convert from month number to name. This means we have to subtract 1 from the month before we give it to gmtime and add one when take it back from timegm.
The year is the number of years since 1900. That means we have to subtract 1900 before we give it to gmtime, and add 1900 when we take it back from timegm.
And, now the program:
#! /usr/bin/env perl
use strict;
use warnings;
use Time::Local;
my $date = 20120615; #2012-June-15
$date =~ /(....)(..)(..)/; #Parse the date
my $year = $1;
my $month = $2;
my $day = $3;
$month -= 1; #Month is 0 to 11 and not 1 to 12
$year -= 1900; #Year is number of years since 1900
my $seconds = 0;
my $minutes = 0;
my $hours = 0;
my $perl_date = timegm($seconds, $minutes, $hours, $day, $month, $year);
my $perl_date2 = $perl_date - (60 * 60 *24);
my ($seconds2, $minutes2, $hours2, $day2, $month2, $year2) = gmtime($perl_date2);
$month2 += 1; #Month is returned as 0 - 11. Make 1 - 12
$year2 += 1900; #Year is given as years since 1900. Add 1900 back to it.
printf qq(The date is %04d-%02d-%02d \n), $year2, $month2, $day2;
I advise you use module DateTime and one ext for format. Also you can see modules Date::Calc or Date::Parse + POSIX function strftime.
use strict;
use DateTime;
use DateTime::Format::Strptime;
my $date_str = '20120704';
my $date_obj = DateTime::Format::Strptime->parse_datetime($date_str);
my $date_res = $date_obj->subtract(days => 1)->ymd;
Will this do?
use Date::Parse;
use POSIX;
my $s1 = "20120704";
my $t = str2time($s1) - 86400;
my $s2 = strftime "%Y%m%d", localtime $t;
print "$s2\n";
Watch out for localtime vs gmtime, and leap seconds if you care about those.
This is a simple strptime/strftime roundtrip. Since strftime normalises inputs it is simply to just subtract 1 from the mday field.
use POSIX 'strftime';
use POSIX::strptime 'strptime';
my $fmt = "%Y%m%d";
my #t = strptime "20120704", $fmt;
$t[3] -= 1; # 1 day
my $str2 = strftime $fmt, #t;

How do I get the current date in ISO format using Perl?

What's the most efficient way to get the current date in ISO format (e.g. "2010-10-06") using Perl?
Most efficient for you or the computer?
For you:
use POSIX qw/strftime/;
print strftime("%Y-%m-%d", localtime), "\n";
For the Computer:
my #t = localtime;
$t[5] += 1900;
$t[4]++;
printf "%04d-%02d-%02d", #t[5,4,3];
Or you can use the DateTime module which seems to be the de facto standard date handling module these days. Need to install it from CPAN.
use DateTime;
my $now = DateTime->now->ymd;
There are plenty of modules in the Date:: namespace, many of which can help you do what you need. Or, you can just roll your own:
my ($day, $mon, $year) = (localtime)[3..5];
printf "%04d-%02d-%02d\n", 1900+$year, 1+$mon, $day;
Resources
Date:: namespace on The CPAN: http://search.cpan.org/search?query=Date%3A%3A&mode=module
You can use the Time::Piece module (bundled with Perl 5.10 and up, or you can download from CPAN), as follows:
use strict;
use warnings;
use Time::Piece;
my $today = localtime->ymd(); # Local time zone
my $todayUtc = gmtime->ymd(); # UTC
This doesn't create any temporary variables:
printf "%d-%02d-%02d", map { $$_[5]+1900, $$_[4]+1, $$_[3] } [localtime];