Find Difference in timestamps in seconds - linux

I have 2 files with timestamps in the format of MMDDYYYY-HHMMSS.
For eg. 04192012-000623 and 04192012-000854.
I need to be able to find the difference between the 2 in seconds.
Special cases to check for
the dates straddling midnight. For eg: 04172012-115500 & 04182012-000200.
it shouldn't matter which file comes in first, etc.
I am running ksh with no access to the date -d flag. Can anyone point me in the right direction on how to shell script this? (It is going to be a part of a larger shell script so no other languages please)
This is intended to be run on both solaris and linux ksh. Thanks in advance.

As a starter (from my provided link above):
#! /usr/bin/ksh
echo enter first time stamp
read TIME1
echo enter second time stamp
read TIME2
H1=${TIME1%:+([0-9])}
M1=${TIME1#+([0-9]):}
H2=${TIME2%:+([0-9])}
M2=${TIME2#+([0-9]):}
H1=${H1#0}
M1=${M1#0}
H2=${H2#0}
M2=${M2#0}
((MAM1=H1*60+M1))
((MAM2=H2*60+M2))
((MAM1>MAM2)) && ((MAM2=MAM2+1440))
((diff=MAM2-MAM1))
echo diff = $diff
exit 0
$ ./timestamp
enter first time stamp
17:30
enter second time stamp
18:05
diff = 35
$ ./timestamp
enter first time stamp
23:59
enter second time stamp
00:01
diff = 2
$

if this is just for fun, good luck :). if it's for actual practical purposes, see my strptime wrapper at How to get the difference between now and a different date (in minutes) using ksh (or another shell script)?, it should be easily adaptable.

This solution uses gnu-date and bashisms, since I don't know ksh.
d1=04192012-000623
dd1="${d1:4:4}/${d1:0:2}/${d1:2:2} ${d1:9:2}:${d1:11:2}:${d1:13:2}"
d1=04192012-000854
dd2="${d1:4:4}/${d1:0:2}/${d1:2:2} ${d1:9:2}:${d1:11:2}:${d1:13:2}"
echo $(($(date -d "$dd1" +%s) - $(date -d "$dd2" +%s)))
Maybe ${var:from:len} is not available in ksh to cut parts from strings, then you have to replace it with something else, maybe sed.

stat -c followed by one of the following
%X time of last access, seconds since Epoch
%Y time of last data modification, seconds since Epoch
%Z time of last status change, seconds since Epoch

Related

How to make a script to rename files

I have an actioncam that saves my video in a folder into the SD Card.
Using linux, here is the path:
/media/mattiapdo/EOS_DIGITAL/_REC/100MEDIA
Files are saved in the REC_0001.AVI format
I would write a script that renames each file using the writing date.
Furthermore I notice that for some strange reason, the date and the hour are different from the effective: for example, 12/07/2017 10:30 is written as 09/02/2011 07:55
As the camera is very old and minimal, I can't reset the correct date and the correct hour so I would prefer to manipulate them in aftermath.
The goal would be to rename REC_0001.AVI in 2017_07_12__10_30.AVI
Does anyone have any ideas?
You can use the date command to print the elapsed seconds since, Unix lingo, the Epoch, aka 1970-01-01 UTC. Assuming that the camera date is in Anglo format, and that by default date likes the Anglo format, you have to swap the month and day in your date
$ date --date='09/02/2011 07:55' +%s
1314942900
$ date --date='07/12/2017 10:30' +%s
1499848200
$
so that you can compute a Delta between the real date and the camera idea of time
$ Delta=$(($(date --date='07/12/2017 10:30' +%s)-$(date --date='02/09/2011 07:55' +%s)))
$ echo $Delta
184905300
$
You haven't (yet?) told us how you fetch the date from the camera, but let's
say that
$ camera=$(fetch_date $current_file_name)
and assuming that $camera is in a format that date likes,
$ fromEpoch=$(($(date --date="$camera" +%s)+$Delta))
the last step is to get back the date in a format that you like , I suggest
the ISO 8601 format, so that your files are correctly sorted by ls
$ corrected_date=$(date --date="#$fromEpoch" +%Y-%m-%dT%H:%M)
$ cp $current_file_name other_directory/$corrected_date.AVI
The boring details about the date command, that is indeed VERY flexible and useful, are available using
$ man date
I hope that you can write your script with the info that I gave you, thank you for the question.
Addendum
Caveat emptor: totally untested
$ cat script
Delta=$(($(date --date='07/12/2017 10:30' +%s)-$(date --date='02/09/2011 07:55' +%s)))
mkdir -p ATTIC
mv *AVI ATTIC
for file in ./ATTIC/*.AVI ; do
########## fetch_date command is a placeholder for the real command
cam_date=$(fetch_date "$file")
cam_fromEpoch=$(date --date="$cam_date" +%s)
correct_fromEpoch=$(($cam_fromEpoch+$Delta))
ISO_8601=$(date --date="#$correct_fromEpoch" +%Y-%m-%dT%H:%M)
cp $file $ISO_8601.AVI
done
# cleanup, e.g. list current directory and ATTIC and ask if ATTIC is to be removed
$

Use linux date command in cronjob

I have a problem using the linux 'date' command within a cronjob.
Linux version: CentOS Linux 7 (Core)
What i need is the date of 9 days ago as a parameter to my test.sh script.
Today is 10-08-2016, the job that needs to be executed is:
/scripts/test.sh 2016-08-01
My code in crontab:
DATEVAR=$(date +%F --date="9 days ago")
0 12 * * tue ~/scripts/test.sh $($DATEVAR)
So the linux command is 'date +%F --date="9 days ago"' but i need this to be executed and set as parameter.
What it does now is run the script with as parameter '$(date':
~/scripts/test.sh $(date
I have tried setting the DATEVAR with the following things without succes:
DATEVAR='date +%F --date="9 days ago"'
DATEVAR=date +%F --date="9 days ago"
DATEVAR=$(date +%F --date="9 days ago")
DATEVAR=(shell date +%F --date="9 days ago")
Does anyone know if this is possible and how my DATEVAR can be set with the result of executing the 'date' command?
This should work:
0 12 * * tue _DV=`date +\%F --date="9 days ago"`; ~/scripts/test.sh $_DV
Unfortunately, there are several issues to overcome here. First, the fact that cron now supports "environment settings" can be very misleading. Folks with shell script experience might easily assume that the full power of the shell can be used here -- it cannot. These settings are as dumb as they come: they are strict verbatim replacements. In my mind, a better moniker would be "placeholder assignment."
Second, the date string you wish to utilize is somewhat complex. Specifically, it contains an embedded quoted string ("9 days ago") and a special crontab character (surprise!): the '%' in the expression '+%F'. Cron replaces '%' with newlines -- a nice feature but surprising if you're unaware or forget about it. And quotes don't survive the assignment phase.
Knowing this, an alternative to the above entry that uses "placeholder assignment" is:
DT1 = date +%F
DT2 = 9 days ago
0 12 * * tue _DV=`$DT1 --date="$DT2"`; ~/scripts/test.sh $_DV
Here we're capturing pieces that we want to be directly substituted without any interpolation.
There -- two solutions for the price of one!
I am not sure you can do it inside a cron job.
A simple workaround is to wrap your call to test.sh into another script without argument. In it, simply write:
DATEVAR=$(date +%F --date="9 days ago")
~/scripts/test.sh $($DATEVAR)
An call this one in your cronjob.

.bashrc code to execute 1 time a day upon first login

Is there a way to make a specific piece of code in my .bashrc file execute only on the first log-in of a specific day of the week? I already know that using the command substitution
"$(date +%u)" will give me a number from 1-7 that corresponds to each day of the week (1 being Monday). However, i do not want this code to execute all day for every subsequent log-in. Any tips would be much appreciated. Thanks in advance!
You should not have to write anything to disk.
I would extract the day out of the commands:
lastlog -u $USER
and
date
Then do the appropriate matches/comparisons.
The logic would be something like:
get day from date
if day from date is the magic day, then
get day from from lastlog -u $USER
if day does not match today's day then
run your command
You can also use what is called 'semaphore file', something like this:
if [[ ! -e /tmp/$(date +%u).sem ]]
then
touch /tmp/$(date +%u).sem
# Do your one-time stuff
fi
However, which approach you choose, I would recommend you to use a full date (date +"%Y%m%d") to avoid potential bug if the user login on Monday, and his next login is in the next Monday.
date +%u | ## Generate timestamp (could be a better date-spec)
tee timestamp.tmp | ## Save a copy for later usage
cmp - timestamp || ## Fail if date-spec changed
{
## In that case, update timestamp
mv timestamp.tmp timestamp &&
## And only if that succeeds, run your code
echo "Once a day" ;
}
I prefer to touch the timestamp BEFORE running de command, because it is usually safer not to run anything at all than running it repeatedly. (The partition could have been remounted read-only, the disk might be full, permissions could have been changed...)

filename last modification date shell in script

I'm using bash to build a script where I will get a filename in a variable an then with this variable get the file unix last modification date.
I need to get this modification date value and I can't use stat command.
Do you know any way to get it with the common available *nix commands?
Why you shouldn't use ls:
Parsing ls is a bad idea. Not only is the behaviour of certain characters in filenames undefined and platform dependant, for your purposes, it'll mess with dates when they're six months in the past. In short, yes, it'll probably work for you in your limited testing. It will not be platform-independent (so no portability) and the behaviour of your parsing is not guaranteed given the range of 'legal' filenames on various systems. (Ext4, for example, allows spaces and newlines in filenames).
Having said all that, personally, I'd use ls because it's fast and easy ;)
Edit
As pointed out by Hugo in the comments, the OP doesn't want to use stat. In addition, I should point out that the below section is BSD-stat specific (the %Sm flag doesn't work when I test on Ubuntu; Linux has a stat command, if you're interested in it read the man page).
So, a non-stat solution: use date
date, at least on Linux, has a flag: -r, which according to the man page:
display the last modification time of FILE
So, the scripted solution would be similar to this:
date -r ${MY_FILE_VARIABLE}
which would return you something similar to this:
zsh% date -r MyFile.foo
Thu Feb 23 07:41:27 CST 2012
To address the OP's comment:
If possible with a configurable date format
date has a rather extensive set of time-format variables; read the man page for more information.
I'm not 100% sure how portable date is across all 'UNIX-like systems'. For BSD-based (such as OS X), this will not work; the -r flag for the BSD-date does something completely different. The question doesn't' specify exactly how portable a solution is required to be. For a BSD-based solution, see the below section ;)
A better solution, BSD systems (tested on OS X, using BSD-stat; GNU stat is slightly different but could be made to work in the same way).
Use stat. You can format the output of stat with the -f flag, and you can select to display only the file modification data (which, for this question, is nice).
For example, stat -f "%m%t%Sm %N" ./*:
1340738054 Jun 26 21:14:14 2012 ./build
1340738921 Jun 26 21:28:41 2012 ./build.xml
1340738140 Jun 26 21:15:40 2012 ./lib
1340657124 Jun 25 22:45:24 2012 ./tests
Where the first bit is the UNIX epoch time, the date is the file modification time, and the rest is the filename.
Breakdown of the example command
stat -f "%m%t%Sm %N" ./*
stat -f: call stat, and specify the format (-f).
%m: The UNIX epoch time.
%t: A tab seperator in the output.
%Sm: S says to display the output as a string, m says to use the file modification data.
%N: Display the name of the file in question.
A command in your script along the lines of the following:
stat -f "%Sm" ${FILE_VARIABLE}
will give you output such as:
Jun 26 21:28:41 2012
Read the man page for stat for further information; timestamp formatting is done by strftime.
have perl?
perl -MFile::stat -e "print scalar localtime stat('FileName.txt')->mtime"
How about:
find $PATH -maxdepth 1 -name $FILE -printf %Tc
See the find manpage for other values you can use with %T.
You can use the "date" command adding the desired format option the format:
date +%Y-%m-%d -r /root/foo.txt
2013-05-27
date +%H:%M -r /root/foo.txt
23:02
You can use ls -l which lists the last modification time, and then use cut to cut out the modification date:
mod_date=$(ls -l $file_name | cut -c35-46)
This works on my system because the date appears between columns 35 to 46. You might have to play with it on your system.
The date is in two different formats:
Mmm dd hh:mm
Mmm dd yyyy
Files modified more than a year ago will have the later format. Files modified less than a year ago will have to first format. You could search for a ":" and know which format the file is in:
if echo "$mod_date" | grep -q ":"
then
echo "File was modified within the year"
else
echo "File was modified more than a year ago"
fi

Get current time in seconds since the Epoch on Linux, Bash

I need something simple like date, but in seconds since 1970 instead of the current date, hours, minutes, and seconds.
date doesn't seem to offer that option. Is there an easy way?
This should work:
date +%s
Just to add.
Get the seconds since epoch(Jan 1 1970) for any given date(e.g Oct 21 1973).
date -d "Oct 21 1973" +%s
Convert the number of seconds back to date
date --date #120024000
The command date is pretty versatile. Another cool thing you can do with date(shamelessly copied from date --help).
Show the local time for 9AM next Friday on the west coast of the US
date --date='TZ="America/Los_Angeles" 09:00 next Fri'
Better yet, take some time to read the man page
http://man7.org/linux/man-pages/man1/date.1.html
Pure bash solution
Since bash 5.0 (released on 7 Jan 2019) you can use the built-in variable EPOCHSECONDS.
$ echo $EPOCHSECONDS
1547624774
There is also EPOCHREALTIME which includes fractions of seconds.
$ echo $EPOCHREALTIME
1547624774.371210
EPOCHREALTIME can be converted to micro-seconds (μs) by removing the decimal point. This might be of interest when using bash's built-in arithmetic (( expression )) which can only handle integers.
$ echo ${EPOCHREALTIME/./}
1547624774371210
In all examples from above the printed time values are equal for better readability. In reality the time values would differ since each command takes a small amount of time to be executed.
So far, all the answers use the external program date.
Since Bash 4.2, printf has a new modifier %(dateformat)T that, when used with argument -1 outputs the current date with format given by dateformat, handled by strftime(3) (man 3 strftime for informations about the formats).
So, for a pure Bash solution:
printf '%(%s)T\n' -1
or if you need to store the result in a variable var:
printf -v var '%(%s)T' -1
No external programs and no subshells!
Since Bash 4.3, it's even possible to not specify the -1:
printf -v var '%(%s)T'
(but it might be wiser to always give the argument -1 nonetheless).
If you use -2 as argument instead of -1, Bash will use the time the shell was started instead of the current date. This can be used to compute elapsed times
$ printf -v beg '%(%s)T\n' -2
$ printf -v now '%(%s)T\n' -1
$ echo beg=$beg now=$now elapsed=$((now-beg))
beg=1583949610 now=1583953032 elapsed=3422
With most Awk implementations:
awk 'BEGIN {srand(); print srand()}'
This is an extension to what #pellucide has done, but for Macs:
To determine the number of seconds since epoch (Jan 1 1970) for any given date (e.g. Oct 21 1973)
$ date -j -f "%b %d %Y %T" "Oct 21 1973 00:00:00" "+%s"
120034800
Please note, that for completeness, I have added the time part to the format. The reason being is that date will take whatever date part you gave it and add the current time to the value provided. For example, if you execute the above command at 4:19PM, without the '00:00:00' part, it will add the time automatically. Such that "Oct 21 1973" will be parsed as "Oct 21 1973 16:19:00". That may not be what you want.
To convert your timestamp back to a date:
$ date -j -r 120034800
Sun Oct 21 00:00:00 PDT 1973
Apple's man page for the date implementation:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/date.1.html
use this bash script (my ~/bin/epoch):
#!/bin/bash
# get seconds since epoch
test "x$1" == x && date +%s && exit 0
# or convert epoch seconds to date format (see "man date" for options)
EPOCH="$1"
shift
date -d #"$EPOCH" "$#"

Resources