Convert a string into date in AIX unix - unix

I need to extract the date part from a file in unix and add +1 day to the date and rename the file with the new date in it.
for ex:
sample file name: sample_file_name_01_31_2022_14_01_45_loadid.csv
I tried to extract the timestamp using substr which gives 01_31_2022_14_01_45. Now, the new date should be 02_01_2022_14_01_45 and the new file name should be sample_file_name_02_01_2022_14_01_45_loadid.csv

Given the AIX operating environment, which doesn't have GNU date installed by default (for the handy date -d ... functionality), I'd approach this problem with a perl script. The script below uses fairly common modules that should be available on an AIX system.
The basic idea behind the script is to loop over every given argument (one or more filenames) and:
extract the date/time fields from the filename
convert those fields into seconds-since-the epoch
add one day's worth of seconds
convert that new timestamp into the desired string format
rename the file
I encountered a slight complication while adding error-checking: the timelocal() function will croak (exit the script) if any of the given date/time fields are out of range. Because I wanted to be able to loop over any remaining arguments, I had to wrap that call in a Try-Catch block.
#!/usr/bin/perl -w
use strict;
use POSIX qw(strftime);
use Time::Local qw(timelocal);
use Try::Tiny;
sub rename_a_file {
my $filename = shift;
# extract date from filename
my ($prefix, $month, $day, $year, $hour, $minute, $second, $suffix);
unless (
($prefix, $month, $day, $year, $hour, $minute, $second, $suffix) =
$filename =~ /^(.*)_(\d{2})_(\d{2})_(\d{4})_(\d{2})_(\d{2})_(\d{2})_(.*)$/
) {
warn "Could not determine a timestamp from ${filename}; skipping\n";
return undef;
}
# local time in seconds-since-the-epoch
my $t;
# timelocal will die if any inputs are out of range; catch it
my $flag = 0;
try {
$t = timelocal($second, $minute, $hour, $day, $month - 1, $year - 1900);
} catch {
warn "Unable to convert time specification: $_";
$flag = 1;
};
return undef if $flag;
# add one day's worth of seconds
$t += 24 * 60 * 60;
# new timestamp in string format
my $newdate;
unless ($newdate = strftime("%m_%d_%Y_%H_%M_%S", localtime $t)) {
warn "Unable to convert new date to a string format: $!";
return undef;
}
# rename file using new date
unless (rename $filename, "${prefix}_${newdate}_${suffix}") {
warn "Unable to rename $filename: $!";
return undef;
}
return 1;
}
my $errors = 0;
for (#ARGV) {
unless (rename_a_file($_)) {
warn "Unable to rename: $_\n";
++$errors;
}
}
$errors = 255 if $errors > 255;
exit $errors;

Related

Strange DateTime behaviour in date validation in php 5.4

I wrote a simple piece of code to validate the format of a date.
The format of the date in my case is d/m/y
List of tests that I run successfully
10/12/2019 DATE OK
aa/12/2019 DATE KO
10-12-2019 DATE KO
But there is this case that surprises me:
32/12/2019 DATE OK
Why does this happen?
Do I need to add controls on the range of days and months?
$value = '32-12-2019';
$checkDate = \DateTime::createFromFormat('d/m/Y', $value);
if ($checkDate) {
print("DATE OK");
} else {
print("DATE KO");
}
I'm using
public static function validateDate($date, $format = 'Y-m-d')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) === $date;
}
It validates correctness of date and required format

Symfony Invalid parameter format, : given

I need create multiply search by years. From request I get string like 2017,2018 and then I want get Questions which createdAt, between from start year and end year. I have query builder with part, and I'am not understand why I have this error
if ($paramFetcher->get('years')) {
$orXSearch = $qb->expr()->orX();
$yearData = trim($paramFetcher->get('years'));
foreach (explode(',', $yearData) as $key => $id) {
if (!$id) {
continue;
}
$orXSearch
->add($qb->expr()->between('q.createdAt', ':'.$key.'dateFrom', ':'.$key.'dateTo'));
$date = $this->additionalFunction->validateDateTime($id, 'Y');
$first = clone $date;
$first->setDate($date->format('Y'), 1, 1);
$first->setTime(0, 0, 0);
$last = clone $date;
$last->setDate($date->format('Y'), 12, 31);
$last->setTime(23, 59 , 59);
$qb
->setParameter($key.'dateFrom', $first->format('Y-m-d H:i:s'))
->setParameter($key.'dateTo', $last->format('Y-m-d H:i:s'));
}
$qb->andWhere($orXSearch);
}
error:
symfony Invalid parameter format, : given, but :<name> or ?<num> expected.
In your foreach loop, you’re looping over the result of an explode operation which yields a numeric array, i.e. $key will always have a numeric value.
Hence, your parameter placeholder is colon + number + string, i.e. :1dateFrom. This is not allowed. Either you reference a string value with a colon + string placeholder (:foo), or you reference a numeric value with a question mark + number value (?1).
Your problem is easy to solve: Simply add any letter between the colon and the number, and you’re good:
->add($qb->expr()->between(
'q.createdAt',
':x'.$key.'dateFrom',
':x'.$key.'dateTo'
));

How do I get value of datetime object in drupal 8?

There is a Datetime object as following and I want to get the date value
Array
(
[0] => Array
(
[value] => Drupal\Core\Datetime\DrupalDateTime Object
(
[formatTranslationCache:protected] =>
[inputTimeRaw:protected] =>
[inputTimeAdjusted:protected] =>
[inputTimeZoneRaw:protected] =>
[inputTimeZoneAdjusted:protected] =>
[inputFormatRaw:protected] =>
[inputFormatAdjusted:protected] =>
[langcode:protected] => en
[errors:protected] => Array
(
)
[dateTimeObject:protected] => DateTime Object
(
[date] => 2018-01-05 01:30:00.000000
[timezone_type] => 3
[timezone] => UTC
)
[stringTranslation:protected] =>
)
)
)
I don't want to get this value by $node->get("field_id")->value;
Because I need dynamic value that means the value should change after I changed date field.
Is it possible?
Figured it out
$date = $form_state->getValue('field_id')[0]['value']->format('Y-m-d H:i:s')
it returns string !!
The point is locate the Object.
The values in the array are of type Drupal\Core\Datetime\DrupalDateTime, check the API on Drupal.org DrupalDateTime Doc.
In order to get value from the object you must use the __toString method as mentioned.
Proceed as :
$dateTime = YourArray[0]['value'];
$date = $dateTime->_toString();
Else
$date = $dateTime->format('Y-m-d h::i::s');
For more date formats check the PHP doc PHP DATE
Edit 1:
The following Code works correctly :
$temp = new \Drupal\Core\Datetime\DrupalDateTime();
echo $temp->__toString();
echo $temp->format('Y-m-d h::i'); die;
I found that in browsers that do no support
<input type="time">
(i.e. Safari) the value is not of type "Drupal\Core\Datetime\DrupalDateTime" but array.
Here is what i did inside a drupal 8 module to get formatted date from DrupalDateTime
I. If you have a date and want format it, just pass it to the static method of the class (DrupalDateTime) as follows. You can replace the string with your date variables.
Below shows both using the static version and non static version of DrupalDateTime
$date = DrupalDateTime::createFromFormat('j-M-Y', '20-Jul-2019');
// Using the static method prints out: 20-Jul-2019:11:am
$date = new DrupalDateTime('now'); // grab current dateTime using NON static
$date->format('l, F j, Y - H:i'); // format it
// prints out nicely formatted version: Tue, Jul 16, 2019 - 11:34:am
// you can remove H:i and what's after it if you don't want hours or am pm
$date = new DrupalDateTime('now'); // grab current dateTime
// Or print $date->format('d-m-Y: H:i A');
// prints out: 16-07-2019: 11:43 AM
More examples:
$date = new DrupalDateTime();
$date->setTimezone(new \DateTimeZone('America/Chicago'));
print $date->format('m/d/Y g:i a');
// The above prints current time for given Timezone
// prints : 07/16/2019 10:59 am
// Another variations of the above except it takes specific date and UTC zone
$date = new DrupalDateTime('2019-07-31 11:30:00', 'UTC');
$date->setTimezone(new \DateTimeZone('America/Chicago'));
print $date->format('m/d/Y g:i a');
// prints 07/31/2019 6:30 am
To use these in your module/code you need to include the following at the top of your file;
use Drupal\Core\Datetime\DrupalDateTime;
Also note that the DrupalDateTime extends DateTimePlus() which it self "wraps the PHP DateTime class with more flexible initialization parameters.... as per docs..."
How to test it with Drush.
Save the above code in a php script, then let drush run the srcipt after it bootstraps drupal like:
drush -r /path-to-your-drupal-documentRoot -l example.com scr ~/path-to your-script
For multisites make sure you use ... drush -l http.... like above
Note:
I posted similar answer to: https://drupal.stackexchange.com/questions/252333/how-to-get-formatted-date-string-from-a-datetimeitem-object/283529#283529
in my case I use date range with duration
in your case you need the bold one
date('Y-m-d\TH:i:s', strtotime($date->get('field')->getValue()[0]['value']))
date('Y-m-d\TH:i:s', strtotime($date->get('field')->getValue()[0]['end_value']))

Join lines based on a starting value using UNIX commands

Here I am again, with another UNIX requirement (as my knowledge in UNIX is limited to basic commands).
I have a file that looks like this (and has about 30 million lines)
123456789012,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
123456789012,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
123456789012,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
456789012345,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
The final output should be like this (without the first value repeating in the joined portions)
123456789012,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
456789012345,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
However, if the above output is a bit complicated, an output like below is also fine. Because I can load the file into Oracle11g and get rid of the redundant columns.
123456789012,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,123456789012,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,123456789012,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,234567890123,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,345678901234,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,345678901234,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
456789012345,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,567890123456,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
Using awk is sufficient; it is a control-break report of sorts. Since the lines with the same key are grouped together — a very important point — it is fairly simple.
awk -F, '{ if ($1 != saved)
{
if (saved != 0) print saved "," list
saved = $1
list = ""
}
pad = ""
for (i = 2; i <= NF; i++) { list = list pad $i; pad = "," }
}
END { if (saved != 0) print saved, list }'
You can feed the data as standard input or list the files to be processed after the final single quote.
Sample output:
123456789012,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
456789012345,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456 PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
The code uses saved to keep a track of the key column value that it is accumulating. When the key column changes, print out the saved values (if there are any) and reset for the new set of lines. At the end, print out the saved values (if there are any). The code deals with an empty file gracefully, therefore.
Perl options
#!/usr/bin/env perl
use strict;
use warnings;
my $saved = "";
my $list;
while (<>)
{
chomp;
my($key,$value) = ($_ =~ m/^([^,]+)(,.*)/);
if ($key ne $saved)
{
print "$saved$list\n" if $saved;
$saved = $key;
$list = "";
}
$list .= $value;
}
print "$saved$list\n" if $saved;
Or, if you really want to, you can saved writing the loop (and using strict and warnings) with:
perl -n -e 'chomp;
($key,$value) = ($_ =~ m/^([^,]+)(,.*)/);
if ($key ne $saved)
{
print "$saved$list\n" if $saved;
$saved = $key;
$list = "";
}
$list .= $value;
} END {
print "$saved$list\n" if $saved;'
That could be squished down to a single (rather long) line. The } END { is a piece of Perl weirdness; the -n option creates a loop while (<>) { … } and interpolates the script in the -e argument into it, so the } in } END { terminates that loop and then creates an END block which is ended by the } that Perl provided. Yes, documented and supported; yes, extremely weird (so I wouldn't do it; I'd use the Perl script shown first).
This awk script does what you want:
BEGIN { FS = OFS = "," }
NR == 1 { a[++n] = $1 }
a[1] != $1 { for(i=1; i<=n; ++i) printf "%s%s", a[i], (i<n?OFS:ORS); n = 1 }
{ a[1] = $1; for(i=2;i<=NF;++i) a[++n] = $i }
END { for(i=1; i<=n; ++i) printf "%s%s", a[i], (i<n?OFS:ORS) }
It stores all of the fields with the same first column in an array. When the first column differs, it prints out all of the elements of the array. Use it like awk -f join.awk file.
Output:
123456789012,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
234567890123,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
345678901234,PID=1,AID=2,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
456789012345,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
567890123456,PID=2,AID=1,EQOSID=1,PDPTY=IPV4,PDPCH=2-0,PID=3,AID=8,EQOSID=1,PDPTY=IPV4,PDPCH=2-0
Here are some Python options, if you decide to go that route... First will work for multiple input files and non-sequential identical indices. Second doesn't read the whole file into memory.
(Note, I know it is not convention, but I intentionally use UpperCase for variables to make it clear what is a user-defined variable and what is a special python word.)
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
concatenate comma-separated values based on first value
Usage:
catfile.py *.txt > output.dat
"""
import sys
if len(sys.argv)<2:
sys.stderr.write(__doc__)
else:
FileList = sys.argv[1:]
IndexList = []
OutDict = {}
for FileName in FileList:
with open(FileName,'rU') as FStream:
for Line in FStream:
if Line:
Ind,TheRest = Line.rstrip().split(",",1)
if Ind not in IndexList:
IndexList.append(Ind)
OutDict[Ind] = OutDict.get(Ind,"") + "," + TheRest
for Ind in IndexList:
print Ind + OutDict[Ind]
Here is a different version which doesn't load the whole file into memory, but requires that the identical Indices all occur in order, and it only runs on one file:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
concatenate comma-separated values based on first value
Usage:
catfile.py *.txt > output.dat
"""
import sys
if len(sys.argv)<2:
sys.stderr.write(__doc__)
else:
FileName = sys.argv[1]
OutString = ''
PrevInd = ''
FirstLine = True
with open(FileName,'rU') as FStream:
for Line in FStream:
if "," in Line:
Ind,TheRest = Line.rstrip().split(",",1)
if Ind != PrevInd:
if not FirstLine:
print PrevInd+OutString
PrevInd = Ind
OutString = TheRest
FirstLine = False
else:
OutString += ","+TheRest
print Ind + OutString
More generally, you can run these with by saving them as say catfile.py and then doing python catfile.py inputfile.txt > outputfile.txt. Or for longer term solutions, make a scripts directory, add it to your $PATH, make them executable with chmod u+x catfile.py and then you can just type the name of the script from any directory. But that is another topic that you would want to research.
A way without array:
BEGIN { FS = OFS = "," ; ORS = "" }
{
if (lid == $1) { $1 = "" ; print $0 }
else { print sep $0 ; lid = $1 ; sep = "\n" }
}
END { if (NR) print }
Note: if you don't need a newline at the end, remove the END block.
This might work for you (GNU sed):
sort file | sed -r ':a;$!N;s/^(([^,]*),.*)\n\2/\1/;ta;P;D'
Sort the file (if need be) and then delete newline and key where duplicates appear.

Log4perl category as log file name

I'm sure I'm being dim and missing the obvious but is there a simple way of using the current category as the filename in a config file without resorting to a subroutine call?
So that in the following one could use ${category}.log instead of repeating bin.nh.tpp in the filename line
log4perl.logger.**bin.nh.tpp**=INFO, BIN_NH_TPP_LOGFILE
log4perl.appender.BIN_NH_TPP_LOGFILE=Log::Log4perl::Appender::File
log4perl.appender.BIN_NH_TPP_LOGFILE.filename=${LOGS}/nh/**bin.nh.tpp**.log
log4perl.appender.BIN_NH_TPP_LOGFILE.mode=append
log4perl.appender.BIN_NH_TPP_LOGFILE.layout=PatternLayout
log4perl.appender.BIN_NH_TPP_LOGFILE.layout.ConversionPattern=[%d] %F{1} %L %c - %m%n
It's somewhat more involved than a subroutine, I'm afraid. Subroutines in l4p conf files allow for including variables known at conf file parsing time, e.g. the time/date or a user id. You can't modify log time behavior that way.
The easiest way I can think of right now to accomplish what you want is a custom appender like
package FileByCategoryAppender;
use warnings;
use strict;
use base qw( Log::Log4perl::Appender::File );
sub new {
my( $class, %options ) = #_;
$options{filename } = "no-category.log";
my $self = $class->SUPER::new( %options );
bless $self, $class;
}
sub log {
my( $self, %params ) = #_;
my $category = $params{ log4p_category };
$self->SUPER::file_switch( $category . ".log" );
$self->SUPER::log( %params );
}
1;
and then use it in your script like
use strict;
use warnings;
use Log::Log4perl qw( get_logger );
my $conf = q(
log4perl.category = WARN, Logfile
log4perl.appender.Logfile = FileByCategoryAppender
log4perl.appender.Logfile.create_at_logtime = 1
log4perl.appender.Logfile.layout = \
Log::Log4perl::Layout::PatternLayout
log4perl.appender.Logfile.layout.ConversionPattern = %d %F{1} %L> %m %n
);
Log::Log4perl::init(\$conf);
my $logger = get_logger("Bar::Twix");
$logger->error("twix error");
$logger = get_logger("Bar::Mars");
$logger->error("mars error");
which will result in two log files being created at log time:
# Bar.Mars.log
2012/11/18 11:12:12 t 21> mars error
and
# Bar.Twix.log
2012/11/18 11:12:12 t 21> twix error

Resources