Perl find closest date in array - perl

How do I get the closest date that is earlier than the input date or equal to from an array using an input date?
For example, my array would look like this.
#dates = ("200811","200905","200912","201005","201202");
and my input date is
$inputdate = "201003";
How do I get the closest date in the array which is "200912".
The format of the date is YEARMM.
Thanks

Sort the dates, select only the ones preceding the input date, take the last such one:
print ((grep $_ <= $inputdate, sort #dates)[-1]);

use List::Util qw( max );
my $date = max grep { $_ <= $inputdate } #dates;

The logic here is to go one year back and change month from January to December if the month is January, otherwise go back one month in the same year.
I don't code much in Perl, the code in PHP is:
(I'm putting it here to give you the logic. Coding it should be trivial)
$dates = array("200811","200905","200912","201005","201202");
$inputdate = "201003";
$date = $inputdate;
while ($found==0) {
if (in_array($date, $dates)) {
$found = 1;
echo "the date is " . $date;
}
if ($date%100==1) { // if it's january, we need to change to december of the previous year
$date = $date - 100 + 12;
}
else {
$date = $date - 1; //go one month back in the same year
}
}

Related

How can I get date difference in minutes with Perl

My example was: How to compare dates using perl?
...
# $ARG1 is specified by the user for example "10" min
my $difftime=$ARG1;
# -- Get date ---------------------------------------------------------------------
#Stores current date and time - $time min
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =localtime(time() - (60*$difftime));
$year += 1900;
#parse date format to '22.10.2021 00:00:00' -----------------------------------------------------
my $act_date="$mday.$mon.$year $hour:$min:$sec";
...
My first problem is $hour and $mon are one to low why?
My second problem is the time is with one digit "8:4:34" and not with two digits "08:04:34". Is that a problem for a date comparison?
...
#compare date
# date example for $sql_value is 06.10.2021 09:38:27
my $date_to_compare=$sql_value;
if ($act_date <= $date_to_compare)
{
print "the current date is smaller";
}
else
{
print "the current date is greater";
}
...
I get only "the current date is smaller" Why?
Additionally how can i get the time different in minutes?
thanks
Dealing with dates and times at a low level like you're trying to do is really making your life far harder than it needs to be. You should follow the advice in the answers to the example that you link to and use Time::Piece.
My first problem is $hour and $mon are one to low why?
If $hour is wrong then that's likely to be down to timezone differences. But $mon is defined to be between 0 and 11 in the documentation for localtime(). This is part of what I mean by making your life too hard by working at this level.
You really haven't made it clear what you're trying to do. But you can make Time::Piece objects from a datetime string using strptime().
my $date_str = '22.10.2021 00:00:00';
my $date = Time::Piece->strptime($date_str, '%d.%m.%y %H:%M:%S');
Two Time::Piece objects can be compared directly:
if ($dt1 > $dt2) {
# do something
} else {
# do something else
}
If you subtract two Time::Piece objects, you get the number of seconds between the two timestamps.
my $secs = $dt1 - $dt2;
And you can use the strftime() method to get your timestamp in whatever format you want.
say $dt1->strftime('%d.%m.%y %H:%M:%S');

How can I get the last day of the current month with DateTime?

My task is to calculate the last day of the current month.
There is a method last_day_of_month in DateTime. You can call it like this:
$av_tmp_TODAY = DateTime->last_day_of_month({year=>2016,month=>05});
But I do not want to set a fixed year and month, I just want to take today's date and get the last day in that month.
In addition, I want my output in the format %Y-%m-%d.
You use the constructor now() and then the output method ymd('-') together with the desired separator. If not specified, it's - by default.
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw{say};
use DateTime;
my $dt = DateTime->now();
say DateTime->last_day_of_month( year => $dt->year, month => $dt->month )->ymd('-');
$ perl -MDateTime -wE 'say DateTime->today
->set_day(1)
->add(months => 1)
->subtract(days => 1)
->ymd'
Output:
2016-05-31
Learn the perldoc command.
perldoc DateTime should tell you that $dt = DateTime->now; will get you an object with the current date and time, from which you can extract the current year and month with
$year = $dt->year;
$month = $dt->month;
You will also find there
$ymd = $dt->ymd; # 2002-12-06
$ymd = $dt->ymd('/'); # 2002/12/06
To get the day, month, and year, you should use localtime:
my($day, $month, $year)=(localtime)[3,4,5];
To then get the last day of the month, use your code from above:
$av_tmp_TODAY = DateTime->last_day_of_month({
year => $year + 1900,
month => $month +1
})->ymd('-');
Note: You must add 1 to $month and 1900 to $year to get the correct month and year. This is shown in the example above.
For further reading on this topic, see:
http://www.perlmonks.org/?node_id=2158
http://perldoc.perl.org/functions/localtime.html

Format Date and text

I need to format the pubDate to example :
2 hours ago, 2 days ago or 20 hours ago ....
while keeping the original date of the feed cause i tried to format before and i get all my feeds same pubDate the one i set in Date format and the date builder. How can i solve this issue ?
As well i tried to format the text of my pubdate and (Read full article ) when i run pipe its perfect but in pipe output and when i call the rss file from my website i always get the format as code.
You help will be greatly appreciated...
function ShowDate($date) // $date --> time(); value
{
$stf = 0;
$cur_time = time();
$diff = $cur_time - $date;
$phrase = array('second','minute','hour','day','week','month','year','decade');
$length = array(1,60,3600,86400,604800,2630880,31570560,315705600);
for($i =sizeof($length)-1; ($i >=0)&&(($no = $diff/$length[$i])< =1); $i--); if($i < 0) $i=0; $_time = $cur_time -($diff%$length[$i]);
$no = floor($no); if($no <> 1) $phrase[$i] .='s'; $value=sprintf("%d %s ",$no,$phrase[$i]);
if(($stf == 1)&&($i >= 1)&&(($cur_tm-$_time) > 0)) $value .= time_ago($_time);
return $value.' ago ';
}
You need to pass the date within that and you can get the desire format.
This is php function that will convert the time as a 2 hours ago and so on...
For more further function you can check this link Date time formate

Date Manipulation in Perl

I had a problem with date manipulation.This is my scenario.I have a daily generating report files,they will be generated from Monday to Friday.Now I need to compare those reports.My perl code should work in such a way that if today is Monday I need to compare todays report with previous week Friday's report.And my date format will be like this 20100803 if i give like this i need to be compared with 20100802. If i give Monday's report i.e 20100802 it should compare with 20100730 i.e 30th of July. Can anyone please help me.
Thanks in Advance.
You'll probably want to look at some kind of Date/DateTime object like Date::Calc. With that one, for example, you could split the string into a day, month, and year (using Regex or whatever you'd like to use) for something like:
#
#Set $date = "20100308" somehow, based on your file structure
#
$date =~ /^(\d{4})(\d{2})(\d{2})$/;
$year = $1;
$month = $2;
$day = $3;
$dow = Day_of_Week($day, $month, $year);
if ( $dow == 1 )
$offset = -3; #Date is a Monday
} else {
$offset = -1; #Date is Tuesday-Friday
}
#Find the date of the last report
$prev_report_date = Add_Delta_Days($day, $month, $year, $offset);
#
#Compare reports
#
The above is just a generalized example, of course. I don't know exactly how your files are structure or where the date field is coming from, but you can also go to Date::Calc's CPAN page for more help. There are a plethora of other packages that deal with dates, too. This is just one.
This won't handle holidays (and you should really think about those), but it's the minimal implementation in Perl:
use strict;
use warnings;
use POSIX ();
my $date_string = '20100802';
my ( $year, $month, $day ) = unpack 'A4 A2 A2', $date_string;
my $today = POSIX::mktime( 0, 0, 0, $day, $month - 1, $year - 1900 );
( $day, $month, $year, my $wday ) = ( localtime $today )[3..6];
my $day_back
= POSIX::mktime( 0, 0, 0, $day - ( $wday == 1 ? 3 : 1 ), $month, $year )
;
my $day_str = POSIX::strftime( '%Y%m%d', localtime( $day_back ));
Where $time is a specified time value.
With Time::Piece there meanwhile is a base distribution module, that offers date manipulation, comparison etc.
Time::Piece objects e.g. support - and + operators. From the POD:
The following are valid ($t1 and $t2 are Time::Piece objects):
$t1 - $t2; # returns Time::Seconds object
$t1 - 42; # returns Time::Piece object
$t1 + 533; # returns Time::Piece object
Depending on the level of performance that you require, there is a Perl package that is a swiss-army-knife of date manipulation and conversion.
It is called Date::Manip.
From that, you could easily ask for any part of the date (like day-of-week or week-of-year), or compare or subtract dates in a really wide variety of formats.
It is doable with other tools too, I'm sure. I've used Date::Manip for funky stuff like dealing with the date string "last friday" and getting a real value.
There are lots of date/time modules on CPAN, but DateTime is the canonical Perl module for dates and times.
use DateTime;
print DateTime->now()->subtract(3)->ymd('');
If you are ever in doubt about which CPAN module to use, a good first step is to see if Task::Kensho says anything about it.

How do I get an array of days of the month with Perl Date::Manip?

I'm using Date::Manip for a variety of things, and want to create an array of days of the month.
I think I need:
#date = &ParseRecur("2010:4:0:0:0:0:0");
but, it doesn't do it.
I've read & reread the man page but can't get the syntax.
#date = &ParseRecur("2010:4:0:1:0:0:0");
#date = &ParseRecur("2010:4:0:1*:0:0:0");
don't work either!
You could build the list with your own loop, instead of using ParseRecur.
$month = 4;
for ($day = 1; $day <= 31; $day++) {
my $date = UnixDate( "$month/$day/2010", "%m-%d-%Y" );
push( #list, $date ) if (defined $date);
}
From the man pages:
"There are a small handful of English strings which can be parsed in place of a numerical recur description."
Check out the examples in the man page.
So, if you want an array of days of a month - say for June in 2010 you would do:
#dates = ParseRecur("every day in June 2010");