How to get three separate variables from a string?
my $string = '2019-08-20';
my ($year, $month, $day);
my $string = '2019-08-20';
my ($year, $month, $day) = $string =~ /^(\d{4})-(\d{2})-(\d{2})$/;
if( defined($day) ) {
print ("$year $month $day\n");
}else{
print "no match\n";
}
~
As others have pointed out, you can use split() to do what you ask for. But I wonder if what you're asking for is really the best approach.
I don't know why you want three different variables, but would suggest that when you have a date and you want to access different parts of it, then it's usually a better idea to create an object.
use Time::Piece;
my $date = Time::Piece->strptime('2019-08-20');
You can then get the individual elements that you want;
say $date->year;
say $date->mon;
say $date->mday;
But you can also get other potentially useful things:
say $date->month; # August
say $date->day; # Tuesday
Or you could use strftime() to reformat the date:
say $date->strftime('%A, %d %B %Y'); # Monday, 20 August 2019
There's a lot more you can do with Time::Piece.
You can use split function to get three values from the input. As mentioned in the comment ikegami
my $str = '2019-08-20';
my ($year, $month, $day) = split /-/, $str;
print "$year\n$month\n$day\n";
Thanks
Related
use Date::Calc qw(:all);
use Time::Piece;
use POSIX qw(strftime);
$a1 = '01.01.1963';
($year, $month, $day) = Decode_Date_US($a1);
print "$year $month $day\n";
$formatted = strftime('%m/%d/%Y',$month,$day,$year);
print "$formatted\n";
I am trying to format dates in a consistent format using POSIX(strftime). I am uncertain what the input format might be. I am using Decode_Date_US to extract the relevant year, month, day information. I am then trying to format the dates in consistent manner using strftime. I am getting following error
Usage: POSIX::strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) at test_dates.pl line 60
Any help would appreciated.
"use Time::Piece" would be eventually used to sort the dates.
Thanks
Just use Time::Piece and strptime
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $date = '01.01.1963';
my $timestamp = Time::Piece->strptime( $date, "%m.%d.%Y" );
print $timestamp -> strftime( "%m/%d/%Y")
But if the format is inconsistent, then you're onto a loser - for starters, there's plenty of places that transpose day/month ordering, or represent year as two digits (that sometimes will clash with month or day).
It's inherently ambiguous. You can - at best - apply some very crude guessing by grabbing groups of digits and assuming that they're in a consistent order.
E.g.
my ( $day, $month, $year ) = m/(\d{2}).*(\d{2}).*(\d{4})/;
$timestamp = Time::Piece -> strptime ( "$year-$month-$day", "%Y-%m-%d" );
But you'll be tripped up by dates like 10/11/12 because you simply can't know which number is which field. You can try guessing, by evaling the strptime and just retrying different formats until you get one that does decode to something valid.
As you indicate - Decode_Date_US basically does this so:
use strict;
use warnings;
use Date::Calc qw(:all);
use Time::Piece;
my $a1 = '01.01.1963';
my ($year, $month, $day) = Decode_Date_US($a1);
my $time = Time::Piece -> strptime("$year/$month/$day", "%Y/%m/%d");
print $time->strftime("%Y-%m-%d"),"\n";
Also - use strict; use warnings; is good.
And - there's one correct way to write dates. If you're going to reformat at all, then the one that isn't ambiguous is the best choice.
I ended up using DateTime module's strftime function which can handle dates earlier than 1970.
"Crashing" -Perl command line interpreter has stopped working. If it helps, I am using a windows machine and a very infrequent perl user.
this worked for me
use Date::Calc qw(:all);
use DateTime;
$dateformat = "%m/%d/%Y";
($year, $month, $day) = Decode_Date_US($date);
$date = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
);
$date = $date->strftime($dateformat);
Can we separate a string using index values, so that my input which comprises of combined characters can be separated and the final output would be a string which is readable.
Input = 20140610182213
Expecting Output = 2014-06-10 18:22:13
I usually use a substitution for similar tasks:
my $input = '20140610182213';
$input =~ s/(....)(..)(..)(..)(..)(..)/$1-$2-$3 $4:$5:$6/;
print $input;
Another possibility is to use substr:
my $input = '20140610182213';
my #delims = ('-', '-', ' ', ':', ':');
substr $input, $_, 0, pop #delims for 12, 10, 8, 6, 4;
print $input;
You might like unpack for this:
my ( $year, $mon, $mday, $hour, $min, $sec ) = unpack "A4 A2 A2 A2 A2 A2", "20140610182213";
say "$year-$mon-$mday $hour:$min:$sec";
Let's get all modern on you:
use strict;
use warnings;
use feature qw(say);
my $input = "20140610182213";
$input =~ /(?<year>\d{4})
(?<month>\d{2})
(?<day>\d{2})
(?<hour>\d{2})
(?<minute>\d{2})
(?<second>\d{2})/x;
say "$+{year}-$+{month}-$+{day} $+{hour}:$+{minute}:$+{second}";
I'm using named back references here. In Perl since the very early beginning, you always had numeric back references which I could set by using parentheses:
$input =~ /(\d{4})(\d{2})(\d{2})/;
my $year = $1;
my $month = $2;
my $day = $3;
Each parentheses grouping was a back reference. This was taken directly from sed.
In Perl 5.10, named back references can now be used. They're in the format of (?<name>regex) where name is the name of the back reference and regex is the regular expression. To refer to them, you use $+{name} where name is your back reference name.
The big advantage is that you now have actual names for your back references, and you don't have to worry what $2 means:
$input =~ /(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})/;
my $year = $+{year};
my $month = $+{month};
my $day = $+{day};
Now, we use the x flag in regular expressions. This allows us to have multiple line regular expressions:
$input =~ /(?<year>\d{4})
(?<month>\d{2})
(?<day>\d{2})/x; #The /x flag
my $year = $+{year};
my $month = $+{month};
my $day = $+{day};
If you're not familiar with the syntax, it can be a bit hard on the eyes at first. However, one of the nice things about this is that it documents what's going on, and makes maintenance easer. Once your eyes adjust to the light, it is easy to see what is going on and find errors.
Another possibility is to use Time::Piece to convert that date time to something that Perl can directly manipulate:
use strict;
use warnings;
use feature qw(say);
use Time::Piece;
my $input = "20140610182213";
my $date_object = Time::Piece->strptime($input, "%Y%m%d%H%M%S");
printf "%04d-%02d-%02d %02d:%02d:%02d\n",
$date_object->year,
$date_object->mon,
$date_object->mday,
$date_object->hour,
$date_object->minute,
$date_object->second;
Again, what's going on is well documented. You can see what the input string is, and you can easily refer to each part of the string, and even change the formatting. What if you want the name of the month? Use $date_object->month.
For simple parsing and never using this again, the first way is probably the best. However, by using Time::Piece, you can now check to see how days there are between two dates (for example, how old is your date/time stamp?).
I think this is tidiest using a global pattrn match with sprintf:
my $dt = sprintf '%s%s-%s-%s %s:%s:%s', '20140610182213' =~ /../g;
print $dt;
output
2014-06-10 18:22:13
If you want the values assigned to variables (e.g. $y, $m,$d etc.) for use later:
perl -E '($y,$m,$d,$H,$M,$S)="20140610182213"=~/(....)(..)(..)(..)(..)(..)/;say "$y-$m-$d $H:$M:$S"'
Just use Time::Piece
use strict;
use warnings;
use Time::Piece;
my $string = "20140610182213";
my $date = Time::Piece->strptime($string, "%Y%m%d%H%M%S");
print $date->strftime("%Y-%m-%d %H:%M:%S"), "\n";
Outputs:
2014-06-10 18:22:13
my$str= '4/25/10';
my$sr = join(' ',split (/\//,$str));
#my$s = sprintf '%3$d %2$d %1$d',$srt;
print$sr,"\n";
output:
4 25 10
But i want output like 2010-25-04.Can any one suggest me how display the my desire output.Give me your suggestion
you answers will be appreciable.
Well, a braindead solution might be:
my #date = split( /\//,$str)
printf("%04d-%02d-%02d", $date[2] + 2000, $date[1], $date[0]);
You could write something a little more self-documenting by highlighting what you expect to be year, month and day like so:
my ($day, $month, $year) = split /\//, $str;
printf("%04d-%02d-%02d", $year + 2000, $month, $day);
You're not that far off.
Instead of splitting and joining in a single operation, you can keep individual variables to handle the data better:
my ($d,$m,$y) = split /\//, $str;
Then you can format it in most any way you please, for example:
printf "20%02d-%02d-%02d\n", $y, $d, $m;
A few notes, though:
I won't comment about the source format, but the format you're converting to doesn't make a lot of sense. You'd probably be better using ISO-8601: 2010-04-25.
Obviously, this way of doing only works up to year 2099.
For anything more serious, you'd be better off delegating this kind of work to date handling modules. See for example this question for parsing and this question for formatting
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(
pattern => '%m/%d/%y',
locale => 'en_US'
);
my $dt = $strp->parse_datetime('4/25/10');
print $dt->strftime('%Y-%d-%m'), "\n";
Gives:
2010-25-04
No need to do to DateTime for this. Time::Piece has been included with the Perl core distribution for years.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $date = '4/25/10';
my $date_tp = Time::Piece->strptime($date, '%m/%d/%y');
say $date_tp->strftime('%Y-%m-%d');
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 am trying to convert given dates to the corresponding days of the week using Perl with Date::Day.
The input string is in the format: October 24, 2011; March 12, 1989; November 26, 1940.
I have written a script which will parse the above input and convert each date to a format which will be accepted by Date::Day::day().
This subroutine accepts the input in format, mm,dd,yyyy. I have done this using hashes. Recently posted a thread on this query on stackoverflow and with the help of other members, was able to do it.
Here's my script and it returns me ERR for each of the dates instead of returning the Day of Week corresponding to the date.
There seems to be something wrong with the input format of the parameter passed to day() subroutine.
Here's more documentation on the Perl Module I am using:
http://helpspy.com/c.m/programming/lang/perl/cpan/c06/Date/Day/d_1/
I am interested to know, where exactly I am going wrong. Do I have to make some modifications to the date before passing it as a parameter to the day() subroutine?
#!/usr/bin/perl
use Date::Day;
use strict;
use warnings;
my #arr;
print "Enter the string: ";
my $str=<>;
chomp $str;
my #dates= split /; /,$str;
my %days= ("January",1,"February",2,"March",3,"April",4,"May",5,"June",6,"July",7,"August",8,"September",9,"October",10,"November",11,"December",12);
my #output = map {
my $pattern=$_;
$pattern =~ s/(\S*)\s/$days{$1}, /;
$pattern =~ s/\s//g;
$pattern
} #dates;
print &day(11,9,1987); # for test purpose and it returns correct value
foreach $output (#output)
{
chomp $output;
my $result=&day($output);
push(#arr,$result);
}
foreach my $arr (#arr)
{
print $arr."; ";
}
The output of the above script is: ERR; ERR; ERR;
Date::Day looks like a rather old module. It was last updated almost nine years ago. That's not to say that it's broken, but these days the DateTime family of modules handle pretty much any date/time processing that you want. I'd strongly recommend taking a look at those instead.
Here's an example solving your problem using DateTime::Format::Strptime.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use DateTime::Format::Strptime;
my $dt_parser = DateTime::Format::Strptime->new(
pattern => '%B %d, %Y'
);
while (<DATA>) {
chomp;
my $dt = $dt_parser->parse_datetime($_);
say $dt->day_name;
}
__END__
October 24, 2011
March 12, 1989
November 26, 1940
You're passing a string to the sub &day.
Here is a rewrite :
#!/usr/local/bin/perl
use Data::Dump qw(dump);
use strict;
use warnings;
use Date::Day;
print "Enter the string: ";
my $str=<>;
chomp $str;
my #dates= split /; /,$str;
my %days = ("January",1,"February",2,"March",3,"April",4,"May",5,"June",6,"July",7,"August",8,"September",9,"October",10,"November",11,"December",12);
my #output = map {
my #l = split/[ ,]+/;
$l[0] = $days{$l[0]};
[#l];
} #dates;
my #arr;
foreach my $date(#output) {
push #arr, &day(#$date);
}
dump#arr;
output:
("MON", "SUN", "TUE")