Calculating number of days given date in UNIX - date

I have tried to calculate number of days from January 1st to given date in same year.
Option -d for UNIX command isn't working
date -d
date: illegal option -- d
Usage: date [-u] [+format]
date [-u] [mmddhhmm[[cc]yy]]
date [-a [-]sss.fff]
I'm using this script but is too long.
Is there a simple way to calculate a nuber of days?
EDIT
Result of a script:
$ ksh datecalc -a 2013 2 5 - 2013 1 1
$ 35

OK so this may be a bit far fetched, but mysql client (or other DB clients) can come in handy for this as they have reliable and well documented date functions.
$ mysql ..... --silent -e "select datediff('2013-02-05', '2013-01-01') from dual;"
35
$
where ..... are your connection options.

If you have Perl installed, you can do:
perl -MPOSIX=strftime -le 'print strftime("%j",localtime)'
For a specific day, e.g. Feb 5:
perl -MPOSIX=strftime -le '
#d=(2013,2,5);
print strftime("%j",0,0,0,$d[2],$d[1]-1,$d[0]-1900)
'
036

Related

I am using Sun OS, I want my script to read date from a file(in format %Y%m%d) and add 1 day to that date

I am working in Sun OS environment, I want to add a functionality to my existing unix ksh script where it allows to read a date(in %Y%m%d format) from a file and add 1 day and rewrite the same into that file. [please note: not adding day to current date instead i want to add 1 day to i/p date present in a file].
Eg:DateFile.dat
20200620
I want my script to change it to 20200621 at the end of run.
My code as below:
#!/bin/ksh
ip_dte</home/{file_Path}
echo $ip_dte
dte_add=`TZ=AEST-24 "$ip_dte"`
echo $dte_add
Something like that ? :
#!/bin/ksh
# Starting date, YYYYMMDD (yes I should verify the format :) )
FIRST_DATE=$1
[[ -z $FIRST_DATE ]] && FIRST_DATE=$(date +"%Y%m%d")
# 1 day in seconds
PERIOD=86400
# Transform the starting date in second and add 1 day
SECOND_DATE=$(( $(date -d "$FIRST_DATE" +"%s")+$PERIOD ))
# Transform the second date from second to human date format
print "Second date is $(date -d #"$SECOND_DATE" +"%Y%m%d")"
We can let date do the calculations and formatting for us:
$ date1='20200415'
$ date -d "${date1}+1 day" # add 1 day, use default output format
Thu Apr 16 00:00:00 UTC 2020
$date -d "${date1}+1 day" '+%Y%m%d' # add 1 day, change to YYYYMMDD format
20200416
$ date2=$(date -d "${date1}+1 day" '+%Y%m%d') # save new date in variable in YYYYMMDD format
$ echo "${date2}"
20200416
Here's a ksh fiddle of the above.
The other answers will work if you have ‎CSWcoreutils or SUNWgnu-coreutils installed. You may have to run gdate or /usr/gnu/bin/date.
But if you have a recent version of Solaris, ksh will be ksh93, and you can use the %T format in printf:
$ cat ddd
20200620
$ ip_dte=`cat ddd`
$ printf "%(%Y%m%d)T\n" "$ip_dte tomorrow"
20200621
If you have perl with the Time::Local module on the old Solaris server, try this:
#!/bin/ksh
ip_dte=20200531 # or read date from file into ip_dte
echo $ip_dte
timestamp=`perl -MTime::Local=timelocal -e '($y,$m,$d) = $ARGV[0] =~ /(\d\d\d\d)(\d\d)(\d\d)/; $m=$m-1; print timelocal(1,1,1,$d,$m,$y);' $ip_dte`
dte_add=`perl -MPOSIX=strftime -e 'print strftime("%Y%m%d", localtime($ARGV[0] +86400));' $timestamp`
echo $dte_add

Convert timestamp Jan 05 11:45 to DD/MM/YY HH:MM format in Unix korn shell

My program goes as shown below where $i is a file.
TIMESTAMP=`ls -ltr $i | awk '{print $6,$7,$8;}'`
Output of this is Jan 6 12:13.
For sorting based on the date, I need to convert it to the format DD/MM/YY HH:MM.
Also please suggest if there is a way of sorting the files with the timestamp in the format Jan 6 12:13.
I am currently using Korn shell. Solaris 5.10.
Under absolutely no circumstances, parse ls(1) output!
Instead, use the right tool for the job. If you need to sort ls output, use ls’ various sort options. If you need to do other processing, make use of a tool… in the Solaris 8 installation I have access to, GNU stat is installed, which makes this easy:
tg#stinky:~ $ stat -c '%y %n' /bin/[ck]sh
2008-07-08 14:16:07.000000000 +0200 /bin/csh
2008-06-10 16:28:32.000000000 +0200 /bin/ksh
tg#stinky:~ $ uname -a
SunOS stinky 5.8 Generic_117350-61 sun4u sparc SUNW,Sun-Fire-V240 Solaris
Otherwise, you could use scripting languages with stat(2) access, such as Perl, to display times for pathnames, like this (be aware of newlines in filenames, though):
tg#stinky:~ $ find /bin/[ck]sh | perl -MPOSIX -ne 'chomp; print POSIX::strftime("%d/%m/%Y %H:%M\n",localtime((stat)[9]));'
08/07/2008 14:16
10/06/2008 16:28
But, as others already pointed out in comments, %Y-%m-%d is indeed easier to sort.
The Korn Shell does not have any built-in functions for time manipulation.
The “magic chars in filenames”-safe version of this (also tested under Solaris 8) is:
find /bin/[ck]sh -print0 | perl -0 -MPOSIX -ne 'chomp; print POSIX::strftime("%d/%m/%Y %H:%M\n",localtime((stat)[9]));'
Of course, the find /bin/[ck]sh part is just an example, you can feed any pathname list you have to the command.

30 minutes ago time format in Solaris

I am writing the below command for 1 hour ago in Solaris format.
date +%Y-%m-%d-%H:%M:%S -M "1 hour ago"
But I need half hour (30 minutes) ago format in Linux.
If you are running on Linux, this should work if run in bash:
date --date=#$((`date +%s`-1800))
(I tested it on Solaris 11 using gdate instead of date. I don't have a Linux box booted right now.)
Solaris 10 date command doesn't support the -M flag which is a GNU date extension.
An alternative is to use perl.
Here is how to get one hour ago:
perl -e 'my ($y,$m,$d,$H,$M,$S)=(localtime(time-3600))[5,4,3,2,1,0];
printf "%04d-%02d-%02d-%02d:%02d:%02d\n",$y+1900,$m+1,$d,$H,$M,$S;'
and half-an-hour ago:
perl -e 'my ($y,$m,$d,$H,$M,$S)=(localtime(time-1800))[5,4,3,2,1,0];
printf "%04d-%02d-%02d-%02d:%02d:%02d\n",$y+1900,$m+1,$d,$H,$M,$S;'
Edit: Using the POSIX Perl module, you can also do it this simpler way:
perl -e 'use POSIX qw(strftime);
print strftime("%Y-%m-%d-%H:%M:%S\n", localtime(time-1800));'

How do I pass Shell parameters to Perl script?

I am trying to find dates with in a certain format, I have done it before with perl(strftime), but that time I mentioned a static time, this time i need a variable $CURRENT_DAY here.
Below is the issue, when equate the CURRENT_DAY by using DAYHOUR=86400 and an integer, the variable is giving the right time, but once I put $CURRENT_DAY variable in the statement, the date would not decrease.
$ DAYHOUR=86400
$ DAY=1
$ CURRENT_DAY=`echo $(($DAYHOUR*$DAY))`
$ DD=`perl -e 'use POSIX; print strftime "%d", localtime time - $CURRENT_DAY;'`
$ echo $DD
20
$ DAY=`echo $(($DAY+1))`
$ CURRENT_DAY=`echo $(($DAYHOUR*$DAY))`
$ DD=`perl -e 'use POSIX; print strftime "%d", localtime time - $CURRENT_DAY;'`
$ echo $DD
20
$ DAY=`echo $(($DAY+1))`
$ echo $DAY
3
$ CURRENT_DAY=`echo $(($DAYHOUR*$DAY))`
$ echo $CURRENT_DAY
259200
$ echo `perl -e 'use POSIX; print strftime "%d", localtime time - 259200;'`
17
Your principal problem is that $CURRENT_DAY is a Perl script variable. By enclosing your Perl script in single quotes, there is no visibility to the shell's variable of the same name. Had you enabled warnings (e.g. with -w) you would have seen this.
There are a couple of ways to circumvent your problem. One is to use double quotes to encapsulate your Perl thus allowing the shell to first expand its variable's value before the Perl is run:
CURRENT_DAY=3
perl -MPOSIX -wle "print strftime qq(%d),localtime time-(86400*$CURRENT_DAY);print $CURRENT_DAY"
17
Another is:
export CURRENT_DAY=3
perl -MPOSIX -wle 'print strftime qq(%d),localtime time-(86400*$ENV{CURRENT_DAY})'
Be advised that adding or subtracting 24-hours from a time to calculate yesterday or tomorrow will not correctly account for daylight saving changes. See this faq
You may pass them as arguments in #ARGV:
$ dd_seconds_ago () { perl -MPOSIX -e 'print strftime q(%d), localtime(time - shift)' "$#"; }
$ DD=$(dd_seconds_ago 86400)
Without an argument and in the above context, shift shifts #ARGV, which is handy for shell one-liners like this
Like Perl, sh doesn't interpolate in single quoted strings, so Perl sees $CURRENT_DAY instead of the actual number, and you've never assigned anything to that Perl variable. You could switch to a double-quoted string.
perl -MPOSIX -e"print strftime '%d', localtime time-$CURRENT_DAY;"
That's fine since $CURRENT_DAY is a number, but if you wanted to pass an arbitrary string, you'd use an env var or an argument.
export CURRENT_DAY
perl -MPOSIX -e'print strftime "%d", localtime time-$ENV{CURRENT_DAY};'
or
perl -MPOSIX -e'print strftime "%d", localtime time-$ARGV[0];' -- "$CURRENT_DAY"
Note that your code is buggy, though. There are two hours every year for which your code will give the wrong answer because not all days have 86400 seconds. Some have 82800, and others have 90000. (And that's assuming leap seconds don't factor in.) A Perl solution that doesn't suffer from that problem follows:
perl -MDateTime -e'print
DateTime->today(time_zone=>"local")
->subtract(days=>$ARGV[0])
->strftime("%d")' -- "$DAY"
Or you could use date.
date -d "$DAY days ago" +%d
I am assuming you want to pass the number of days in the past in the shell variable DAY and that you want the answer in the shell variable DD
So if it is the 20th of the month and the DAY is 1, then DD should be set to 19
You could modify your Perl command as follows:
DD=`perl -e 'use POSIX; print strftime "%d", localtime( time - ($ENV{DAY}* 86400))';
Alternatively, you could use the GNU date command that is widely available
DD=`date -d "$DAY days ago" +%d`
Using date is probably better at dealing with leap days, etc

How can I convert a file full of unix time strings to human readable dates?

I am processing a file full of unix time strings. I want to convert them all to human readable.
The file looks like so:
1153335401
1153448586
1153476729
1153494310
1153603662
1153640211
Here is the script:
#! /bin/bash
FILE="test.txt"
cat $FILE | while read line; do
perl -e 'print scalar(gmtime($line)), "\n"'
done
This is not working. The output I get is Thu Jan 1 00:00:00 1970 for every line. I think the line breaks are being picked up and that is why it is not working. Any ideas? I'm using Mac OSX is that makes any difference.
$ perl -lne 'print scalar gmtime $_' test.txt
Wed Jul 19 18:56:41 2006
Fri Jul 21 02:23:06 2006
Fri Jul 21 10:12:09 2006
Fri Jul 21 15:05:10 2006
Sat Jul 22 21:27:42 2006
Sun Jul 23 07:36:51 2006
Because $line is in single quotes, it's not being processed by bash, and so $line is treated as an (undefined) Perl variable rather than a bash variable.
You don't need a while read bash loop; Perl can do the looping itself using its -n option.
perl -nE 'say scalar(gmtime($_))' test.txt
(using -E to enable say, which automatically appends a newline)
Don't use cat.
#! /bin/bash
file="test.txt"
while read line
do
date -d #$line
done < "$file"
It's not the line breaks, it's that the $line inside the Perl script is a different variable than the $line in the bash script. You could try:
perl -e "print scalar(gmtime($line)),qq/\\n/"
Note the double-quotes, which allow bash to do variable interpolation.
No need for Perl:
awk '{ print strftime("%c", $0) }' somefile.txt
The issue is that you haven't assigned anything to the $line variable, so it defaults to a zero-value, which is why you always get Thu Jan 1 00:00:00 1970 as an output.
gbacon's answer is about as slick as it gets in Perl.
GNU date/xargs solution:
xargs -i date -d "1970-01-01 00:00:00 {} seconds" </tmp/timestamps
This simple command will do
cat time.txt | while read line; do date -ud #$line; done > string.txt
Not forgetting that localtime() can be used instead of gmtime() in Perl
So, if you're not in Greenwich in Winter, you can use localtime(), e.g.
Perl code:
my $unixtime = 1417014507;
my $humantime = localtime($unixtime);
print "\$humantime = $humantime \n";
output:
$humantime = Wed Nov 26 15:08:27 2014