my yesterday date is 201103116
I want to take starttime timestamp and endtime time stamp for yesterday in perl.
Using DateTime:
use DateTime;
my $start = DateTime->now(time_zone => 'local')->subtract(days => 1)
->set(hour => 0, minute => 0, second => 0);
my $end = $start->clone()->add(days => 1, seconds => -1);
print $start, " - ",$end,"\n"; # 2011-03-15T00:00:00 - 2011-03-15T23:59:59
print $start->epoch," - ",$end->epoch,"\n"; # 1300147200 - 1300233599
The Perl-core way would be:
my ( $y, $m, $d ) = unpack 'A4 A2 A2', $date;
my $start_ts = POSIX::mktime( 0, 0, 0, $d, $m - 1, $y - 1900 );
my $end_ts = POSIX::mktime( 0, 0, 0, $d + 1, $m - 1, $y - 1900 );
see POSIX
And with mktime it's perfectly okay to just add negatives to values. So if you need to have 23:59:59 as your end date as suggested in the comments, you can just fix it up with this:
my $end_ts = POSIX::mktime( -1, 0, 0, $d + 1, $m - 1, $y - 1900 );
(Although, I would just like to note that the excluded endpoint is not an unknown case in programming.)
I did not understand your question. However, have a look at DateTime.
Related
I'm trying to use Perl's DateTime to subtract one day from another with a sign. I can get the days in between easily:
sub delta_days {
my $date1 = shift;
my $date2 = shift;
my $d1 = str_to_date_object($date1);
my $d2 = str_to_date_object($date2);
return $d2->delta_days($d1)->delta_days();
}
say delta_days('2021-10-21', '1980-8-20');
say delta_days('1980-8-20', '2021-10-21');
but both of these calls give the difference as 15037, without a sign.
Following the documentation https://metacpan.org/pod/DateTime
I see
# not DST
my $dt1 = DateTime->new(
year => 2003,
month => 5,
day => 6,
time_zone => 'America/Chicago',
);
# is DST
my $dt2 = DateTime->new(
year => 2003,
month => 11,
day => 6,
time_zone => 'America/Chicago',
);
my $dur = $dt2->subtract_datetime($dt1)->days();
I have checked a similar question in How to make DateTime::Duration output only in days? but I don't see how to get a signed difference there.
How can I get the difference in days with a sign?
Two issues: You're doing the subtraction on dates in the wrong order if you want a negative offset, and with the dates you're testing subtract_datetime() with, the duration object is going to have 0 days.
Compare with this version:
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
use DateTime;
use Data::Dumper;
# not DST
my $dt1 = DateTime->new(
year => 2003,
month => 5,
day => 6,
time_zone => 'America/Chicago',
);
# is DST
my $dt2 = DateTime->new(
year => 2003,
month => 11,
day => 6,
time_zone => 'America/Chicago',
);
say $dt1;
say $dt2;
my $dur = $dt1->subtract_datetime($dt2);
print Dumper({$dur->deltas});
which when run produces
2003-05-06T00:00:00
2003-11-06T00:00:00
$VAR1 = {
'minutes' => 0,
'nanoseconds' => 0,
'months' => -6,
'seconds' => 0,
'days' => 0
};
Note the -6 months offset. DateTime::Duration objects will not convert between months and days according to the documentation so this looks like a dead end.
The delta_days method you looked at first returns the actual difference in days, but as noted it's an absolute value. You can add a check to convert it to negative if the first date is before the second:
my $days = $dt1->delta_days($dt2)->in_units('days');
$days *= -1 if $dt1 < $dt2;
say $days; # Prints -184
and a variation of your delta_days() function:
sub delta_days {
my $date1 = shift;
my $date2 = shift;
my $d1 = str_to_date_object($date1);
my $d2 = str_to_date_object($date2);
return $d1->delta_days($d2)->in_units('days') * ($d1 < $d2 ? -1 : 1);
}
say delta_days('2021-10-21', '1980-8-20');
say delta_days('1980-8-20', '2021-10-21');
PERL : I take mday value from locatime as below ,now I want value of day before yesterday . How can I subtract 1 from mday which I take from localtime
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my $part = "P".$mday;
print "Today value is $part \n";
my $part_yes = "P".$mday - $num;
print "$part_yes \n";
Using DateTime:
my $dt =
DateTime
->now( time_zone => 'local' )
->set_time_zone('floating') # Do this when working with dates.
->truncate( to => 'days' ); # Optional.
$dt->subtract( days => 2 );
my $yesterday = $dt->day;
DateTime is pretty heavy, and it seems people asking date-time questions invariably come back and say "core modules only!", so here's a solution using only core modules.
use Time::Local qw( timegm );
# Create an timestamp with the same date in UTC as the one local one.
my $epoch = timegm(0, 0, 0, ( localtime() )[3,4,5]);
# We can now do date arithmetic without having to worry about DST switches.
$epoch -= 2 * 24*60*60;
my $yesterday = ( gmtime($epoch) )[3] + 1;
my $now = time(); # time as seconds since 1970-01-01
my $day_ago = $now - 24*60*60;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($day_ago);
my $part = "P".$mday;
WARNING (ikegami comment): Not all days have 24 hours. This can produce a result that's 0, 1 or 2 days earlier
https://perldoc.perl.org/functions/time
https://perldoc.perl.org/functions/localtime
I have problem with Perl substr function. It is so simple, but anyway... Don't know what is the problem.
sub encode_date
{
$date = $_[0];
$day = substr($date, 0, 2);
$month = substr($date, 2, 2);
$year = substr($date, 6, 4);
return "$year-$month-$day";
}
Sub accept "DD.MM.YYYY" formatted string and have to convert it to "YYYY-MM-DD" format.
Input : 09.09.1993
Output : 0-09-93-19 ???
Can anybody explain what's wrong, please.
p.s.: I wrote another sub for decoding date (from 'yyyy-mm-dd' to 'dd.mm.yyyy') and all work properly.
sub decode_date
{
$date = $_[0];
$year = substr $date, 0, 4;
$month = substr $date, 5, 2;
$day = substr $date, 8, 2;
return $day.".".$month.".".$year;
}
Sure, I tried both substr $date, 0, 2; and substr($date, 0, 2); and different combinations of the return value.
Month starts at index 3, not 2.
sub encode_date
{
my ($date) = #_;
my $day = substr($date, 0, 2);
my $month = substr($date, 3, 2);
my $year = substr($date, 6, 4);
return "$year-$month-$day";
}
Perhaps better way would be splitting string by non-digit(.), reverse numbers, and join them with dash -
sub encode_date
{
my ($date) = #_;
return join "-", reverse split /\D/, $date;
}
Your problem is that your offsets are wrong, because they don't take into account the separators. (For example, the month starts at offset 3, not 2, because it comes after the two-character date plus a period.)
That said, I think the best way to write this function is:
sub encode_date($) {
if ($_[0] =~ /^(\d\d)\.(\d\d)\.(\d{4})$/) {
return "$3-$2-$1";
}
}
sub encode_date
{
$date = $_[0];
$day = substr($date, 0, 2);
$month = substr($date, 3, 2);
$year = substr($date, 6, 4);
return "$year-$month-$day";
}
There were 2 problems. I used encode_date(encode_date($date)); (2 times)Another was $month = substr($date, 2, 2); Correct is $month = substr($date, 3, 2);
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
I thought this was going to be very simple but I am really out of options now. I want to substract 15 minutes from a given time.
Example
My time is 15:04 I want to substract 15 minutes to be 14:49. I have searched for solutions on the internet but there is no perl module that can help me out.
You can use DateTime:
my $dt = DateTime->new(
year => 1,
month => 1,
day => 1,
hour => 15,
minute => 4,
);
$dt->subtract(minutes => 15);
printf "%d:%d\n", $dt->hour, $dt->minute; # prints 14:49
Well it all depends on how your time is stored. I prefer to use a time_t as returned by the time built in.
my $now = time();
my $before1 = $now - (15*60); # 15 minutes ago
my $before2 = $now - (3*60*60); # 3 hours ago
my $before3 = $now - (2*24*60*60); # 2 days ago
For output I use the POSIX module
print POSIX::strftime( '%Y-%m-%d %T', localtime($before1) );
perl -MClass::Date -e 'my $d=Class::Date->new("2011-07-13 15:04:00"); my $d2 = $d-"15m"; print $d2, "\n";'
Output:
2011-07-13 14:49:00
Try using Date::Calc
use Date::Calc qw(Add_Delta_DHMS);
($year2, $month2, $day2, $h2, $m2, $s2) =
Add_Delta_DHMS( $year, $month, $day, $hour, $minute, $second, $days_offset, $hour_offset, $minute_offset, $second_offset );
($y,$m,$d,$H,$M,$S) = Add_Delta_DHMS(Today_and_Now(), 0, 0, -15, 0);
convert the time to unix time, for example the current time: $unixtime = time(); then subtract 15*60 from it then convert to a nice string with something like
sub display_time {
my ($sec,$min,$hour,$mday,$mon,$year,undef,undef,undef) = localtime(time);
$year += 1900;
$mon += 1;
return "$year.".sprintf("%02d.%02d %02d:%02d:%02d",$mon,$mday,$hour,$min,$sec);
}
You can use the below sub-routine if you are only concerned about time not date:
sub subTime{
my ($time) = #_;
my #splittime = split(':', $time);
my $hour = $splittime[0];
my $min = $splittime[1];
if($min < 15){
$min=($min+60)-15;
$hour-=1;
}
else{
$min = $min-15;
}
return "$hour:$min";
}
Disclamer: This was the solution OP used, he mentioned it in comments in above answer (in #eugene's answer).