Perl: Getting weeknumbers from pre-formatted date-time strings - date

I am getting date-time strings in the format "2021-04-25 04:27:35" (YYYY-MM-DD hh:mm:ss) and need to convert them to "2021w18".
I must get the weeknumber and I already have the below in my perl script.
use Time::Piece;
use POSIX qw(strftime);
Any help will help me progress beyond "newbie".

Here's a subroutine that will do what you want:
use Time::Piece;
use POSIX qw(strftime);
use strict;
use warnings;
use feature 'say';
sub dateToWeek {
my ($date) = #_;
my $t = Time::Piece->strptime($date, "%Y-%m-%d %H:%M:%S");
return $t->strftime("%Yw%U");
}
say dateToWeek("2021-04-25 04:27:35");
Output:
2021w17
Pass it a date contained in a string and it will return the year + "w" + week number.
If you need it to return 2021w18 instead of 2021w17 for April 25, 2021, change the return statement to add 1 to the strftime like so:
return $t->year . "w" . ($t->strftime("%U")+1);

Related

Perl Format dates

use Date::Calc qw(:all);
use Time::Piece;
use POSIX qw(strftime);
$a1 = '01.01.1963';
($year, $month, $day) = Decode_Date_US($a1);
print "$year $month $day\n";
$formatted = strftime('%m/%d/%Y',$month,$day,$year);
print "$formatted\n";
I am trying to format dates in a consistent format using POSIX(strftime). I am uncertain what the input format might be. I am using Decode_Date_US to extract the relevant year, month, day information. I am then trying to format the dates in consistent manner using strftime. I am getting following error
Usage: POSIX::strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) at test_dates.pl line 60
Any help would appreciated.
"use Time::Piece" would be eventually used to sort the dates.
Thanks
Just use Time::Piece and strptime
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $date = '01.01.1963';
my $timestamp = Time::Piece->strptime( $date, "%m.%d.%Y" );
print $timestamp -> strftime( "%m/%d/%Y")
But if the format is inconsistent, then you're onto a loser - for starters, there's plenty of places that transpose day/month ordering, or represent year as two digits (that sometimes will clash with month or day).
It's inherently ambiguous. You can - at best - apply some very crude guessing by grabbing groups of digits and assuming that they're in a consistent order.
E.g.
my ( $day, $month, $year ) = m/(\d{2}).*(\d{2}).*(\d{4})/;
$timestamp = Time::Piece -> strptime ( "$year-$month-$day", "%Y-%m-%d" );
But you'll be tripped up by dates like 10/11/12 because you simply can't know which number is which field. You can try guessing, by evaling the strptime and just retrying different formats until you get one that does decode to something valid.
As you indicate - Decode_Date_US basically does this so:
use strict;
use warnings;
use Date::Calc qw(:all);
use Time::Piece;
my $a1 = '01.01.1963';
my ($year, $month, $day) = Decode_Date_US($a1);
my $time = Time::Piece -> strptime("$year/$month/$day", "%Y/%m/%d");
print $time->strftime("%Y-%m-%d"),"\n";
Also - use strict; use warnings; is good.
And - there's one correct way to write dates. If you're going to reformat at all, then the one that isn't ambiguous is the best choice.
I ended up using DateTime module's strftime function which can handle dates earlier than 1970.
"Crashing" -Perl command line interpreter has stopped working. If it helps, I am using a windows machine and a very infrequent perl user.
this worked for me
use Date::Calc qw(:all);
use DateTime;
$dateformat = "%m/%d/%Y";
($year, $month, $day) = Decode_Date_US($date);
$date = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
);
$date = $date->strftime($dateformat);

Date formatting in Perl

I have a variable which contain value "20140720". I need to change it to the format "20/07".
My code is shown below.
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
my $date = '20140720';
my $date_format = Time::Piece->strptime($date, '%d/%m');
my $new_date = $date_format->strftime('%d/%m');
print $new_date;
I get following error during execution.
Error parsing time at /usr/lib/perl5/5.10.0/x86_64-linux-thread-multi/Time/Piece.pm line 470.
In this line — Time::Piece->strptime($date, '%d/%m'); — you specified the format that $date is currently in incorrectly. The second argument describes how the string should be parsed, not the format you want it to be in (which is what the following line is for).
Use '%Y%m%d' instead.
With a fixed string, you should use the pack/unpack function:
use strict;
use warnings;
my $date = '20140720';
my (undef, $m, $d) = unpack 'A4A2A2', $date;
print "$d/$m";
If you don't need further date processing, using a simple regular expression may be simpler:
use strict;
use warnings;
my $date = '20140720';
my $new_date = $date;
$new_date =~ s!\d{4}(\d{2})(\d{2})$!$2/$1!;
print $new_date, "\n";

How do I get last year date and current date using perl?

I want to fetch current date and exactly last year date using perl in the format of 140220 and 130220.
Perhaps the following will help:
use strict;
use warnings;
use Time::Piece;
my $time = Time::Piece->new;
my $currDate = $time->strftime('%y%m%d');
print $currDate, "\n";
my $lastYear = $time->add_years(-1)->strftime('%y%m%d');
print $lastYear;
Output:
140219
130219
Here is a sample using DateTime.
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
use DateTime;
my $dt = DateTime->now();
my $year_ago = DateTime->now()->subtract(years => 1);
say $dt->strftime("%y%m%d");
say $year_ago->strftime("%y%m%d");

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 to change ctime to normal string representation?

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