Use Perl to Add 2 days to Today - perl

I want to use perl and add two days from today and output this as a unix time. I have found lots of information on how to convert Unix time to readable time but I need the ouput to be a unix time. I found this
my $time = time; # or any other epoch timestamp
my #months = ("Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec");
my ($sec, $min, $hour, $day,$month,$year) = (localtime($time))[0,1,2,3,4,5];
# You can use 'gmtime' for GMT/UTC dates instead of 'localtime'
print "Unix time ".$time." converts to ".$months[$month].
" ".$day.", ".($year+1900);
How do I take current time and add 2 days and output as Unix time.

Have you considered using the DateTime package? It contains a lot of date manipulation and computation routines, including the ability to add dates.
There is an FAQ, with examples, here (in particular, see the section on sample calculations and DateTime formats).
Here is a snippet:
use strict;
use warnings;
use DateTime;
my $dt = DateTime->now();
print "Now: " . $dt->datetime() . "\n";
print "Now (epoch): " . $dt->epoch() . "\n";
my $two_days_from_now = $dt->add(days => 2);
print "Two days from now: " . $two_days_from_now->datetime() . "\n";
print "Two days from now (epoch): " . $two_days_from_now->epoch() . "\n";
Which produces the following output:
Now: 2013-02-23T18:30:58
Now (epoch): 1361644258
Two days from now: 2013-02-25T18:30:58
Two days from now (epoch): 1361817058

yuu can change the timestamp, which is seconds from epoc
change
my $time = time;
to
my $time = time + 2 * 24 * 60 * 60 ; # 60 seconds 60 minutes 24 hours times 2

Now is time(). Two days from now is time() + 2 * 86400. Today (midnight at the beginning of the current day) is int(time() / 86400) * 86400. Two days from today is today plus 2 * 86400. localtime in scalar context will print any of them out as a readable date, unless you really want gmtime or strftime (from the POSIX module).

The time function returns the current epoch seconds, and core module Time::Seconds provides useful constants for time periods.
use strict;
use warnings;
use Time::Seconds 'ONE_DAY';
print time + ONE_DAY * 2;
output
1361872751

Related

How can I convert the epoch time to YMD in Perl?

I am trying to convert a date from epoch to year month day and get the correct date.
my $day = 18322;
my ($y, $m, $d) = (gmtime 86400*$day)[5,4,3];
The epoch date is 1583020800 The conversion is as follows $y is 120 $m is 2 $d is 1
I guess I have to add $y = $y+1900 I get the correct year, I can add 1 to $m to get the correct month the day $d I don't have to add anything to. Is this correct. I am taking over code for someone but I have no idea what [5,4,3] does.
Epoch time 1583020800 is Sun Mar 1 00:00:00 2020.
You can use gmtime, but it's awkward. It returns an array of values and they need to be converted. The year is the number of years since 1900 and the month starts at 0. This is because it is a thin wrapper around struct tm from the C programming language Perl is written in.
my($y,$m,$d) = (gmtime(1583020800))[5,4,3];
$y += 1900;
$m += 1;
printf "%04d-%02d-%02d\n", $y, $m, $d;
Instead, use the built in Time::Piece.
use v5.10;
use Time::Piece;
my $time = Time::Piece->gmtime(1583020800);
say $time->ymd;
Or the more powerful DateTime.
use v5.10;
use DateTime;
my $dt = DateTime->from_epoch(epoch => 1583020800);
say $dt->ymd;
The (...)[5,4,3] is a literal list slice. The thing inside the parens creates a list, but this selects only elements 5, 4, and 3.
The gmtime docs point to localtime, which shows you the position of each thing in its list:
localtime
Converts a time as returned by the time function to a 9-element
list with the time analyzed for the local time zone. Typically
used as follows:
# 0 1 2 3 4 5 6 7 8
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
I would use Time::Piece as in Schwern's answer. But just to cover all bases, you can use the strftime() function from POSIX.pm as well.
use feature 'say';
use POSIX qw[strftime];
say strftime('%Y-%m-%d', gmtime(1583020800));
Output:
2020-03-01
You can pass different format strings to strftime().

How to find the difference of time in hours between local time and user-defined time?

#!/usr/bin/perl
sub parkingcharge {
sub exittime
{
($sec, $min, $hour) = localtime();
print "exit time:$hour:$min:$sec\n";
}
my $exit = exittime();
my $entry = "9:10:8";
print "\nvehicle entry time is :$entry\n";
print "\nvehicle exit time is :$exit\n";
my $parkingCharge = ($entry - $exit);
print "\ntotal parking charge is : $parkingCharge\n";
}
parkingcharge();
The output appears like this
exit time:5:46:57
vehicle entry time is :9:10:8
vehicle exit time is :1
total parking charge is : 8
I want to find the parking charge in a Perl vehicle management program. The rate is $2 per hour, so I want to find the difference between entry time and exit time in hours and multiply by 2. The code I have written produces the wrong result.
How to take the difference between times in hours?
You can use Time::Piece, which is included with Perl. It gives you a convenient way to parse dates into Time::Piece objects, which are essentially epoch timestamps with syntactic sugar. The nice thing about them is that you can use them in math and you'll get seconds.
Because you only have times, we need to have the same date for both the entry and the exit time. One way to do that would be to check today's date and use it in both variables. But it's easier to just leave it out. Time::Piece will assume it's 1970-01-01, which is fine, because we don't care. It's only important that both timestamps have the same date as long as you cannot park over night.
use strict;
use warnings;
use Time::Piece;
my $entry = Time::Piece->strptime( '9:10:8', '%H:%M:%S' );
We use the strptime method to parse the entry time. The second argument is a pattern of placeholders. %H is hours in 24 hour notation, %M is minutes and %S is seconds. This also works without the leading zeroes.
We now have an entry date of 1970-01-01 09:10:08, or Thu Jan 1 09:10:08 1970 if you just print $entry.
Next we need to get the exit time.
my ( $sec, $min, $hour ) = localtime;
my $exit = Time::Piece->strptime( "$hour:$min:$sec", '%H:%M:%S' );
Because just using localtime in scalar context would give us today's date, we have to do an extra step. Your code already got the seconds, minutes and hours of this moment. We just use that as a string in the right format and feed it into strptime the same way we did for $entry. Now we have the exit timestamp, which is Thu Jan 1 14:46:56 1970 while I write this.
Getting the duration is a simple matter of subtraction. Converting it to hours is just a division by 60 for minutes and by 60 for hours.
my $duration = $exit - $entry;
my $duration_in_hours = $duration / 60 / 60;
The $duration_in_hours is 5.61333333333333 for me right now. If you want people to pay for every started hour, you'd have to round up.
my $fee_started_hours = int( $duration_in_hours + 1 ) * $hourly_fee;
I prefer to only pay for full hours of parking, so I'd like rounding down more.
my $fee_full_hours = int( $duration_in_hours ) * $hourly_fee;

Compare date time zone with time() in perl

I am trying to compare a file creation time which is in the format: 08-07-2016 08:16:26 GMT with the current time using time() in perl.
Since time() returns epoch time, I am not sure how to find the time difference between these two different time formats.
I tried something like below and for obvious reasons, I get an error saying: "Argument 08-07-2016 08:16:26 GMT" isn't numeric in subtraction".
my $current_time = time();
my $time_diff = $creation_time - $current_time;
if ($time_diff > 10) { #compare if the difference is greater than 10hours
# do something...
}
Some of the questions I have:
Since I want to compare only the hour difference, how can I extract just the hours from both these time formats?
I am unsure if the comparison of $time_diff > 10 is right. How to represent 10hours? 10*60?
OR is there a way to at least convert any given time format into epoch using DateTime or Time::Local?
How can I pass a a date parameter to a DateTime constructor?
my $dt1 = DateTime-> new (
year =>'1998',
month =>'4',
day =>'4',
hour =>'21',
time_zone =>'local'
);
Instead can we do something like
my $date = '08-07-2016 08:16:26 GMT';
my $dt1 = DateTime->new($date); # how can i pass a parameter to the constructor
print Dumper($dt1->epoch);
Thanks in advance for any help.
Time::Piece has been a standard part of Perl since 2007.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
use Time::Seconds;
my $creation_string = '08-07-2016 08:16:26 GMT';
my $creation_time = Time::Piece->strptime($creation_string, '%d-%m-%Y %H:%M:%S %Z');
my $current_time = gmtime;
my $diff = $current_time - $creation_time;
say $diff; # Difference in seconds
say $diff->pretty;

How to get timestamp in minutes using Perl

I am using Perl for time comparison.
#!/usr/bin/perl
print $fh "End Time : $endTime ";
print $fh "Before if loop : ", time();
# time() gives current time timestamp
if ( time() < $endTime ) {
print $fh "Inside if loop : ", time();
$exitValue = 11;
}
Currently, i am using if ( time() < $endTime ). Here, time() gives timestamp in millisecomds but i get $endTime as timestamp in minutes.
I want to compare timestamp in munutes.
How do i get timestamp in minutes?
time() gives you the time since the epoch in seconds.
If you want to have minutes, you can use this:
my $time_min = int(time() / 60);
David Cross justly emphasizes that using int() always rounds down. Alternatives include:
my $time_sec = sprintf '%.0f', time() / 60; (Note: uses "half-to-even" rounding)
use Math::Round
as FSp suggested, use POSIX' floor() or ceil()
I see two possible solutions:
you can multiply $endTime by the milliseconds in a minute (i.e. $endTime = $endTime * 60000) and later compare it with time() as you are doing
you can take the integer division of time() by the milliseconds in a minute (i.e. if (floor(time() / 60000) < $endTime) ...). As long as I know, you need to use POSIX in order to use floor
The first would be my favourite option.

Computing small time differences in Singapore adds 30 minutes when converted to hh:mm:ss.mmm

I have this Perl script where I need to monitor the execution time of DBI calls.
In Europe (France), I have no problem: 2 seconds execution time is reported 2 seconds.
This same script running on a computer in Singapore reports 30 minutes and 2 seconds.
Why ?
use strict;
use Time::Format qw(%time);
use Time::HiRes qw(gettimeofday);
my $time_start = gettimeofday();
sleep 2; # some action goes here
my $stat_perf = gettimeofday() - $time_start;
print STDOUT $time{'mm:ss.mmm', $stat_perf} . " \n";
The output in France is
00:02.000
The same script running in Singapore yields:
30:02.001
Why ?
According to this documentation, the gettimeofday function returns seconds or microseconds since the unix epoch, which is 1/1/1970 UTC. Because it is in UTC, it is not affected by time zones at all.
Also, in your original code you are just using gettimeofday, which is going to be returning timestamps from now, not from 1970. But in your suggested answer, for some reason, you have hard-set the timestamp, which won't help you do much.
Yes, there is history to just about every time zone, including Singapore. You can see it in the TZDB here. But you are incorrect about it being +8:30 at the epoch. It was actually +7:30. You can verify also on this site. But it doesn't matter anyway because like I said, gettimeofday works strictly in UTC.
I think the problem is in how you are interpreting the results. You have as your last line:
print STDOUT $time{'mm:ss.mmm', $stat_perf} . " \n";
But $stat_perf is the elapsed duration of time, not a value that you can treat as a timestamp. You probably shouldn't be passing it to $time, since that will use the local time zone and be expecting a full timestamp.
Also, you may want to use tv_interval, as shown in the examples.
Update
I searched through the CPAN archives and I'm sure somewhere there is a module for formatting an elapsed duration of time, but I can't seem to find it. Anyway, it's not too hard to write this on your own. Here, this should work:
my $min = $stat_perf / 60;
my $sec = ($stat_perf * 1000 % 60000) / 1000;
my $elapsed = sprintf("%02u:%06.3f", $min, $sec);
print STDOUT $elapsed . "\n";
The anser is ...
Singapore is now 08h00 offset from UTC. In 1970, it was offset by 08h30. Asking for the conversion of a few seconds into a string will get us to 1970, not today's date, and timezone.
By requesting
print STDOUT $time{'mm:ss.mmm', 2} . " \n";
the system adjusts to 1970 (epoch) timezone offset.
In order to get a correct result in Singapore, we must shift to after 1982, when Singapore made its last timezone change.
print STDOUT $time{'mm:ss.mmm', 2 + 1356994800} . " \n";
as
UNIX_TIMESTAMP('2013-01-01 00:00:00') = 1356994800
We are only concerned by the time of day portion of the date, so this does it.
Check with
zdump -v Asia/Singapore
This is the trick.
Here is a script that emulates $time{} in converting a real number into a string representing the mm:ss sexagesimal conversion of its integer part, concatenated with the decimal remainder formatted as microseconds.
As this is going to be part of a library, there are protections set to avoid invoking it with bad arguments.
I hope I didn't miss something.
use strict;
use Time::Format qw(%time);
# ----------------------------------------------------------
# A substitute to $time{} as we have issues with TZ offsets at epoch days in some part of the World
# A real to sexagesimal converter
# Format will be set to match $time{'mm:ss.mmm', $stat_perf};
sub microTime {
return '' unless (my ($intertime) = #_);
return '' unless (ref ($intertime) eq '');
return '' unless (sprintf("%s", $intertime) =~ m/^(?:[\d]+)(?:\.(?:[\d]+))?$/);
my $intNum = int($intertime);
"a" =~ /a/; # Resets regex buffers
sprintf ("%.03f", $intertime - $intNum) =~ m,\.([\d]+),;
my $intDec = $1; # It's always defined
my $intUnder = $intNum % 3600;
my $intMin = int($intUnder / 60);
my $intSec = $intUnder % 60;
return sprintf ("%02d:%02d.%03d", $intMin, $intSec, $intDec);
}
my $stat_perf;
$stat_perf = 345.987;
$stat_perf = 345;
$stat_perf = 3945.987;
$stat_perf = 0;
$stat_perf = 3945.918733;
print STDOUT sprintf (" >> %s\n", &microTime ($stat_perf));
print STDOUT sprintf (" == %s\n", $time{'mm:ss.mmm', $stat_perf});