How to change ctime to normal string representation? - perl

Using File::stat we can get the ctime of a given file. My question is how to change the ctime, which means the inode change time in seconds since the epoch, to a normal time representation like "2009-08-26 17:28:28". Is there any build-in or module can solve this task?

The most standard way is to use POSIX module and it's strftime function.
use POSIX qw( strftime );
use File::stat;
my $stat_epoch = stat( 'some_file.name' )->ctime;
print strftime('%Y-%m-%d %H:%M:%S', localtime( $stat_epoch ) );
All these markers like %Y, %m and so on, are defined in standard, and work the same in C, system "date" command (at least on Unix) and so on.

If all you want is a human-readable representation, then
print scalar localtime stat($filename)->ctime;
will do the job. This prints something like "Wed Jun 10 19:25:16 2009".
You can't influence the format, though.
If you want the time in GMT, use "scalar gmtime" instead.
This is a special behaviour of localtime and gmtime in scalar context.

use DateTime;
$dt = DateTime->from_epoch( epoch => $epoch );
The datetime object then contains the representations you require, e.g. $year = $dt->year; etc. In scalar context you get a nice human-readable representation, e.g.
$epoch = 123456789;
$dt = DateTime->from_epoch( epoch => $epoch );
print $dt;
1973-11-29T21:33:09

use File::stat;
use Time::CTime;
$file = "BLAH BLAH BLAH";
$st = stat($file) or die "No $file: $!";
print strftime('%b %o', localtime($st->ctime));
#Feb 11th, for example.

As you can see from the number of answers here, you have lots of options. I like the Date::Format module:
#!/usr/bin/perl
use strict;
use warnings;
use Date::Format;
use File::Stat;
my $fs = File::Stat->new( '.vimrc' );
my $mtime = $fs->ctime();
print time2str( "changed in %Y on %B, %o at %T\n", $mtime );

First, are you really using File::Stat rather than File::stat? If so, and if you have 5.8 or greater, switch to File::stat.
perldoc localtime
localtime EXPR
localtime
Converts a time as returned by the time function to a 9-element list with the time analyzed for the local time zone.
...
In scalar context, localtime() returns the ctime(3) value:
Once you realize thatlocaltime can take an argument, then your mind opens up to all the other possibilities mentioned in this thread.
#!/usr/bin/perl
use strict;
use warnings;
use File::stat;
my $stat = stat 't.pl';
print "$_\n" for $stat->ctime, scalar localtime($stat->ctime);

There's an example in Time::localtime perldoc for using it's ctime() to do this sort of thing.
use File::stat;
use Time::localtime;
my $date_string = ctime(stat($file)->ctime);

Related

Comparing date and time and the same time in perl

I want to compare both date and time check if the timestamp from the file I'm going to open will have equal or greater date and time as if the my timestamp which looks like this:
$Date = "20170608";
$Time = "105006";
My main problem is how to do it efficiently possibly without adding perl libraries and how to check it when there's going to be situation of date switching and the hour will be for example 23:59:44
Time::Piece is core in perl, and supports 'strptime'.
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $Date = "20170608";
my $Time = "10506";
my $ts = Time::Piece->strptime( "$Date $Time", "%Y%m%d %H%M%S" );
print $ts, "\n";
print "Delta:", $ts->epoch - time(), "\n";
Was unclear on what time that $Time represented - strptime converts it to 10:50:06, but I'm guessing it might be intended to be 01:05:06?
If so, then zero pad.
$Time = sprintf ( "%06d", $Time );
To read the timestamp from the file metadata, then you need stat:
my $mtime = (stat $filename)[9];

program to calculate the time

I would like to calculate the the current time and add 2 minutes to it and print the output in the following format. HH:MM . I searched online and came to know that there are lot of CPAN modules that can be used to implement this. But I'd like to do it without cpan modules.
$current_time = time();
$new_time = $current_time + (2*60); // adding two minutes
print( ' the time is ' . $ new_time ) ;
Output : the time is 1424906904
I searched online and came to know that we need to use POSIX perl interface to print the time in the appropriate format. However i'd like to know if there is a way to do this without using any cpan modules.
You can use localtime:
print scalar localtime($current_time);
Or you can run localtime's return values through POSIX::strftime (which is distributed with Perl as a core module):
use POSIX qw(strftime);
print strftime('%Y-%m-%d %H:%M:%S', localtime $current_time);
That's easy to do with localtime. Hours, minutes, and seconds are the 2nd, 1st, and 0th values returned. For example:
my ($sec, $min, $hours) = localtime(time()+120); # add 120 seconds
printf "%02d:%02d:%02d\n", $hours, $min, $sec;
Time::Piece and Time::Seconds have been included with all Perl installations since 2007.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
use Time::Seconds;
my $time = localtime;
$time += 2 * ONE_MINUTE;
say $time->strftime('%H:%M');

Perl script to convert logged datetimes to UNIX epoch timestamps

I have a log file (datetimes.log) consisting of hundreds of thousands of timestamps of the form:
YYYY-MM-DD HH:mm:ss
For example:
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
...etc.
I'd like to write a simple Perl script to output a new unix_timestamps.log file that contains the same entries, but instead of the datetime, to have the corresponding UNIX epoch timestamp. For the example above, the unix_timestamps.log file would have the following info in it:
1364453031
1364453035
1364453043
...etc.
The only thing I can think of is perl convert_2_timestamps.pl:
#!/usr/bin/perl
use warnings;
use strict;
grep m/_(\d{4})(\d\d)(\d\d)/ | POSIX::mktime(?, ?, ?, ?, ?, ?) > unix_timestamps.log
But not sure how to transfer the parameters into mktime, and not sure if this is even the right approach. Thanks in advance.
use strict;
use warnings;
use DateTime::Format::Strptime;
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
on_error => 'croak',
);
while( <DATA> ) {
my $dt = $parser->parse_datetime($_);
print $dt->epoch, "\n";
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
This is a perfect use for the Time::Piece module which has been a standard part of the Perl distribution for over five years.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
# Read the data a record at a time. Data ends up in $_.
# N.B. Using built-in DATA filehandle for this demo.
# In the real world you'd open a separate filehandle.
while (<DATA>) {
chomp;
# Create a Time::Piece object using strptime (that's "string
# parse time") and immediately call the epoch method on the
# new object to get the value you want.
say Time::Piece->strptime($_, '%Y-%m-%d %H:%M:%S')->epoch;
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
You could break up the YYYY-MM-DD HH:mm:ss format like so:
my ( $y, $m, #t ) = split /[-: ]+/, $time_str;
my $time = mktime( reverse #t, $m - 1, $y - 1900 );
But you could also put it in a replace like so:
s{(\d{4})-(0?[1-9]\d?)-(0?[1-9]\d?) (0?\d{1,2}):(0?\d{1,2}):(0?\d{1,2})}{
mktime( $6, $5, $4, $3, $2 - 1, $1 - 1900 )
}e;
Try the Date::Parse CPAN module. (http://metacpan.org/pod/Date::Parse)
With it, your convert_2_timestamps.pl can be just:
#!/usr/bin/perl
use warnings;
use strict;
use Date::Parse;
while (<>) {
chomp;
printf("%s\n", str2time("$_ GMT"));
}
Note that I had to append GMT to your example input to get your expected output.
Run as:
perl convert_2_timestamps.pl < datetimes.log > unix_timestamps.log

Today's Date in Perl in MM/DD/YYYY format

I'm working on a Perl program at work and stuck on (what I think is) a trivial problem. I simply need to build a string in the format '06/13/2012' (always 10 characters, so 0's for numbers less than 10).
Here's what I have so far:
use Time::localtime;
$tm=localtime;
my ($day,$month,$year)=($tm->mday,$tm->month,$tm->year);
You can do it fast, only using one POSIX function. If you have bunch of tasks with dates, see the module DateTime.
use POSIX qw(strftime);
my $date = strftime "%m/%d/%Y", localtime;
print $date;
You can use Time::Piece, which shouldn't need installing as it is a core module and has been distributed with Perl 5 since version 10.
use Time::Piece;
my $date = localtime->strftime('%m/%d/%Y');
print $date;
output
06/13/2012
Update
You may prefer to use the dmy method, which takes a single parameter which is the separator to be used between the fields of the result, and avoids having to specify a full date/time format
my $date = localtime->dmy('/');
This produces an identical result to that of my original solution
use DateTime qw();
DateTime->now->strftime('%m/%d/%Y')
expression returns 06/13/2012
If you like doing things the hard way:
my (undef,undef,undef,$mday,$mon,$year) = localtime;
$year = $year+1900;
$mon += 1;
if (length($mon) == 1) {$mon = "0$mon";}
if (length($mday) == 1) {$mday = "0$mday";}
my $today = "$mon/$mday/$year";
use Time::Piece;
...
my $t = localtime;
print $t->mdy("/");# 02/29/2000
Perl Code for Unix systems:
# Capture date from shell
my $current_date = `date +"%m/%d/%Y"`;
# Remove newline character
$current_date = substr($current_date,0,-1);
print $current_date, "\n";
Formating numbers with leading zero is done easily with "sprintf", a built-in function in perl (documentation with: perldoc perlfunc)
use strict;
use warnings;
use Date::Calc qw();
my ($y, $m, $d) = Date::Calc::Today();
my $ddmmyyyy = sprintf '%02d.%02d.%d', $d, $m, $y;
print $ddmmyyyy . "\n";
This gives you:
14.05.2014

How can I parse a strftime formatted string in Perl?

I am new to Perl and I wan to know whether there is an inverse function to the strftime().
Look,
use POSIX qw(strftime);
print strftime("%YT%mT%d TTTT%H:%M:%S", localtime)
I get: 2009T08T14 TTTT00:37:02. How can I do the oposite operation? From "2009T08T14 TTTT00:37:02" string to get 2009-08-14 00:37:02, knowing the formatting string "%YT%mT%d TTTT%H:%M:%S"?
One option is to parse the numbers using a regular expression and then use Time::Local. However, now that I understand your question is how to go from a strftime formatted string to a time in general, that approach is bound to be cumbersome.
You mention in your answer POSIX::strptime which is great if your platform supports it. Alternatively, you can use DateTime::Format::Strptime:
#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
use POSIX qw(strftime);
my $f = "%YT%mT%d TTTT%H:%M:%S";
my $s = strftime($f, localtime);
print "$s\n";
my $Strp = DateTime::Format::Strptime->new(
pattern => $f,
locale => 'en_US',
time_zone => 'US/Eastern',
);
my $dt = $Strp->parse_datetime($s);
print $dt->epoch, "\n";
print scalar localtime $dt->epoch, "\n";
$dt is a DateTime object so you can do pretty much whatever you want with it.
I think I have found the solution: strptime($strptime_pattern, $string)
So easyy
use Time::ParseDate;
my $t = '2009T08T14 TTTT00:37:02';
$t =~ s/TTTT//;
$t =~ s/T/-/g;
$seconds_since_jan1_1970 = parsedate($t)