Im looking for a perl module which takes a date string like this "Nov 23 10:42:31.808381" and its format something like "%b %d ...." this and get me a dateTime object/or print it into another format specified in the same way. Time::Piece doesnt have resolution upto nano seconds. Is there any module which will help me?
Im using perl 5.8 (this doesnt have named backreferences)
DateTime::Format::Strptime has support for microseconds and nanoseconds.
Your format is slightly strange as it doesn't include a year. I've added one you make this demo code work.
#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(
pattern => '%b %d %Y %H:%M:%S.%6N',
on_error => 'croak',
);
my $string = 'Nov 23 2010 10:42:31.808381';
my $dt = $strp->parse_datetime($string);
print $dt->microsecond;
"Nov 23 10:42:31.808381" -- is microseconds, not nanoseconds
If you need microseconds, you must use Time::HiRes; module and gettimeofday method in it.
Related
This question already has answers here:
How can I parse dates and convert time zones in Perl?
(5 answers)
Closed 7 years ago.
I have a date/time like this: 2015-07-31T13:30:00.000+01:00
And I want to convert it to normal date and time using Perl and Time::Piece->strptime
Here is my code:
sub changeDateFormat {
my ($date, $fromFormat, $toFormat) = (#_);
return Time::Piece->strptime($date, $fromFormat)->strftime($toFormat);
}
The call:
print changeDateFormat($that_date, '%Y-%m-%dT%H:%M:%S.%N+%z', '%Y:%m:%d');
I think that .000 are nano seconds and +01.00 stands for time zone.
But the given code gives this:
Error parsing time at /usr/lib64/perl5/Time/Piece.pm line 470
Any help is appreciated.
There's a couple of problems I think.
%N isn't in my strftime manpage. So that might well not work.
And %z - I'm pretty sure +01:00 isn't valid.
%z The +hhmm or -hhmm numeric timezone (that is, the hour and
minute offset from UTC). (SU)
This works though:
my $date = '2015-07-31T13:30:00+0100';
my $fromFormat = '%Y-%m-%dT%H:%M:%S%z';
print Time::Piece->strptime($date, $fromFormat);
So I'd suggest - unless your milliseconds are important - you could just strip those via a regex, and likewise the timezone. (And it they are important, I don't think Time::Piece does ms resolution anyway)
You can probably use a regular expression to 'correct' your input date if you were so inclined. I'm unsure if fits your use case but:
$date =~ s/\+(\d{2}):(\d{2})$/+$1$2/;
$date =~ s/\.\d{3}+/+/;
You can use strptime in Time::Piece and adding the time zone manually as shown in this answer, or you could try using DateTime::Format::Strptime instead:
use feature qw(say);
use strict;
use warnings;
use DateTime::Format::Strptime;
my $timestamp = '2015-07-31T13:30:00.000+0100';
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%dT%H:%M:%S.%N%z'
);
my $dt = $strp->parse_datetime( $timestamp );
say $dt->strftime('%Y:%m:%d');
Output:
2015:07:31
use DateTime;
use DateTime::Format::ISO8601;
use DateTime::Format::Strptime;
my $string = '2015-07-31T13:30:00.000+01:00';
my $date = DateTime::Format::ISO8601->parse_datetime( $string );
die "Error" unless $date;
my $formatter = new DateTime::Format::Strptime(pattern => '%Y-%m-%d %T');
$date->set_formatter($formatter);
print "$date\n";
I am reading a log file which contains time stamps which I want to convert to human readable.
In this command, $1 contains a time stamp (like this 1403457192.663): $temp = localtime->mon($1) but instead of storing the month, $temp contains the same timestamp that was input. What am I doing wrong?
You're close. The time should be passed to the localtime function, not the mon method.:
$temp = localtime($1)->mon; # 6
You can use strftime with this to turn it into any arbitrary format
localtime($1)->strftime("%b %d %a"); # Jun 22 Sun
Or if you're not picky about the format you can just stringify it:
$temp = localtime($1);
print "$temp\n"; # Sun Jun 22 13:13:12 2014
This assumes that Time::Piece is loaded.
I'd simply go with
$ perl -E'
use POSIX qw( strftime );
say strftime("%Y/%m/%d %H:%M:%S", localtime(1403457192.663));
'
2014/06/22 13:13:12
But you're using Time::localtime. That module overrides the localtime builtin, so you need a slight modification if you use that.
Either avoid using Time::localtime's localtime
$ perl -E'
use POSIX qw( strftime );
use Time::localtime qw( localtime );
say strftime("%Y/%m/%d %H:%M:%S", CORE::localtime(1403457192.663));
'
2014/06/22 13:13:12
or flatten an existing Time::localtime object.
$ perl -E'
use POSIX qw( strftime );
use Time::localtime qw( localtime );
my $tm = localtime(1403457192.663);
say strftime("%Y/%m/%d %H:%M:%S", #$tm);
'
2014/06/22 13:13:12
All of these solutions lose the millisecond precision. If it's relevant, you'll have to extract it from the original input and reinsert it in the output.
For formatting dates most system strftime manual pages will list a few "shortcuts" to get you certain "standard" formats.
e.g. %F is equivalent to ā%Y-%m-%dā.
~/% perl -MPOSIX -E'say strftime"%D",localtime'
06/25/14
~/% perl -MPOSIX -E'say strftime"%F",localtime'
2014-06-25
These can make using "ye olde" strftime easier ;-)
Perl since 5.10 now contains Time::Piece. This makes it the official way to handle time in Perl. Or, about as official as something gets in Perl. Since it's always available, you might as well learn to use that:
use strict;
use warnings;
use Time::Piece;
use Time::Seconds; # More time fun!
my $time = Time::Piece->new; # Gets the current timestamp
my $month = $time->mon(); # Month from 1 to 12
my $month = $time->month(); # Abbreviation of the name of month
my $month = $time->fullmonth(); # Full name of the month
my $time = $time + (ONE_DAY * 30) # Add thirty days to the time
my $date = $time->mdy # The date 30 days from now.
I have done some searching and I'm not sure how to get this converted correctly using core Perl modules. I have 2013-10-22T19:31:00Z and want to get 10/22/2013 and the time in US Central time.
Here's a solution using just core modules (well, you need to have at least perl 5.8):
use strict;
use POSIX qw(tzset strftime);
use Time::Local qw(timegm);
my $iso_time = "2013-10-22T19:31:00Z";
my $formatted_time;
{
local $ENV{TZ} = "America/Chicago";
tzset;
if (my($y,$m,$d,$H,$M,$S) = $iso_time =~ m{^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$}) {
$formatted_time = strftime '%m/%d/%Y %H:%M:%S', localtime timegm $S,$M,$H,$d,$m-1,$y;
} else {
# invalid ISO date, do something
}
}
tzset; # restore default time zone handling
warn $formatted_time, "\n"; # output is "10/22/2013 14:31:00"
A word about the TZ trick: by setting the environment variable TZ some time-related libc functions (e.g. localtime) use that time zone instead of the default time zone. If the TZ environment variable is set within a program, then tzset() has to be called to adjust the internal time-related data structures. And don't forget to call tzset() again to restore the data structures again.
This should work on most Unix system, but may or may not work on a Windows system.
use DateTime::Format::RFC3339 qw( );
use DateTime::Format::Strptime qw( );
my $in_dt_format = DateTime::Format::RFC3339->new();
my $out_dt_format = DateTime::Format::Strptime->new(
pattern => '%m/%d/%Y %H:%M:%S',
on_error => 'croak',
);
my $dt = $in_dt_format->parse_datetime('2013-10-22T19:31:00Z');
$dt->set_time_zone('America/Chicago');
say $out_dt_format->format_datetime($dt); # 10/22/2013 14:31:00
Standard Perl modules?
That would include Time::Piece that's been part of Perl since 5.10.
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Time::Piece;
my $date = "2013-10-22T19:31:00Z";
my $time = Time::Piece->strptime ( $date, "%Y-%m-%dT%H:%M:%SZ" );
$time = localtime($time); # Converts time to local time
say $time->mdy("/");
This prints out:
10/22/2013
That wacky "%Y-%m-%dT%H:%M:%SZ" string represents the format of your time input. You can find it in your manage for strftime.
%Y: Four digit year
%m: Month from 01 - 12
%d: Day from 01 - 31
%H: Hour from 00 - 23
%M: Minute from 00 - 59
%S: Second from 00 - 59
I'm looking for a way to convert a date in format YYDDD to YY/MM/DD.
i.e. 12212 becomes 12/07/30.
An example in php can be found at http://www.longpelaexpertise.com.au/toolsJulian.php and you can find a DDD calendar at http://landweb.nascom.nasa.gov/browse/calendar.html
I'd appreciate any guidance both with and without perl modules.
Thanks!
edit: I'm not looking for a way to convert php2perl or anything like that. I'm simply looking for a way to convert YYDDD to YY/MM/DD using perl. I would prefer a way without using any additional perl modules however if that is the only way to do it, then I'll welcome examples using perl modules.
The nicest way would be to use Time::Piece to parse the date and reformat it, like this
Time::Piece->strptime('12212', '%y%j')->strftime('%y/%m/%d')
unfortunately however, the module doesn't accept %j (day of year) in its strptime format (although it is fine in strftime).
The second best option is strftime from the POSIX module. The string has to be split into year and day first, and the day of year is zero-based so one must be subtracted, but then the conversion is straightforward. It is probably best packaged as a subroutine, like this
use strict;
use warnings;
use POSIX 'strftime';
sub yj2ymd {
my ($year, $yday) = $_[0] =~ /(\d\d)(\d\d\d)/;
strftime('%y/%m/%d', 0, 0, 0, 0, 0, 2000+$year, 0, $yday-1);
}
print yj2ymd('12212');
output
12/07/30
You will have to do something fancier with the year if you expect any dates from last century.
I like Time::Piece simply because it comes with Perl since, I believe revision 5.10. You'll find dozens of date/time modules and everyone has their favorites, but with Time::Piece becoming part of the official distribution, it's time to switch to that.
To use Time::Piece, you need to know about strptime (STRing Parse TIME) and strftime (STRing Format TIME) both which uses %x letter formats to represent certain aspects of your time string. The reason is that Time::Piece uses the same %x format characters to both convert your time string to a time object and sometimes to format that time object into your string.
From strftime's manpage:
%j
The day of the year as a decimal number (range 001 to 366).
And:
%y
The year as a decimal number without a century (range 00 to 99).
Now to convert your date:
use Time::Piece;
my $old_time = "12212"; #YYddd
my $time = Time::Piece->strptime( $old_time, "%y%j" );
my $new_time = $time->ymd("/"); Now in YY/MM/DD format
Whoops
Hang on ā strptime does not grok %j. This will give the wrong answer.
I didn't test this because I have used Time::Piece so often that I can do it in my sleep. I never used %j before in Time::Piece. The perldoc mentions nothing about %j not working, and I don't get any sort of error. That's not nice.
New strategy. I can parse the YYddd string into year and days. Then, I can get the beginning of the year as 01/01/$year. After that, I can take the days, and add it to the year. However, to do this correctly, I need a constant from Time::Seconds:
use strict;
use warnings;
use feature qw(say);
use Time::Piece;
use Time::Seconds;
my $old_date = "12212";
$old_date =~ /(..)(.*)/;
my $year = $1;
my $days = $2;
my $time = Time::Piece->strptime("01/01/$year", "%m/%d/%y");
$time += ( ( $days - 1 ) * ONE_DAY); #01/01/$year is day 1 and not 0
say $time->strftime("%y/%m/%d");
That gives 12/07/30 as the answer.
Announcement
The owner of the Time::Piece module fixed the error in the module. Version 1.23 now works:
use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;
use Time::Piece;
my $old_time = "12212"; #YYddd
my $time = Time::Piece->strptime( $old_time, "%y%j" );
my $new_time = $time->ymd("/"); #Now in YY/MM/DD format
say "Version: $Time::Piece::VERSION";
say $new_time;
This prints out:
Version: 1.23
2012/07/30
Here's a short and sweet way to do what you want:
#!/usr/bin/perl
use strict;
use Date::Calc qw(Add_Delta_Days);
my $dt = '12212';
my $startYr = 2000 + substr($dt, 0, 2);
my $daysToAdd = substr($dt, 2) - 1;
my ($newYr, $newMo, $newDay) = Add_Delta_Days($startYr, 1, 1, $daysToAdd);
printf("%02d/%02d/%02d\n", $newYr % 100, $newMo, $newDay);
Need help parsing the datetime stamp and splitting it up by date and time.
use strict;
use warnings;
use Time::Piece;
my $string = "05:57:03 08/31/10 MDT";
print $string,"\n";
my $time = Time::Piece->strptime($string, "%H:%M:%S");
my $date = Time::Piece->strptime($string, "%Y/%m/%d");
print $time,$date,"\n";
Thanks! Also how do I figure out which day of week this is using code?
use DateTime::Format::Strptime;
my $s = DateTime::Format::Strptime->new(pattern => '%T %D %Z');
my $dt = $s->parse_datetime('05:57:03 08/31/10 MDT');
say $dt->strftime('%A'); # Tuesday
You should be able to use code like the following:
my $t = Time::Piece->strptime($string, "%H:%M:%S %m/%d/%y %Z");
However, on my system at least, I have to change the time zone MST to GMT for it to match; if I leave it as in your example, I get an error:
Perl> my $t = Time::Piece->strptime("05:57:03 08/31/10 DST", "%H:%M:%S %m/%d/%y %Z");
[!] Runtime error: Error parsing time at /usr/local/lib/perl/5.10.0/Time/Piece.pm line 469.
If it works for you, though, you'll have a Time::Piece object, on which you can call e.g. $t->day_of_week for the day of the week as a number, $t->day for e.g. 'Tue', or $t->fullday for e.g. 'Tuesday'.
See the documentation for Time::Piece for details on the methods you can call.