Convert string date to Perl DateTime - perl

I'm a newbie in Perl, so please be patient with me:
I am writing a log parser and have successfully parsed "Dec 1 17:45:36.185" into it's individual units (month, day, hour, minute, seconds, milliseconds). I want to convert this to Perl's DateTime object.
I'm having trouble with the milliseconds portion: .185.
I hope to use DateTime::Format::Strptime like such:
my $strp = DateTime::Format::Strptime(
pattern => "%b %d %H:%M:%S" # how do I add the milliseconds part?
)

If you want to display milliseconds, use this format %3N:
my $strp = DateTime::Format::Strptime(
pattern => "%b %d %H:%M:%S.%3N" # now we have the milliseconds part
)
The number jut before the N means the number of digits that will be displayed.
The number displayed is truncated, not rounded.

I might be missunderstanding you. But if you want to have an object of this: http://metacpan.org/pod/DateTime and know the individual numbers, why not use the constructor like so:
use DateTime;
$dt = DateTime->new(
year => 1964,
month => 10,
day => 16,
hour => 16,
minute => 12,
second => 47,
nanosecond => 500000000,
time_zone => 'Asia/Taipei',
);
Or do you wonder how to format that information into a string later? In that case, you could just use sprintf and DateTimes get methods to produce any format you want.
edit: I think i understood you now. DataTime does not have ms, only ns. When constructing, that is no problem, as you can just put nanosecond => ($ms*1000000) but i see how that can be a problem when using ::Strptime.
I cannot install DateTime here to test it, but the CPAN does say
%N
Nanoseconds. For other sub-second values use %[number]N.
So when you have a DateTime object with nanoseconds, you could play with that [number] value to see what it does and when you have found a way to tell it that you like ms, it should even work for parsing.

Related

Parsing timestamp string to integer and subtract hires timestamp

New to perl. I have a string that is in this form 20190123120445, i.e. YYYYMMDDHHMISS. In perl how do you turn this into a timestamp that can be used to subtract another timestamp generated from a Time::Hires time timestamp. I know the timestamps are different resolutions and will assume that the first timestamp starts at 0 ms.
I can turn the timestamp into a DateTime object, however attempting to subtract the hires timer value result in error.
How do I turn the first string into a timestamp of the same resolution as the time timestamp, so that I can subtract the values and get a delta? Or is there a more obvious solution?
use Time::Hires;
use Date::Parse;
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y%m%d%H%M%S',
on_error => 'croak',
);
my $dt = $parser->parse_datetime($args->{EVENTCREATEDTIMESTAMP});
my $delta = time - $dt;
If I attempt to do this, I get this error
Bad message vendor or subscription: Cannot subtract 1548265276 from a
DateTime object (DateTime=HASH(0x28e10d98)). Only a DateTime::Duration
or DateTime object can be subtracted from a DateTime object.
To submit it as a proper answer: To get an epoch timestamp which is the same format you get from time, call the epoch method on the DateTime object. You can easily subtract epoch timestamps to get a difference in seconds, and then convert that to larger denominations. Time::Seconds provides useful constants for this if you prefer.
use strict;
use warnings;
use Time::Seconds;
my $diff = time - $dt->epoch;
my $diff_hours = $diff / ONE_HOUR;
If you want a calendar duration difference, things get complicated. This is because there is no static definition of things like "one month" or even "one day" and "one minute", because of gross things like daylight savings and leap seconds. So the difference depends on the time zone and the absolute start and end time. The simplest way to deal with this is turn your epoch timestamp into a DateTime object and have DateTime do the work for you.
my $dt_time = DateTime->from_epoch(epoch => time);
# Each of the following returns DateTime::Duration objects with different measures of calendar time
my $diff_duration = $dt_time->subtract_datetime($dt); # months, days, minutes, seconds, nanoseconds
my $diff_days = $dt_time->delta_days($dt); # full days
my $diff_ms = $dt_time->delta_ms($dt); # minutes and seconds
my $diff_abs = $dt_time->subtract_datetime_absolute($dt); # seconds and nanoseconds
The individual components of the resulting DateTime::Duration objects can be retrieved with the in_units method or by passing it to DateTime::Format::Duration. The subtract_datetime_absolute method is the only way to count leap seconds - epoch timestamps effectively ignore them, and "minutes" from the other methods may not be 60 seconds long.

Calculate number of days between two dates in Perl

I am using Perl to create a script that will email password expiration notifications.
I have two dates:
The date that the users password was set
The date that the users password will expire (180 days after the password was set)
use DateTime::Format::Strptime;
my $dt_pattern = DateTime::Format::Strptime->new( pattern => '%F',);
my $displayName = $entry->get_value("displayName");
my $pwdLastSet = convertWinFileTimestamp($entry->get_value("pwdLastSet"));
# Determine password expiration date
my $pwdLastSet_dt = $dt_pattern->parse_datetime($pwdLastSet);
my $pwdExpirationDate = $pwdLastSet_dt->add( days => $maxPwdAge );
# Days until password expires
# HELP!!!!!!!
sub convertWinFileTimestamp {
my $timestamp = shift;
# Strip off nanoseconds, then adjust date from AD epoch (1601) to UNIX epoch (1970)
return POSIX::strftime( "%Y-%m-%d",
localtime( ( $timestamp / 10000000 ) - 11644473600 ) );
}
I cannot figure out how to calculate the difference between the two dates!
Below is the output for each variable:
pwdLastSet: 2015-02-12
pwdExpireDate: 2015-08-11T00:00:00
Any help much appreciated...been googling like crazy but I can't figure it out...Thanks!
I tried the following lines of code:
my $pwdDaysLeft = int(($pwdExpirationDate - $pwdLastSet) / 86400);
but got the following error:
Only a DateTime::Duration or DateTime object can be subtracted from a DateTime object. at pwdreminder.pl line 65
So, we have three dates here:
The date that the password was last set. This starts off as a string in the format YYYY-MM-DD stored in $pwdLastSet, but then you parse it into a DateTime object stored in $pwdLastSet_dt.
The date that the current password expires. This is calculated by adding $maxPwdAge days to $pwdLastSet_dt, which gives a DateTime object which is then stored in $pwdExpirationDate.
The current date. Which, in your current code, you don't calculate.
What you actually want is the difference in days a between the second and third of these two dates. We can ignore the first date as is it only used to calculate the second date. I assume that you're calculating that correctly.
Hopefully, the password expiration date will always be in the future. So the calculation we want to do is:
my $diff = $pwdExpirationDate - $current_date;
As long as both of those are DateTime objects, we'll get a DateTime::Duration object back, which we can then ask for the number of days.
DateTime has a today() method that will give the current date. So our code becomes:
# Use delta_days() to get a duration object that just contains days
my $diff = $pwdExpirationDate->delta_days(DateTime->today);
print $diff->in_units('days');

Carbon Difference in Time between two Dates in hh:mm:ss format

I'm trying to figure out how I can take two date time strings that are stored in our database and convert it to a difference in time format of hh:mm:ss.
I looked at diffForHumans, but that does give the format I'd like and returns things like after, ago, etc; which is useful, but not for what I'm trying to do.
The duration will never span days, only a max of a couple hours.
$startTime = Carbon::parse($this->start_time);
$finishTime = Carbon::parse($this->finish_time);
$totalDuration = $finishTime->diffForHumans($startTime);
dd($totalDuration);
// Have: "21 seconds after"
// Want: 00:00:21
I ended up grabbing the total seconds difference using Carbon:
$totalDuration = $finishTime->diffInSeconds($startTime);
// 21
Then used gmdate:
gmdate('H:i:s', $totalDuration);
// 00:00:21
If anyone has a better way I'd be interested. Otherwise this works.
$finishTime->diff($startTime)->format('%H:%I:%S');
// 00:00:21
$start = new Carbon('2018-10-04 15:00:03');
$end = new Carbon('2018-10-05 17:00:09');
You may use
$start->diff($end)->format('%H:%I:%S');
which gives the difference modulo 24h
02:00:06
If you want to have the difference with more than 24h, you may use :
$start->diffInHours($end) . ':' . $start->diff($end)->format('%I:%S');
which gives :
26:00:06
I know this is an old question, but it still tops Google results when searching for this sort of thing and Carbon has added a lot of flexibility on this, so wanted to drop a 2022 solution here as well.
TL;DR - check out the documentation for different/more verbose versions of the diffForHumans method, and greater control over options.
As an example, we needed to show the difference between two Carbon instances (start and end) in hours & minutes, but it's possible they're more than 24 hours apart—in which case the minutes become less valuable/important. We want to exclude the "ago" or Also wanted to join the strings with a comma.
We can accomplish all of that, with the $options passed into diffForHumans, like this:
use Carbon\CarbonInterface;
$options = [
'join' => ', ',
'parts' => 2,
'syntax' => CarbonInterface::DIFF_ABSOLUTE,
];
return $end->diffForHumans($start, $options);
Which will result in values like what's seen in the Duration column:
Hope that's helpful for someone!
You can do it using the Carbon package this way to get the time difference:
$start_time = new Carbon('14:53:00');
$end_time = new Carbon('15:00:00');
$time_difference_in_minutes = $end_time->diffInMinutes($start_time);//you also find difference in hours using diffInHours()

How do I use Date::Manip to create a date usable by Date::ICal?

I need to take the result of a Date::Manip ParseDateString() and use it as the bast for an Date::ICal::Event
Date::ICal::Event has the following date creating inputs:
use Date::ICal;
$ical = Date::ICal->new( ical => '19971024T120000' );
$ical = Date::ICal->new( epoch => time );
$ical = Date::ICal->new( year => 1964,
month => 10, day => 16, hour => 16,
min => 12, sec => 47 );
Date::Manip ParseDateString() returns a standard date value.
How should I use that date in the ICal date? Convert to epoch? Can it easily be converted to the ical format? I feel like this should be easier than it is.
Here's what I'd do:
sub date2ical
{
my $date = shift;
Date::ICal->new( ical => UnixDate($date, '%QT%H%M%S'), # %Q means %Y%m%d
offset => UnixDate($date, '%z'));
} # end date2ical
# Usage:
my $ical = date2ical(ParseDateString('today'));
This should properly handle timezones (provided Date::Manip gets the timezone right).
I did some further CPAN hunting and came up with the module DateTime::Format::DateManip
Using this I was able to convert it to a DateTime representation and then get the epoch from that using the epoch method available in DateTime:
my $cagedate = ParseDateString($cagewatch);
my $cagedatetime = DateTime::Format::DateManip->parse_datetime($cagedate);
$vevent->add_properties(
summary => $cagemovie,
description => $cagemovie,
dtstart => Date::ICal->new( epoch => $cagedatetime->epoch )->ical,
);
Just in case you are curious about the CAGE variables. I was parsing the list of movies for the Year of the Cage. All Nick Cage, all year. Oh yeah.
Your life will be so much easier if you dump Date::Manip and switch to DateTime for all your date and time processing. There's even a DateTime::Format::ICal to help with this specific task.
It seems that, if you've got a date into Date::Manip successfully, you can just use its printf directives to output it in any format you want.
It looks like %Y%m%dT%H%M%S is what you want for iCal.

Greenwich Mean Time to Indian Standard Time

How to convert given Greenwich Mean Time to Indian Standard Time in perl?
Thanks
It helps to know what format your desired input/output are, but:
use DateTime;
$datetime = DateTime->new( year => 2010, month => 12, day => 27, hour => 15, minute => 45, second => 15, time_zone => 'GMT' );
$datetime->set_time_zone( 'Asia/Kolkata' );
print $datetime->ymd, ' ', $datetime->hms;
Have you tried using the DateTime::TimeZone module? I believe it's got some pretty easy-to-use methods for time-manipulation.