Compare date time zone with time() in perl - 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;

Related

Converting string to date time using Perl

I am not a perl programmer, but I'm trying to update someone else's code. I need to format the date and time. I have three variables returned from a database. One variable contains the time, one has AM/PM, on has the date in mm/dd/yyyy format. For example:
variable1 = 10:00
variable2 = PM
variable3 = 11/27/2019
I need to take these three variables and format them accordingly: 2019-11-27 20:00:00
How could I go about doing this?
The strptime and strftime functions can do this. One version of these is provided by the core module Time::Piece:
use strict;
use warnings;
use Time::Piece;
my $time = '10:00';
my $ampm = 'PM';
my $date = '11/27/2019';
my $tp = Time::Piece->strptime("$date $time $ampm", '%m/%d/%Y %I:%M %p');
print $tp->strftime('%Y-%m-%d %H:%M:%S'), "\n";

Subtract two date strings in Perl with conversion to unix time and reverting back

I want to subtract two timestamps in Perl. I converted them to unix-time via the function below and convert the unix timestamp back to how it was. In the example below the result is 01:20:00 instead of 00:20:00
(I think it has sth to do with the start of the unix timestamp 1.1.1970 01:00:00 but not sure how to resolve it)
Any idea? Many thanks for your help in advance.
use POSIX qw( strftime );
use Time::Local qw( timelocal );
sub to_epoch {
$_ = shift;
my #a = split /\W+/, $_;
my $b = timelocal($a[5],$a[4],$a[3],$a[2],$a[1],$a[0]);
return $b;
}
my $h_end = "2018.11.12 00:50:00";
my $h_start = "2018.11.12 00:30:00";
my $duration = to_epoch($h_end) - to_epoch($h_start);
my $convert_back = POSIX::strftime("%H:%M:%S", localtime($duration));
print $convert_back , "\n";
Ouptut: 01:20:00
It works for me. But I think that's because I'm in GMT and you're in CET (GMT+1).
The flaw is in your final step. You are confusing two concepts - a point in time and a duration.
You correctly convert your two points in time to Unix epoch numbers and then you subtract those numbers to get the number of seconds between them. That number is a duration. And you want to convert that duration into a human-readable format. Using localtime() and POSIX::strtime() is not the way to do that. POSIX::strftime() and localtime() deal with points in time, not durations.
The number you get is 1,200. By passing that to localtime() you are saying "what is the epoch number 1,200 when converted to a date and time in my local timezone?" 1,200 is 20 past midnight on Jan 1st 1970 GMT. But in your local, Frankfurt, timezone, it's 20 past 1am. Which is why you're getting 1:20 and I'm getting 0:20.
There are a couple of ways to fix this. You can do the conversion manually.
my $duration = 1_200;
my $mins = int($duration/60);
my $secs = $duration % 60;
Or you can use a proper date/time handling module like DateTime (along with its associated module DateTime::Duration).
It might work if you use timegm() and gmtime() in place of timelocal() and localtime() - but I really don't recommend this approach as it perpetuates the confusion between points in time and durations.
Update: A version using DateTime.
#/usr/bin/perl
use strict;
use warnings;
use DateTime;
use DateTime::Format::Strptime;
my $h_end = '2018.11.12 00:50:00';
my $h_start = '2018.11.12 00:30:00';
my $date_p = DateTime::Format::Strptime->new(
pattern => '%Y.%m.%d %H:%M:%S'
);
my $duration = $date_p->parse_datetime($h_end)
- $date_p->parse_datetime($h_start);
printf '%02d:%02d:%02d', $duration->in_units('hours', 'minutes', 'seconds');
1200, the value of $duration, signifies the following when treated as a epoch timestamp
1970-01-01T01:20:00+01:00
^^^^^^^^
The solution is to replace
strftime("%H:%M:%S", localtime($duration));
with
strftime("%H:%M:%S", gmtime($duration));
This gives
1970-01-01T00:20:00Z
^^^^^^^^
Of course, this is still a hack. You're not suppose to be passing a duration to gmtime. Use an appropriate module instead.
use DateTime::Format::Strptime qw( );
my $format = DateTime::Format::Strptime->new(
pattern => '%Y.%m.%d %H:%M:%S',
on_error => 'croak',
);
my $h_end = $format->parse_datetime('2018.11.12 00:50:00');
my $h_start = $format->parse_datetime('2018.11.12 00:30:00');
my $dur = $h_end - $h_start;
printf "%02d:%02d:%02d\n", $dur->in_units(qw( hours minutes seconds ));
By the way,
timelocal($a[5],$a[4],$a[3],$a[2],$a[1],$a[0])
should be
timelocal($a[5],$a[4],$a[3],$a[2],$a[1]-1,$a[0])

How to convert unknown date/time format into normal using Perl? [duplicate]

This question already has answers here:
How can I parse dates and convert time zones in Perl?
(5 answers)
Closed 7 years ago.
I have a date/time like this: 2015-07-31T13:30:00.000+01:00
And I want to convert it to normal date and time using Perl and Time::Piece->strptime
Here is my code:
sub changeDateFormat {
my ($date, $fromFormat, $toFormat) = (#_);
return Time::Piece->strptime($date, $fromFormat)->strftime($toFormat);
}
The call:
print changeDateFormat($that_date, '%Y-%m-%dT%H:%M:%S.%N+%z', '%Y:%m:%d');
I think that .000 are nano seconds and +01.00 stands for time zone.
But the given code gives this:
Error parsing time at /usr/lib64/perl5/Time/Piece.pm line 470
Any help is appreciated.
There's a couple of problems I think.
%N isn't in my strftime manpage. So that might well not work.
And %z - I'm pretty sure +01:00 isn't valid.
%z The +hhmm or -hhmm numeric timezone (that is, the hour and
minute offset from UTC). (SU)
This works though:
my $date = '2015-07-31T13:30:00+0100';
my $fromFormat = '%Y-%m-%dT%H:%M:%S%z';
print Time::Piece->strptime($date, $fromFormat);
So I'd suggest - unless your milliseconds are important - you could just strip those via a regex, and likewise the timezone. (And it they are important, I don't think Time::Piece does ms resolution anyway)
You can probably use a regular expression to 'correct' your input date if you were so inclined. I'm unsure if fits your use case but:
$date =~ s/\+(\d{2}):(\d{2})$/+$1$2/;
$date =~ s/\.\d{3}+/+/;
You can use strptime in Time::Piece and adding the time zone manually as shown in this answer, or you could try using DateTime::Format::Strptime instead:
use feature qw(say);
use strict;
use warnings;
use DateTime::Format::Strptime;
my $timestamp = '2015-07-31T13:30:00.000+0100';
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%dT%H:%M:%S.%N%z'
);
my $dt = $strp->parse_datetime( $timestamp );
say $dt->strftime('%Y:%m:%d');
Output:
2015:07:31
use DateTime;
use DateTime::Format::ISO8601;
use DateTime::Format::Strptime;
my $string = '2015-07-31T13:30:00.000+01:00';
my $date = DateTime::Format::ISO8601->parse_datetime( $string );
die "Error" unless $date;
my $formatter = new DateTime::Format::Strptime(pattern => '%Y-%m-%d %T');
$date->set_formatter($formatter);
print "$date\n";

Create time variable in perl

I want to create a variable that will store hardcoded hours and minutes value. Rest stuff like min, day, date, year should be current date and time. How can I do this? I tried timelocal, localtime and many others, but they didn't work.
If you are interested in a complete date time object (like it seems according your description), use DateTime. Example:
use DateTime;
my $dt = DateTime->now; # initialize with current date time
$dt->set_hour(20); #set your own hour
$dt->set_minute(20); #set your own minute
Unless I'm missing something, you indeed use localtime, as in perldoc:
http://perldoc.perl.org/functions/localtime.html
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
Then, if you want to stick to using the broken-down components, you could overwrite whichever variables you want to "fix":
$hour = $my_hardcoded_hour;
$min = $my_hardcoded_minute;
If instead you need to translate this back to "seconds since the epoch" (Jan 1, 1970, 12:00AM GMT) format, you need the Time::Local package:
http://perldoc.perl.org/Time/Local.html
use Time::Local;
$epoch_current_time_with_fixed_hour_min =
timelocal($sec, $my_hardcoded_minutes, $my_hardcoded_hour, $mday, $mon, $year);

How do I convert datetime to a different format? [perl]

Need help parsing the datetime stamp and splitting it up by date and time.
use strict;
use warnings;
use Time::Piece;
my $string = "05:57:03 08/31/10 MDT";
print $string,"\n";
my $time = Time::Piece->strptime($string, "%H:%M:%S");
my $date = Time::Piece->strptime($string, "%Y/%m/%d");
print $time,$date,"\n";
Thanks! Also how do I figure out which day of week this is using code?
use DateTime::Format::Strptime;
my $s = DateTime::Format::Strptime->new(pattern => '%T %D %Z');
my $dt = $s->parse_datetime('05:57:03 08/31/10 MDT');
say $dt->strftime('%A'); # Tuesday
You should be able to use code like the following:
my $t = Time::Piece->strptime($string, "%H:%M:%S %m/%d/%y %Z");
However, on my system at least, I have to change the time zone MST to GMT for it to match; if I leave it as in your example, I get an error:
Perl> my $t = Time::Piece->strptime("05:57:03 08/31/10 DST", "%H:%M:%S %m/%d/%y %Z");
[!] Runtime error: Error parsing time at /usr/local/lib/perl/5.10.0/Time/Piece.pm line 469.
If it works for you, though, you'll have a Time::Piece object, on which you can call e.g. $t->day_of_week for the day of the week as a number, $t->day for e.g. 'Tue', or $t->fullday for e.g. 'Tuesday'.
See the documentation for Time::Piece for details on the methods you can call.