Would like to generate report, which calculate the number of days, the material is in the warehouse.
The number of days is the difference between date ($3 field) the material comes in and
against (01 OCT 2014) manual feed date.
Input.csv
Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj
aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj
aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj
Currently i am using below command to popualte Ageing - No of days at $13 field ( thanks to gboffi)
awk -F, 'NR>0 {date=$3;
gsub("[-.]"," ",date);
printf $0 ",";system("date --date=\"" date "\" +%s")}
' Input.csv | awk -F, -v OFS=, -v now=`date --date="01 OCT 2014 " +%s` '
NR>0 {$13=now-$13; $13=$13/24/3600;print $0}' >Op_Step11.csv
while using the above command in Cygwin (windows), it is taking 50 minutes for 1 Lac (1,00,000) rows of sample input.
Since my actual input file contains 25 million rows of lines , it seems that the script will take couple of days ,
Looking for your suggestions to improve the command and advice !!!
Expected Output:
Des11,Material,DateIN,Des22,Des33,MRP,Des44,Des55,Des66,Location,Des77,Des88,Ageing-NoOfDays
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611
aa,xxx,19-AUG-14.08:08:01,cc,dd,x20,ee,ff,gg,XX128,hh,jj,42.6611
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621
aa,yyy,13-JUN-14.09:06:08,cc,dd,x20,ee,ff,gg,XX128,hh,jj,109.621
aa,yyy,05-FEB-14.09:02:09,cc,dd,x20,ee,ff,gg,YY250,hh,jj,237.624
aa,yyy,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624
aa,zzz,05-FEB-14.09:02:09,cc,dd,y35,ee,ff,gg,YY250,hh,jj,237.624
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
aa,zzz,11-JUN-13.05:06:17,cc,dd,y35,ee,ff,gg,YY250,hh,jj,476.787
I don't have the access to change the input format and dont have perl & python access.
Update#3:
BEGIN{ FS=OFS=","}
{
t1=$3
t2="01-OCT-14.00:00:00"
print $0,(cvttime(t2) - cvttime(t1))/24/3600
}
function cvttime(t, a) {
split(t,a,"[-.:]")
match("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC",a[2])
a[2] = sprintf("%02d",(RSTART+2)/3)
return( mktime("20"a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) )
}
Since you are on cygwin you are using GNU awk which has it's own built-in time functions and so you do not need to be trying to use the shell date command. Just tweak this old command I had lying around to suit your input and output format:
function cvttime(t, a) {
split(t,a,"[/:]")
match("JanFebMarAprMayJunJulAugSepOctNovDec",a[2])
a[2] = sprintf("%02d",(RSTART+2)/3)
return( mktime(a[3]" "a[2]" "a[1]" "a[4]" "a[5]" "a[6]) )
}
BEGIN{
t1="01/Dec/2005:00:04:42"
t2="01/Dec/2005:17:14:12"
print cvttime(t2) - cvttime(t1)
}
It uses GNU awk for time functions, see http://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions
Here is an example in Perl:
use feature qw(say);
use strict;
use warnings;
use Text::CSV;
use Time::Piece;
my $csv = Text::CSV->new;
my $te = Time::Piece->strptime('01-OCT-14', '%d-%b-%y');
my $fn = 'Input.csv';
open (my $fh, '<', $fn) or die "Could not open file '$fn': $!\n";
chomp(my $head = <$fh>);
say "$head,Ageing-NoOfDays";
while (my $line = <$fh>) {
chomp $line;
if ($csv->parse($line)) {
my $t = ($csv->fields())[2];
my $tp = Time::Piece->strptime($t, '%d-%b-%y.%T');
my $s = $te - $tp;
say "$line," . $s->days;
} else {
warn "Line could not be parsed: $line\n";
}
}
close($fh);
I have a file containing many columns of text, including a timestamp along the lines of Fri Jan 02 18:23 and I need to convert that date into MM/DD/YYYY HH:MM format.
I have been trying to use the standard `date' tool with awk getline to do the conversion, but I can't quite figure out how to pass the fields into the 'date' command in the format it expects (quoted with " or 's,) as getline needs the command string enclosed in quotes too.
Something like "date -d '$1 $2 $3 $4' +'%D %H:%M'" | getline var
Now that I think about it, I guess what I'm really asking is how to embed awk variables into a string.
If you're using gawk, you don't need the external date which can be expensive to call repeatedly:
awk '
BEGIN{
m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|")
for(o=1;o<=m;o++){
months[d[o]]=sprintf("%02d",o)
}
format = "%m/%d/%Y %H:%M"
}
{
split($4,time,":")
date = (strftime("%Y") " " months[$2] " " $3 " " time[1] " " time[2] " 0")
print strftime(format, mktime(date))
}'
Thanks to ghostdog74 for the months array from this answer.
you can try this. Assuming just the date you specified is in the file
awk '
{
cmd ="date \"+%m/%d/%Y %H:%M\" -d \""$1" "$2" "$3" "$4"\""
cmd | getline var
print var
close(cmd)
}' file
output
$ ./shell.sh
01/02/2010 18:23
and if you are not using GNU tools, like if you are in Solaris for example, use nawk
nawk 'BEGIN{
m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|")
for(o=1;o<=m;o++){
months[d[o]]=sprintf("%02d",o)
}
cmd="date +%Y"
cmd|getline yr
close(cmd)
}
{
day=$3
mth=months[$2]
print mth"/"day"/"yr" "$4
} ' file
I had a similar issue converting a date from RRDTool databases using rrdfetch but prefer one liners that I've been using since Apollo computer days.
Data looked like this:
localTemp rs1Temp rs2Temp thermostatMode
1547123400: 5.2788174937e+00 4.7788174937e+00 -8.7777777778e+00 2.0000000000e+00
1547123460: 5.1687014581e+00 4.7777777778e+00 -8.7777777778e+00 2.0000000000e+00
One liner:
rrdtool fetch -s -14400 thermostatDaily.rrd MAX | sed s/://g | awk '{print "echo ""\`date -r" $1,"\`" " " $2 }' | sh
Result:
Thu Jan 10 07:25:00 EST 2019 5.3373432378e+00
Thu Jan 10 07:26:00 EST 2019 5.2788174937e+00
On the face of it this doesn't look very efficient to me but this kind of methodology has always proven to be fairly low overhead under most circumstances even for very large files on very low power computer (like 25Mhz NeXT Machines). Yes Mhz.
Sed deletes the colon, awk is used to print the other various commands of interest including just echoing the awk variables and sh or bash executes the resulting string.
For methodology or large files or streams I just head the first few lines and gradually build up the one liner. Throw away code.
Related question is "Datetime To Unix timestamp", but this question is more general.
I need Unix timestamps to solve my last question. My interests are Python, Ruby and Haskell, but other approaches are welcome.
What is the easiest way to generate Unix timestamps?
In Linux or MacOS you can use:
date +%s
where
+%s, seconds since 1970-01-01 00:00:00 UTC. (GNU Coreutils 8.24 Date manual)
Example output now 1454000043.
in Ruby:
>> Time.now.to_i
=> 1248933648
curl icanhazepoch.com
Basically it's unix timestamps as a service (UTaaS)
In python add the following lines to get a time stamp:
>>> import time
>>> time.time()
1335906993.995389
>>> int(time.time())
1335906993
$ date +%s.%N
where (GNU Coreutils 8.24 Date manual)
+%s, seconds since 1970-01-01 00:00:00 UTC
+%N, nanoseconds (000000000..999999999) since epoch
Example output now 1454000043.704350695.
I noticed that BSD manual of date did not include precise explanation about the flag +%s.
In Bash 5 there's a new variable:
echo $EPOCHSECONDS
Or if you want higher precision (in microseconds):
echo $EPOCHREALTIME
In Perl:
>> time
=> 1335552733
The unix 'date' command is surprisingly versatile.
date -j -f "%a %b %d %T %Z %Y" "`date`" "+%s"
Takes the output of date, which will be in the format defined by -f, and then prints it out (-j says don't attempt to set the date) in the form +%s, seconds since epoch.
First of all, the Unix 'epoch' or zero-time is 1970-01-01 00:00:00Z (meaning midnight of 1st January 1970 in the Zulu or GMT or UTC time zone). A Unix time stamp is the number of seconds since that time - not accounting for leap seconds.
Generating the current time in Perl is rather easy:
perl -e 'print time, "\n"'
Generating the time corresponding to a given date/time value is rather less easy. Logically, you use the strptime() function from POSIX. However, the Perl POSIX::strptime module (which is separate from the POSIX module) has the signature:
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) =
POSIX::strptime("string", "Format");
The function mktime in the POSIX module has the signature:
mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
So, if you know the format of your data, you could write a variant on:
perl -MPOSIX -MPOSIX::strptime -e \
'print mktime(POSIX::strptime("2009-07-30 04:30", "%Y-%m-%d %H:%M")), "\n"'
in Haskell
import Data.Time.Clock.POSIX
main :: IO ()
main = print . floor =<< getPOSIXTime
in Go
import "time"
t := time.Unix()
in C
time(); // in time.h POSIX
// for Windows time.h
#define UNIXTIME(result) time_t localtime; time(&localtime); struct tm* utctime = gmtime(&localtime); result = mktime(utctime);
in Swift
NSDate().timeIntervalSince1970 // or Date().timeIntervalSince1970
For completeness, PHP:
php -r 'echo time();'
In BASH:
clitime=$(php -r 'echo time();')
echo $clitime
In Haskell...
To get it back as a POSIXTime type:
import Data.Time.Clock.POSIX
getPOSIXTime
As an integer:
import Data.Time.Clock.POSIX
round `fmap` getPOSIXTime
public static Int32 GetTimeStamp()
{
try
{
Int32 unixTimeStamp;
DateTime currentTime = DateTime.Now;
DateTime zuluTime = currentTime.ToUniversalTime();
DateTime unixEpoch = new DateTime(1970, 1, 1);
unixTimeStamp = (Int32)(zuluTime.Subtract(unixEpoch)).TotalSeconds;
return unixTimeStamp;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return 0;
}
}
Let's try JavaScript:
var t = Math.floor((new Date().getTime()) / 1000);
...or even nicer, the static approach:
var t = Math.floor(Date.now() / 1000);
In both cases I divide by 1000 to go from seconds to millis and I use Math.floor to only represent whole seconds that have passed (vs. rounding, which might round up to a whole second that hasn't passed yet).
If I want to print utc date time using date command I need to using -u argument with date command.
Example
date -u
Output
Fri Jun 14 09:00:42 UTC 2019
nawk:
$ nawk 'BEGIN{print srand()}'
Works even on old versions of Solaris and probably other UNIX systems, where '''date +%s''' isn't implemented
Doesn't work on Linux and other distros where the posix tools have been replaced with the GNU versions (nawk -> gawk etc.)
Pretty unintuitive but definitelly amusing :-)
For Unix-like environment the following will work.
# Current UNIXTIME
unixtime() {
datetime2unixtime "$(date -u +'%Y-%m-%d %H:%M:%S')"
}
# From DateTime(%Y-%m-%d %H:%M:%S)to UNIXTIME
datetime2unixtime() {
set -- "${1%% *}" "${1##* }"
set -- "${1%%-*}" "${1#*-}" "${2%%:*}" "${2#*:}"
set -- "$1" "${2%%-*}" "${2#*-}" "$3" "${4%%:*}" "${4#*:}"
set -- "$1" "${2#0}" "${3#0}" "${4#0}" "${5#0}" "${6#0}"
[ "$2" -lt 3 ] && set -- $(( $1-1 )) $(( $2+12 )) "$3" "$4" "$5" "$6"
set -- $(( (365*$1)+($1/4)-($1/100)+($1/400) )) "$2" "$3" "$4" "$5" "$6"
set -- "$1" $(( (306*($2+1)/10)-428 )) "$3" "$4" "$5" "$6"
set -- $(( ($1+$2+$3-719163)*86400+$4*3600+$5*60+$6 ))
echo "$1"
}
# From UNIXTIME to DateTime format(%Y-%m-%d %H:%M:%S)
unixtime2datetime() {
set -- $(( $1%86400 )) $(( $1/86400+719468 )) 146097 36524 1461
set -- "$1" "$2" $(( $2-(($2+2+3*$2/$3)/$5)+($2-$2/$3)/$4-(($2+1)/$3) ))
set -- "$1" "$2" $(( $3/365 ))
set -- "$#" $(( $2-( (365*$3)+($3/4)-($3/100)+($3/400) ) ))
set -- "$#" $(( ($4-($4+20)/50)/30 ))
set -- "$#" $(( 12*$3+$5+2 ))
set -- "$1" $(( $6/12 )) $(( $6%12+1 )) $(( $4-(30*$5+3*($5+4)/5-2)+1 ))
set -- "$2" "$3" "$4" $(( $1/3600 )) $(( $1%3600 ))
set -- "$1" "$2" "$3" "$4" $(( $5/60 )) $(( $5%60 ))
printf "%04d-%02d-%02d %02d:%02d:%02d\n" "$#"
}
# Examples
unixtime # => Current UNIXTIME
date +%s # Linux command
datetime2unixtime "2020-07-01 09:03:13" # => 1593594193
date -u +%s --date "2020-07-01 09:03:13" # Linux command
unixtime2datetime "1593594193" # => 2020-07-01 09:03:13
date -u --date #1593594193 +"%Y-%m-%d %H:%M:%S" # Linux command
https://tech.io/snippet/a3dWEQY
With NodeJS, just open a terminal and type: node -e "console.log(new Date().getTime())" or node -e "console.log(Date.now())"
In Rust:
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let now = SystemTime::now();
println!("{}", now.duration_since(UNIX_EPOCH).unwrap().as_secs())
}
If you need a Unix timestamp from a shell script (Bourne family: sh, ksh, bash, zsh, ...), this should work on any Unix machine as unlike the other suggestions (perl, haskell, ruby, python, GNU date), it is based on a POSIX standard command and feature.
PATH=`getconf PATH` awk 'BEGIN {srand();print srand()}'