How to get timestamp in minutes using Perl - 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.

Related

How to ignore files over two hours from a timestamp range in Perl

I am trying to set up a timestamp range for a file that is not over 2 hours in Perl. Taking times from file are formatted as "May 26 20:30 filename.csv" in perl format.
Here is what I am setting up:
use File::stat;
my $stat = stat($file);
# To start a time within a range or no more than 2 hours
my $start = UnixDate("now", "%m%d %H:%M");
my $stop = UnixDate("$start"+2, "%m%d %H:%M"); // here max it to 2 hours, not sure this part
if ($stat->$start <= $stat->$stop) { next; }
Since you say that UnixDate returns an epoch timestamp, all you need is this:
my $cutoff = time - 2*60*60;
my $file_time = UnixDate( "%m%d %H:%M", $fn );
next if $file_time < $cutoff;

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;

Get Execution Time Difference and Display it in Seconds

I have browse SO for last 30 mins but couldn't get answer, so decided to post question.
I cannot use Time::Piece or Date::Parse module as suggested in some answers.
I'm trying to subtract two times and get result in seconds
use warnings;
use strict;
$tod = `date "+%H:%M:%S"`; chomp $tod; #record time of the day to variable
#Sample time 16:55:44
my startTime = $tod;
Insert records;
my endTime = $tod;
my totalTime = $startTime - $endTime;
Error:
Arguemnt "16:55:14" isn't numeric in subtraction (-)
Thanks,
You can use the time function:
my $start = time;
sleep 3;
my $end = time;
print $end - $start, ' seconds elapsed';
In general, it's best to avoid executing external commands with backticks or system when you can do the same thing with pure Perl.
If you want better than one-second resolution, you can use Time::HiRes as described in Is there a better way to determine elapsed time in Perl?
Time::Piece has come with Perl since 5.10 which was seven years ago, I'm a bit dubious about your claim to not be able to use it and it's really going to cause a lot of unnecessary pain in the long term to not use modules. You can check these things using Module::CoreList. Anyhow...
You can convert the "HH:MM:SS" time of day into seconds since midnight. Fortunately you're using 24 hour time which makes this simpler.
sub time_of_day_to_seconds {
my $tod = shift;
my($hour, $min, $sec) = split /:/, $tod;
my $total_seconds = $sec;
$total_seconds += $min * 60;
$total_seconds += $hour * 60 * 60;
return $total_seconds;
}
If you cannot avoid to get the time as a string, you can use DateTime::Format::Strptime in combination with Datetime::Duration.
Bear in mind you will have to install it since it is not in the core modules...anyway here an example:
use warnings;
use strict;
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new( pattern => '%T', );
my $diff = $strp->parse_datetime("23:23:12") - $strp->parse_datetime("23:23:10");
print join('-',$diff->deltas()); #months-0-days-0-minutes-0-seconds-2-nanoseconds-0
Hope this helps!

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});

Use Perl to Add 2 days to Today

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