Want to convert for example that date:
02082012
In that case:
02 - Day
08 - Month
2012 - Year
For now I separate the date but not able to convert into month:
#echo "02082012"|gawk -F "" '{print $1$2 "-" $3$4 "-" $5$6$7$8}'
#02-08-2012
Expected view after convert and to catch all Months:
02-Aug-2012
straightforward:
kent$ date -d "$(echo '02082012'|sed -r 's/(..)(..)(....)/\3-\2-\1/')" "+%d-%b-%Y"
02-Aug-2012
Another Perl sollution with the POSIX module, which is in the Perl core.
use POSIX 'strftime';
my $date = '02082012';
print strftime( '%d-%b-%Y', 0, 0, 0,
substr( $date, 0, 2 ),
substr( $date, 2, 2 ) - 1,
substr( $date, 4, 4 ) - 1900 );
Look at http://strftime.net/ for a very nice overview of what the placeholders to strftime do.
Using Perl’s POSIX module and strftime looks like
#! /usr/bin/env perl
use strict;
use warnings;
use POSIX qw/ strftime /;
while (<>) {
chomp;
if (my($d,$m,$y) = /^(\d\d)(\d\d)(\d\d\d\d)$/) {
print strftime("%d-%b-%Y", 0, 0, 0, $d, $m-1, $y-1900), "\n";
}
}
Output:
$ echo 02082012 | convert-date
02-Aug-2012
Time::Piece is a core Perl module and is great for simple manipulations like this.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $string = '02082012';
my $date = Time::Piece->strptime($string, '%d%m%Y');
say $date->strftime('%d-%b-%Y');
(Yes, this is very similar to user1811486's answer - but it uses the correct formats as requested in the original question.)
I think like this.....
use 5.10;
use strict;
use warnings;
use Time::Piece;
my $date = '2013-04-07';
my $t = Time::Piece->strptime($date, '%Y-%m-%d');
print $t->month;
print $t->strftime('%Y-%b-%d');
Just I tried this ...
To break apart a string with fixed field lengths, use unpack:
my $input = "02082012";
my ( $day, $month, $year ) = unpack( 'a2 a2 a4', $input );
print "$input becomes $day, $month, $year\n";
See http://perldoc.perl.org/functions/unpack.html
Then, as stated in the other answers, use POSIX::strftime() to reformat the date.
Related
I have a log file (datetimes.log) consisting of hundreds of thousands of timestamps of the form:
YYYY-MM-DD HH:mm:ss
For example:
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
...etc.
I'd like to write a simple Perl script to output a new unix_timestamps.log file that contains the same entries, but instead of the datetime, to have the corresponding UNIX epoch timestamp. For the example above, the unix_timestamps.log file would have the following info in it:
1364453031
1364453035
1364453043
...etc.
The only thing I can think of is perl convert_2_timestamps.pl:
#!/usr/bin/perl
use warnings;
use strict;
grep m/_(\d{4})(\d\d)(\d\d)/ | POSIX::mktime(?, ?, ?, ?, ?, ?) > unix_timestamps.log
But not sure how to transfer the parameters into mktime, and not sure if this is even the right approach. Thanks in advance.
use strict;
use warnings;
use DateTime::Format::Strptime;
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
on_error => 'croak',
);
while( <DATA> ) {
my $dt = $parser->parse_datetime($_);
print $dt->epoch, "\n";
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
This is a perfect use for the Time::Piece module which has been a standard part of the Perl distribution for over five years.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
# Read the data a record at a time. Data ends up in $_.
# N.B. Using built-in DATA filehandle for this demo.
# In the real world you'd open a separate filehandle.
while (<DATA>) {
chomp;
# Create a Time::Piece object using strptime (that's "string
# parse time") and immediately call the epoch method on the
# new object to get the value you want.
say Time::Piece->strptime($_, '%Y-%m-%d %H:%M:%S')->epoch;
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
You could break up the YYYY-MM-DD HH:mm:ss format like so:
my ( $y, $m, #t ) = split /[-: ]+/, $time_str;
my $time = mktime( reverse #t, $m - 1, $y - 1900 );
But you could also put it in a replace like so:
s{(\d{4})-(0?[1-9]\d?)-(0?[1-9]\d?) (0?\d{1,2}):(0?\d{1,2}):(0?\d{1,2})}{
mktime( $6, $5, $4, $3, $2 - 1, $1 - 1900 )
}e;
Try the Date::Parse CPAN module. (http://metacpan.org/pod/Date::Parse)
With it, your convert_2_timestamps.pl can be just:
#!/usr/bin/perl
use warnings;
use strict;
use Date::Parse;
while (<>) {
chomp;
printf("%s\n", str2time("$_ GMT"));
}
Note that I had to append GMT to your example input to get your expected output.
Run as:
perl convert_2_timestamps.pl < datetimes.log > unix_timestamps.log
I was wondering if someone could show me how to convert 9/15/12 to 255 format.
Something in php from getdate array you can get ydate.
I think you're asking how you can get the 1 <= yday <= 366 day representation of a date, similar to yday in php's getdate(). As is common in PERL, there's more than one way to do it. The simplest mechanism would be to use localtime() for today's date:
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
If you want to do it for a different date, I'd probably use the TimeDate CPAN module
use Date::Parse;
print time2str("%j",str2time("9/15/2012"));
I think Tawnos's mentioning php's yday from getdate() is on target. Here's one option (assuming 2012 is the year in your date string):
use strict;
use warnings;
use Date::Calc qw/Day_of_Year/;
my $date = '9/15/12';
my ( $month, $day, $year ) = split '/', $date;
my $doy = Day_of_Year( "20$year", $month, $day ) - 1;
print $doy; # (0 - 365)
Output:
258
Do you want the day of the year? That would be day 258 (0-based) or the 259th day (1-based), though. Using only core Perl:
use Time::Local qw( timegm );
my $date = '9/15/12';
my ($m,$d,$y) = split(qr{/}, $date);
my $epoch = timegm(0,0,0, $d,$m-1,$y);
my $yday = ( gmtime($epoch) )[7]; # 258 (0-based index)
Note that timegm+gmtime is applicable no matter the time zone of the date.
Here's another way, using the core module Time::Piece :
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $t = Time::Piece->strptime(shift,"%m/%d/%y");
print $t->yday, "\n";
The day output is zero-relative: January 01 = 0.
my $dt = '9/15/2012';
my ( $m, $d, $y ) = split( '/', $dt );
my $t = POSIX::mktime( 0, 0, 0, $d, $m - 1, $y - 1900 );
say [ localtime $t ]->[7] - 3;
Julian date (minus 1) is slot 7 in the list return from localtime and gmtime.
Why subtract 3? I don't know; Sept 15 is 259 Julian. Still it performs the function mapping '9/15/2012' to 255.
You can use only function strftime from core module POSIX.
use strict;
use POSIX qw(strftime);
print strftime "%j", localtime(time);
I'm working on a Perl program at work and stuck on (what I think is) a trivial problem. I simply need to build a string in the format '06/13/2012' (always 10 characters, so 0's for numbers less than 10).
Here's what I have so far:
use Time::localtime;
$tm=localtime;
my ($day,$month,$year)=($tm->mday,$tm->month,$tm->year);
You can do it fast, only using one POSIX function. If you have bunch of tasks with dates, see the module DateTime.
use POSIX qw(strftime);
my $date = strftime "%m/%d/%Y", localtime;
print $date;
You can use Time::Piece, which shouldn't need installing as it is a core module and has been distributed with Perl 5 since version 10.
use Time::Piece;
my $date = localtime->strftime('%m/%d/%Y');
print $date;
output
06/13/2012
Update
You may prefer to use the dmy method, which takes a single parameter which is the separator to be used between the fields of the result, and avoids having to specify a full date/time format
my $date = localtime->dmy('/');
This produces an identical result to that of my original solution
use DateTime qw();
DateTime->now->strftime('%m/%d/%Y')
expression returns 06/13/2012
If you like doing things the hard way:
my (undef,undef,undef,$mday,$mon,$year) = localtime;
$year = $year+1900;
$mon += 1;
if (length($mon) == 1) {$mon = "0$mon";}
if (length($mday) == 1) {$mday = "0$mday";}
my $today = "$mon/$mday/$year";
use Time::Piece;
...
my $t = localtime;
print $t->mdy("/");# 02/29/2000
Perl Code for Unix systems:
# Capture date from shell
my $current_date = `date +"%m/%d/%Y"`;
# Remove newline character
$current_date = substr($current_date,0,-1);
print $current_date, "\n";
Formating numbers with leading zero is done easily with "sprintf", a built-in function in perl (documentation with: perldoc perlfunc)
use strict;
use warnings;
use Date::Calc qw();
my ($y, $m, $d) = Date::Calc::Today();
my $ddmmyyyy = sprintf '%02d.%02d.%d', $d, $m, $y;
print $ddmmyyyy . "\n";
This gives you:
14.05.2014
I was wondering if there is a simple way in Perl to ensure that a date string corresponds to a valid date.
For example, 2012 02 30 is incorrect because it doesn't exist.
The DateTime module will validate dates when creating a new object.
$ perl -we 'use DateTime; my $dt;
eval { $dt = DateTime->new(
year => 2012,
month => 2,
day => 30);
}; print "Error: $#" if $#;'
Error: Invalid day of month (day = 30 - month = 2 - year = 2012) at -e line 1
It also works dynamically on a given DateTime object:
$dt->set(day => 30);
Something like this using Class::Date should work
perl testit.pl
Range check on date or time failed
use Class::Date;
my $d=Class::Date->new('2021-02-30');
unless ( $d->error ) {
print "good date\n";
} else {
print $d->errstr(). "\n";
}
exit;
Check here:
http://www.perlmonks.org/?node_id=564594
I believe you'll get the answers you seek from the wise monks.
You can do this through the use of POSIX mktime, but apparently only if you have a flexible-enough implementation of mktime.
What I do is plug the numbers in and then use local time to get them back and if I get the same day value back, it's a valid number. So, given your string:
my ( $y, $m, $d ) = split ' ', $date_string;
die "$date_string is not a valid date!"
unless ( $d == ( localtime mktime( 0, 0, 0, $d, $m - 1, $y - 1900 ))[3] )
;
See, in the versions of mktime that I'm used to, mktime( 0, 0, 0, 30, 1, 112 ) would make '2012-03-01' and 30 != 1
You can also use Time::Local:
#!/usr/bin/env perl
use strict; use warnings;
use Carp qw( croak );
use Time::Local qw( timegm );
my #to_check = ('1927 06 18', '2012 02 30');
for my $date ( #to_check ) {
printf "'%s' is %s\n", $date, check_date($date) ? 'valid' : 'invalid';
}
sub check_date {
my ($date) = #_;
my ($year, $month, $mday) = split ' ', $date;
my $ret;
eval {
$ret = timegm(0, 0, 0, $mday, $month - 1, $year - 1900);
};
return $ret && $ret;
}
May be this will help too:
use Time::Piece; #in perl CORE distro since 5.10
use 5.010;
say Time::Piece->strptime("2011-02-29","%Y-%m-%d")->strftime("%Y-%m-%d");
#2011-03-01
say Time::Piece->strptime("2012-02-29","%Y-%m-%d")->strftime("%Y-%m-%d");
#2012-02-29
Using this function:
perl -e 'use Time::Local; print timelocal("00","00","00","01","01","2000"),"\n";'
It will return an epochtime - but only in GMT - if i want the result in GMT+1 (which is the systems localtime(TZ)), what do i need to change?
Thanks in advance,
Anders
use DateTime;
my $dt = DateTime->now;
$dt->set_time_zone( 'Europe/Madrid' );
There is only one standard definition for epochtime, based on UTC, and not different epochtimes for different timezones.
If you want to find the offset between gmtime and localtime, use
use Time::Local;
#t = localtime(time);
$gmt_offset_in_seconds = timegm(#t) - timelocal(#t);
While Time::Local is a reasonable solution, you may be better off using the more modern DateTime object oriented module. Here's an example:
use strict;
use DateTime;
my $dt = DateTime->now;
print $dt->epoch, "\n";
For the timezones, you can use the DateTime::TimeZone module.
use strict;
use DateTime;
use DateTime::TimeZone;
my $dt = DateTime->now;
my $tz = DateTime::TimeZone->new(name => "local");
$dt->add(seconds => $tz->offset_for_datetime($dt));
print $dt->epoch, "\n";
CPAN Links:
DateTime
You just need to set the timezone. Try:
env TZ=UTC+1 perl -e 'use Time::Local; print timelocal("00","00","00","01","01","2000"),"\n";'
Time::Local::timelocal is the inverse of localtime. The result will be in your host's local time:
$ perl -MTime::Local -le \
'print scalar localtime timelocal "00","00","00","01","01","2000"'
Tue Feb 1 00:00:00 2000
Do you want the gmtime that corresponds to that localtime?
$ perl -MTime::Local' -le \
'print scalar gmtime timelocal "00","00","00","01","01","2000"'
Mon Jan 31 23:00:00 2000
Do you want it the other way around, the localtime that corresponds to that gmtime?
$ perl -MTime::Local -le \
'print scalar localtime timegm "00","00","00","01","01","2000"'
Tue Feb 1 01:00:00 2000
An other example based on DateTime::Format::Strptime
use strict;
use warnings;
use v5.10;
use DateTime::Format::Strptime;
my $s = "2016-12-22T06:16:29.798Z";
my $p = DateTime::Format::Strptime->new(
pattern => "%Y-%m-%dT%T.%NZ",
time_zone => "UTC"
);
my $dt = $p->parse_datetime($s);
$dt->set_time_zone("Europe/Berlin");
say join ' ', $dt->ymd, $dt->hms; # shows 2016-12-22 07:16:29
The Algorithm
If you want to change a time value from one timezone to another timezone, you must be able to indicate both timezones.
After all, if you set if you want to convert "12:30" to GMT or US/Eastern or Venezuelan time, which means adding/subtracting some amount of hours or hours and minutes, you need to know what timezone is the starting time zone, otherwise, the calculation won't know how much to add or subtract.
If you use DateTime->now;, the timezone is defaulted to the system-time, which may not be the timezone you want to convert from.
In the below code, I demonstrate how to initialize the datetime object to the right starting timezone (fromtimezone) and how to convert that time to the ending timezone (totimezone)...
Working Code
I could not find a Perl sandbox online with the DateTime CPAN module installed.
use strict;
use DateTime;
sub convertTimeZonesForTime {
my ($args) = #_;
my $time = $args->{time};
my $date = $args->{date};
my $totimezone = $args->{totimezone};
my $fromtimezone = $args->{fromtimezone};
my $format = $args->{format} || '%H:%M:%S';
my ($year, $month, $day) = map {int $_} split('-', $date);
my ($hour, $minute, $second) = map {int $_} split(':', $time);
$year ||= 1999 if !defined $year;
$month ||= 1 if !defined $month;
$day ||= 1 if !defined $day;
$hour ||= 12 if !defined $hour;
$minute ||= 30 if !defined $minute;
$second ||= 0 if !defined $second;
my $dt = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
hour=>$hour,
minute=>$minute,
second=>$second,
time_zone => $fromtimezone,
);
my $formatter = new DateTime::Format::Strptime(pattern => $format);
$dt->set_formatter($formatter);
$dt->set_time_zone($totimezone);
return "$dt";
}
print(convertTimeZonesForTime({
'totimezone'=>'America/Denver',
'fromtimezone'=>'US/Eastern',
'time'=>'12:30:00',
}));
Output:
10:30:00