Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How can I get yesterday's date ?

137 views
Skip to first unread message

richyts

unread,
Jan 23, 2002, 3:19:15 AM1/23/02
to
what could be the simplest way of obtaining yesterday's date in a
shell script ?.. i can use bsh, csh, ksh and awk on aix4.3.

Alex

unread,
Jan 23, 2002, 5:22:55 AM1/23/02
to

YESTERDAY=$(expr `date +%d` - 1).$(date +%m.%y)
under Solaris works good !!!


"richyts" <ric...@yahoo.com> schrieb im Newsbeitrag
news:d1c185ef.02012...@posting.google.com...

Chris F.A. Johnson

unread,
Jan 23, 2002, 6:20:37 AM1/23/02
to
On Wed, 23 Jan 2002, Alex wrote:

> "richyts" <ric...@yahoo.com> schrieb im Newsbeitrag
> news:d1c185ef.02012...@posting.google.com...
> > what could be the simplest way of obtaining yesterday's date in a
> > shell script ?.. i can use bsh, csh, ksh and awk on aix4.3.

[please don't top post]

> YESTERDAY=$(expr `date +%d` - 1).$(date +%m.%y)
> under Solaris works good !!!

Have you tried it on the first day of the month?

The easiest way is to use a version of date that allows you to specify
which date to display. In GNU date, for example:

date -d yesterday
or
date -d "-1 day"

FreeBSD and NetBSD also have versions that allow specifying a date (I
think they use the -v option).

Another way is to calculate the Julian day (or something like it),
subtract 1, then convert back to a calendar date:

c2j() { ## c2j YYYY MM DD
echo $* | awk '
{day = $3; month = $2; year = $1
if (year > 0) ycor = 0; else ycor = .75
if (month <= 2) {
year--
month += 12;
}
b = 0
if ( ((year * 10000) + (month * 100) + day) >= 15821015) {
a = year / 100
b = 2 - a + (a / 4)
}
yn = int((365.25 * year) - ycor)
printf("%d\n",yn + (30.6001 * (month + 1)) + day + 1720994 + b)
}'
}

j2c() { ## j2c julian_day
echo $* | awk '{
jdate = $1
z = jdate + 1
if (z < 2299161) a = z;
else {
alpha = int(int(z - 1867216.25) / 36524.25)
a = int(z + 1 + alpha - int(alpha / 4))
}
b = a + 1524
c = int((b - 122.1) / 365.25)
d = int(365.25 * c)
e = int (int(b - d) / 30.6001)
day = int(b - d - int(30.6001 * e))
month = int((e < 13.5) ? e - 1 : e - 13)
year = int( (month > 2.5) ? (c - 4716) : c - 4715)
printf "%04d-%02d-%02d\n", year, month, day
}'
}

jdate=`c2j \`date "+%Y %m %d"\``
j2c $(( jdate - 1 ))

These should probably be converted to awk functions so both can be
used with a single invocation of awk.

--
Chris F.A. Johnson http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2002, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License


richyts

unread,
Jan 23, 2002, 9:10:37 PM1/23/02
to
"Alex" <aham...@materna.de> wrote in message news:<a2m2ov$9eq$1...@penthesilea.materna.de>...

i'm afraid it isnt so straight... then i need to handle month, year
rollover and leap year logic etc.

richyts

unread,
Jan 23, 2002, 9:31:49 PM1/23/02
to
> The easiest way is to use a version of date that allows you to specify
> which date to display. In GNU date, for example:
>
> date -d yesterday
> or
> date -d "-1 day"
>
> FreeBSD and NetBSD also have versions that allow specifying a date (I
> think they use the -v option).

im afraid aint using a gnu version.... i tried "date -d" but it spits back..
___________

$ date -d yesterday
date: Not a recognized flag: d
Usage: date [-u] [+"Field Descriptors"]
$
___________

thanks you very much for this snippet... i'll try this one for now....

Tony Lawrence

unread,
Jan 24, 2002, 2:54:03 AM1/24/02
to
richyts wrote:


http://pcunix.com/Unix/yesterday.html


--
Tony Lawrence
SCO/Linux Support Tips, How-To's, Tests and more: http://pcunix.com

Sean Murphy

unread,
Jan 29, 2002, 5:41:45 PM1/29/02
to

There is probably a better way, but here's how I've done it...

current_month=`date +%m`

current_year=`date +%Y`

current_day=`date +%d`

if [ $current_day -eq '01' ] && [ $current_month -eq '01' ]

then

get_year=`expr $current_year - 1`

get_month=12

else

get_year=$current_year

fi

if [ $current_day -eq '01' ] && [ $current_month -ne '01' ]

then

get_month=`expr $current_month - 1`

if [ $get_month -lt 10 ]

then

get_month="0"$get_month

fi

else

get_month=$current_month

fi

"richyts" <ric...@yahoo.com> wrote in message
news:d1c185ef.02012...@posting.google.com...

Valdis Kletnieks

unread,
Feb 5, 2002, 5:42:33 PM2/5/02
to
ric...@yahoo.com (richyts) writes:

> what could be the simplest way of obtaining yesterday's date in a
> shell script ?.. i can use bsh, csh, ksh and awk on aix4.3.

Since you're on AIX (though this has worked elsewhere for me as well)

#!/bin/ksh

yesterday=$(TZ=EST26EDT date +%mm-%d-%yy) or whatever formatting you want.

The trick is to specify an "hours" offset sufficient to roll it into yesterday.

And of course, TZ=EST-19EDT date will get you tomorrow...

TZ=EST720EDT date for a month ago... (24*30)... etc etc etc.

--
Valdis Kletnieks
Computer Systems Senior Engineer
Virginia Tech

Tapani Tarvainen

unread,
Feb 6, 2002, 4:47:32 AM2/6/02
to
Valdis Kletnieks <valdis.k...@vt.edu> writes:

> ric...@yahoo.com (richyts) writes:
>
> > what could be the simplest way of obtaining yesterday's date in a
> > shell script ?.. i can use bsh, csh, ksh and awk on aix4.3.
>
> Since you're on AIX (though this has worked elsewhere for me as well)
>
> #!/bin/ksh
>
> yesterday=$(TZ=EST26EDT date +%mm-%d-%yy) or whatever formatting you want.
>
> The trick is to specify an "hours" offset sufficient to roll it into yesterday.

Sigh. I wish people would forget that - it isn't portable and
may even break in the same system some of the time even if
it works most of the time.

The problem is that many (most?) systems don't accept offsets over 24
hours (often treat bigger ones as 24h), and if your timezone is west of
GMT you can't set the offset far enough for the trick to work all day.

Portable solutions have been posted in this group something like
once a month. Here's one (again):

---------------------------------clip---------------------------------
#! /usr/bin/ksh
# Get yesterday's date in YYYY-MM-DD format.
# With argument N in range 1..28 gets date N days before.
# Tapani Tarvainen January 2002
# This code is in the public domain.

OFFSET=${1:-1}

case $OFFSET in
*[!0-9]* | ???* | 3? | 29) print -u2 "Invalid input" ; exit 1;;
esac

eval `date "+day=%d; month=%m; year=%Y`
typeset -Z2 day month
typeset -Z4 year

# Subtract offset from day, if it goes below one use 'cal'
# to determine the number of days in the previous month.
day=$((day - OFFSET))
if (( day <= 0 )) ;then
month=$((month - 1))
if (( month == 0 )) ;then
year=$((year - 1))
month=12
fi
set -A days `cal $month $year`
xday=${days[$(( ${#days[*]}-1 ))]}
day=$((xday + day))
fi

print $year-$month-$day
print $month/$day/${year#??}
---------------------------------clip---------------------------------

--
Tapani Tarvainen

Peter J. Acklam

unread,
Feb 6, 2002, 6:36:34 AM2/6/02
to
Tapani Tarvainen <t...@it.jyu.fi> wrote:

> Portable solutions have been posted in this group something like
> once a month. Here's one (again):
>
> ---------------------------------clip---------------------------------
> #! /usr/bin/ksh
> # Get yesterday's date in YYYY-MM-DD format.
> # With argument N in range 1..28 gets date N days before.

> [...]

Here is another, although not a shell script...

#!/usr/bin/perl -w
#
# Print yesterday's date. Unsigned or negative input goes N days
# back in time. Signed positive input goes forward in time.

$days = @ARGV ? shift : 1;
$days = -$days if $days =~ /^\d/;
@lt = localtime(time() + 86400*$days);
printf "%d-%02d-%02d\n", $lt[5]+1900, $lt[4]+1, $lt[3];

Peter

--
I put the batteries the wrong way in my flashlight.
Now when I turn it on, it gets dark.

Chris F.A. Johnson

unread,
Feb 6, 2002, 1:53:19 PM2/6/02
to

I have a couple of quibbles with this script:

1. It is NOT portable; it's ksh specific, even though there's nothing
in it that cannot be done in a generic POSIX shell.

2. It uses an unnecessary external command (cal), some versions of
which may not work in this context.

To get the number of days in a specific month, I use:

days_in_month() { ## USAGE: days_in_month [month [year]]
dim_m=${1:-`date +%m`}
case ${dim_m#0} in
9|4|6|11) echo 30 ;; ## 30 days hath September...
1|3|5|7|8|10|12) echo 31 ;;
2) is_leap_year ${2:-`date +%Y`} && echo 29 || echo 28 ;;
esac
}

is_leap_year() { ## USAGE: is_leap_year [year]
ily_yr=${1:-`date +%Y`}
[ $(( $ily_yr % 400)) -eq 0 -o \
\( $(( $ily_yr % 4)) -eq 0 -a $(( $ily_yr % 100)) -ne 0 \) ]
}

Then you can replace 3 lines (set -A ....) with:

day=$(( `days_in_month $month $year` + $day ))

Valdis Kletnieks

unread,
Feb 6, 2002, 5:11:34 PM2/6/02
to
Tapani Tarvainen <t...@it.jyu.fi> writes:

> Sigh. I wish people would forget that - it isn't portable and
> may even break in the same system some of the time even if
> it works most of the time.

Right. Which is why I prefaced it with "since the person is on AIX".
All AIX 'date' commands I've seen from 3.1 through 5.1 (which cover
over 10 years) *do* support it. I don't have any AIX 1.2 (PC), AIX/370,
or AIX 2.2.1 (RT) handy to check what they did, although those 3 were
all fairly painfully SVR2 in flavor.

Tapani Tarvainen

unread,
Feb 7, 2002, 9:46:40 AM2/7/02
to
Valdis Kletnieks <valdis.k...@vt.edu> writes:

> Tapani Tarvainen <t...@it.jyu.fi> writes:
>
> > Sigh. I wish people would forget that - it isn't portable and
> > may even break in the same system some of the time even if
> > it works most of the time.
>
> Right. Which is why I prefaced it with "since the person is on AIX".
> All AIX 'date' commands I've seen from 3.1 through 5.1 (which cover
> over 10 years) *do* support it.

I'm curious, how big offsets do work there?
If you have an AIX box at hand, could you please try
the following commands and report the results:

date
TZ=TMP+23 date
TZ=TMP+24 date
TZ=TMP+30 date
TZ=TMP+36 date
TZ=TMP+100 date

I've yet to see a system where the last one would work
correctly, but I haven't tried it on AIX.

--
Tapani Tarvainen

Tapani Tarvainen

unread,
Feb 7, 2002, 10:01:34 AM2/7/02
to
"Chris F.A. Johnson" <c.f.a....@rogers.com> writes:

> On 6 Feb 2002, Tapani Tarvainen wrote:

> > #! /usr/bin/ksh
> > # Get yesterday's date in YYYY-MM-DD format.

[...]

> I have a couple of quibbles with this script:
>
> 1. It is NOT portable; it's ksh specific, even though there's nothing
> in it that cannot be done in a generic POSIX shell.

True.

> 2. It uses an unnecessary external command (cal), some versions of
> which may not work in this context.

Do you know of a version of cal which would fail there?
Does anyone?

> To get the number of days in a specific month, I use:
>
> days_in_month() { ## USAGE: days_in_month [month [year]]
> dim_m=${1:-`date +%m`}
> case ${dim_m#0} in
> 9|4|6|11) echo 30 ;; ## 30 days hath September...
> 1|3|5|7|8|10|12) echo 31 ;;
> 2) is_leap_year ${2:-`date +%Y`} && echo 29 || echo 28 ;;
> esac
> }
>
> is_leap_year() { ## USAGE: is_leap_year [year]
> ily_yr=${1:-`date +%Y`}
> [ $(( $ily_yr % 400)) -eq 0 -o \
> \( $(( $ily_yr % 4)) -eq 0 -a $(( $ily_yr % 100)) -ne 0 \) ]
> }

It could be argued that 'cal' is more portable because month lengths
vary in different locations and it could be hoped 'cal' has been
localised ... have you considered September 1752 in America (19 days)
or February 1712 in Sweden (30 days)? :-)

(Not exactly a practical issue, I agree. Your code is better.)

--
Tapani Tarvainen

Chris F.A. Johnson

unread,
Feb 7, 2002, 10:57:31 AM2/7/02
to
On 7 Feb 2002, Tapani Tarvainen wrote:

> "Chris F.A. Johnson" <c.f.a....@rogers.com> writes:
>
> > On 6 Feb 2002, Tapani Tarvainen wrote:
>
> > > #! /usr/bin/ksh
> > > # Get yesterday's date in YYYY-MM-DD format.
> [...]
>
> > I have a couple of quibbles with this script:
> >
> > 1. It is NOT portable; it's ksh specific, even though there's nothing
> > in it that cannot be done in a generic POSIX shell.
>
> True.
>
> > 2. It uses an unnecessary external command (cal), some versions of
> > which may not work in this context.
>
> Do you know of a version of cal which would fail there?
> Does anyone?

I have had a couple of versions that printed the month sandwiched
between the preceding and following month, e.g.:

January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2
6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9
13 14 15 16 17 18 19 10 11 12 13 14 15 16 10 11 12 13 14 15 16
20 21 22 23 24 25 26 17 18 19 20 21 22 23 17 18 19 20 21 22 23
27 28 29 30 31 24 25 26 27 28 24 25 26 27 28 29 30

I saw this on SCO SysV/386 R3.2. I liked it so much that I wrote a
version for the Amiga that did the same thing (it could also
highnlight the current date). I've lost the source code, but one day
I'll get around to recreating it.

> > To get the number of days in a specific month, I use:
> >
> > days_in_month() { ## USAGE: days_in_month [month [year]]
> > dim_m=${1:-`date +%m`}
> > case ${dim_m#0} in
> > 9|4|6|11) echo 30 ;; ## 30 days hath September...
> > 1|3|5|7|8|10|12) echo 31 ;;
> > 2) is_leap_year ${2:-`date +%Y`} && echo 29 || echo 28 ;;
> > esac
> > }
> >
> > is_leap_year() { ## USAGE: is_leap_year [year]
> > ily_yr=${1:-`date +%Y`}
> > [ $(( $ily_yr % 400)) -eq 0 -o \
> > \( $(( $ily_yr % 4)) -eq 0 -a $(( $ily_yr % 100)) -ne 0 \) ]
> > }
>
> It could be argued that 'cal' is more portable because month lengths
> vary in different locations and it could be hoped 'cal' has been
> localised ... have you considered September 1752 in America (19 days)
> or February 1712 in Sweden (30 days)? :-)
>
> (Not exactly a practical issue, I agree. Your code is better.)

Writing date calculations that will work for any date and locale is
even more difficult than writing all one's shell scripts to work on
all shells on all systems.

Tapani Tarvainen

unread,
Feb 7, 2002, 11:43:51 AM2/7/02
to
"Chris F.A. Johnson" <c.f.a....@rogers.com> writes:

> I have had a couple of versions [of cal] that printed the month sandwiched


> between the preceding and following month

Yuck. But, you've convinced me: using 'cal' is not portable.

> Writing date calculations that will work for any date and locale is
> even more difficult than writing all one's shell scripts to work on
> all shells on all systems.

That pretty much sums it up. :-)

--
Tapani Tarvainen

Valdis Kletnieks

unread,
Feb 7, 2002, 2:01:29 PM2/7/02
to
Tapani Tarvainen <t...@it.jyu.fi> writes:

> I'm curious, how big offsets do work there?

*BIG* offsets.

On my AIX5.1 box:

[~]1 date
Thu Feb 7 13:48:34 EST 2002
[~]1 TZ=EST8765EDT date
Wed Feb 7 13:48:45 EST 2001
[~]1 TZ=EST87605EDT date
Mon Feb 10 13:49:02 EST 1992
[~]1 TZ=EST-87695EDT date
Thu Feb 9 17:49:23 EST 2012
[~]1 TZ=EST876005EDT date
Tue Mar 4 13:50:55 EST 1902

Seeing drift there because I didn't allow for leap years....

You can't forwardspace over the 2038 barrier:

[~]1 TZ=EST-315104EDT date
Tue Jan 19 02:56:09 EST 2038
[~]1 TZ=EST-315105EDT date
Fri Dec 13 21:27:56 EST 1901

Or back before 00:00 Jan 01 1901 UTC:

[~]1 TZ=EST877942EDT date
Fri Dec 13 21:00:12 EST 1901
[~]1 TZ=EST877943EDT date
Tue Jan 19 02:28:25 EST 2038

0 new messages