nth date

Hi
I need to get the date of 50th day from the last friday for one of the calculation into variable in Unix script. The format required is YYYYMMDD. I have solaris OS and dont have GNU date. I would appreciate if some one can help me with this.
It can be a onliner or function or block of code.

Thanks

I wrote this ultimate time tool for all those shell scripts wanting to do time stuff - parsing, clock, offsets and formatted output. Complex questions might mean you call it more than once or in a loop, like what is the day of month of the next third thursday:

$ cat mysrc/tm2tm.c
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
static void usage_exit()
{
        fputs(
"\n"
"Usage: tm2tm { -c | { - | <tm_str> } <in_fmt> } <delta> <out_fmt>\n"
" First, gets dates and time(s):\n"
"  - when '-c' is used, from gettimeofday() (microsecond system clock)\n"
"  - when '-' is used, from the front of each line of stdin per <in_fmt>\n"
"  - else, from the front of <tm_str> per <in_fmt>\n"
" The default year is 2000, and for other elements, minimum values.\n"
" The <in_fmt> is either one of these or composed per strptime():\n"
"    %s       Absolute Unix time in integer seconds\n"
"    %s.%F    Unix time in integer and fractional 6 place seconds\n"
"    %s.%f    Unix time in integer and fractional 1-6 place seconds\n"
" Modify each time by <delta>, an optionally sign, integer number,\n"
"  and optional suffix indicating the time unit (default seconds):\n"
"    Y or y   years           m        months\n"
"    D or d   days            H or h   hours\n"
"    M        minutes         S or s   seconds\n"
" Format the time by <out_fmt>, which supports all of the strftime() values,\n"
"  plus the following:\n"
"    %s       Absolute Unix time in seconds\n"
"    %F       Fractional 6 place seconds\n"
"    %f       Fractional 1-6 place, zero suppressed seconds\n"
" Write the converted time plus any following input data to standard out.\n"
" For example: tm2tm '5/7/05 15:34' '%m/%d/%y %H:%M' -8h '%Y-%m-%d %r %Z'\n"
"  prints '2005-05-07 07:34:00 AM EDT'\n",
                stderr );
        exit( 1 );
}
static void add_u_time( char *os, char *is, struct timeval *tv )
{
        int st ;
        int i ;
        for ( st=0 ; *is ; os++, is++ )
        {
                switch ( *os = *is )
                {
                case '%':
                        st ^= 1 ;
                        continue ;
                case 's':
                        if ( st )
                        {
                                st = 0 ;
                                os += sprintf( os - 1, "%u", tv->tv_sec ) ;
                                os -= 2 ;
                        }
                        continue ;
                case 'f':
                case 'F':
                        if ( st )
                        {
                                st = 0 ;
                                os += sprintf( os - 1, "%6.6u", tv->tv_usec );
                                os -= 2 ;
                                /* trim off up to 5 trailing 0's for %f */
                                for ( i = 0 ;
                                      i < 5 && *os == '0' && *is == 'f' ;
                                      i++ )
                                {
                                        os-- ;
                                }
                        }
                        continue ;
                default:
                        st = 0 ;
                }
        }
        *os = NULL ;
}
int main( int argc, char **argv )
{
        long td = 0L ;
        struct tm tm ;
        struct timeval tv = { 0, 0 };
        int c = 0 ;
        int sff = 0 ;
        int dst_sav ;
        char *td_sufx ;
        char *in_sufx ;
        char *tbufp ;
        char *cp ;
        char tbuf[65536];
        char tbuf2[65536];
        char tbuf3[65536];
        if ( argc < 4 )
                usage_exit();
        if ( !strcmp( argv[1], "-c" ) )
        {
                if ( argc != 4 )
                {
                        usage_exit();
                }
                c = 1 ;
                in_sufx = "" ;
                tbufp = "<system_clock>" ;
        }
        else
        {
                if ( argc != 5 )
                {
                        usage_exit();
                }
                if ( !strcmp( argv[1], "-" ) )
                {
                        tbufp = tbuf ;
                }
                else
                {
                        tbufp = argv[1];
                }
                if ( !strcmp( argv[2], "%s" ) )
                {
                        sff = 1 ;
                }
                else if ( !strcmp( argv[2], "%s.%F" ) )
                {
                        sff = 2 ;
                }
                else if ( !strcmp( argv[2], "%s.%f" ) )
                {
                        sff = 3 ;
                }
        }
        td = strtol( argv[ 3 - c ], &td_sufx, 0 );
        while ( *td_sufx
             && isspace( *td_sufx ) )
        {
                td_sufx++ ;
        }
        do
        {
                if ( c )
                {
                        if ( gettimeofday( &tv, (void *)NULL ) )
                        {
                                perror( "gettimeofday()" );
                                exit( 1 );
                        }
                        localtime_r( &tv.tv_sec, &tm );
                }
                else
                {
                        if ( tbufp == tbuf )
                        {
                                if ( !fgets( tbuf, sizeof( tbuf ), stdin ) )
                                {
                                        if ( ferror( stdin ) )
                                        {
                                                perror( "stdin" );
                                                exit( 1 );
                                        }
                                        exit( 0 );
                                }
                        }
                        if ( sff )
                        {
                                errno = 0 ;
                                tv.tv_sec = strtoul( tbufp, &in_sufx, 0 );
                                if ( errno )
                                {
                                        fprintf( stderr,
                                            "\nInput '%s' not format '%s'",
                                                tbufp, argv[2] );
                                        perror( "" );
                                        continue ;
                                }
                                localtime_r( &tv.tv_sec, &tm );
                                if ( sff > 1 )
                                {
                                        cp = in_sufx ;
                                        errno = 0 ;
                                        tv.tv_usec = strtoul( cp, &in_sufx, 0 );
                                        if ( errno
                                          || *in_sufx != '.' )
                                        {
                                                fprintf( stderr,
                                                 "\nInput '%s' not format '%s'",
                                                        tbufp, argv[2] );
                                                perror( "" );
                                                continue ;
                                        }
                                        while ( ( in_sufx - cp ) < 6
                                             && sff > 2 )
                                        {
                                                tv.tv_usec *= 10 ;
                                                cp-- ;
                                        }
                                }
                        }
                        else
                        {
                                if ( !( in_sufx = strptime( tbufp,
                                                        argv[2], &tm ) ) )
                                {
                                        fprintf( stderr,
                                                "\nInput '%s' not format '%s'",
                                                tbufp, argv[2] );
                                        continue ;
                                }
                                if ( tm.tm_year < 69 )
                                {
                                        tm.tm_year += 100 ;
                                }
                                if ( !tm.tm_mday )
                                {
                                        tm.tm_mday = 1 ;
                                }
                                dst_sav = tm.tm_isdst ;
                                errno = 0 ;
                                tv.tv_sec = mktime( &tm );
                                if ( errno )
                                {
                                        fprintf( stderr, "\n"
"Error converting date-time '%s' using format '%s': ",
                                                tbufp, argv[ 2 ] );
                                        perror( "" );
                                        continue ;
                                }
                                if ( dst_sav < tm.tm_isdst )
                                {
                                        tm.tm_hour-- ;
                                        tv.tv_sec = mktime( &tm );
                                }
                        }
                }
                if ( td )
                {
                        switch( *td_sufx )
                        {
                        case 'y':
                        case 'Y':
                                tm.tm_year += td ;
                                break ;
                        case 'm':
                                tm.tm_mon += td ;
                                break ;
                        case 'w':
                        case 'W':
                                tm.tm_mday += ( 7 * td );
                                break ;
                        case 'd':
                        case 'D':
                                tm.tm_mday += td ;
                                break ;
                        case 'h':
                        case 'H':
                                tm.tm_hour += td ;
                                break ;
                        case 'M':
                                tm.tm_min += td ;
                                break ;
                        case 's':
                        case 'S':
                        case NULL:
                                tm.tm_sec += td ;
                                break ;
                        default:
                                fprintf( stderr,
        "\n"
        "Fatal: Unknown delta unit %c in delta arg '%s'.\n",
                                        *td_sufx, argv[ 3 - c ] );
                                exit( 1 );
                        }
                        errno = 0 ;
                        tv.tv_sec = mktime( &tm );
                        if ( errno )
                        {
                                fprintf( stderr, "\n"
        "Error converting time + delta '%s' using ",
                                        argv[ 3 - c ] );
                                perror( "mktime()" );
                                continue ;
                        }
                } /* if td */
                add_u_time( tbuf2, argv[ 4 - c ], &tv );
                if ( !strftime( tbuf3, sizeof( tbuf3 ), tbuf2, &tm ) )
                {
                        fprintf( stderr, "\n"
"String too long using format '%s' on time '%s'\n", tbuf2, tbufp );
                        continue ;
                }
                if ( 0 > printf( "%s%s%s", tbuf3, in_sufx,
                                        ( tbufp != tbuf ? "\n" : "" ) ) )
                {
                        if ( ferror( stdout ) )
                        {
                                perror( "stdout" );
                                exit( 1 );
                        }
                        exit( 0 );
                }
        } while ( tbufp == tbuf ) ;
        exit( 0 );
}

The input option for time at the front of a line fits many files, and I have another tool mystat that is a wrapper for the stat() call that can stream file names in (if not on the command line) and by default outputs (file mod times in decimal unix time TAB file name), so you can sort -n to find the oldest or newest of any number of files.

1 Like

try this: note it uses ksh - if you use bash uncomment the red code; comment the blue code and change the shebang to /bin/bash

#!/bin/ksh
#
# assumptions - the LAST friday means:
#       Find a Friday (not today, even if today is Friday) 
#         in the past
# number of days friday is in the past

set -A weekdays_dec 2 3 4 5 6 7 1
# in bash this is           
# declare -a weekdays_dec=( 2 3 4 5 6 7 1 )

decrement=${weekdays_dec[`date +%w`]}
# 86400 secs per day * decrement
decrement=$(( $decrement * 86400 ))

# 86400 secs per day * 50
fifty_days=$(( 86400 * 50 ))

when=`perl -e 'print time;'`
when=$(( $when - $fifty_days )) 

when=$(( $when - $decrement ))
answer=`perl -e 'use POSIX qw(strftime);
              $mt = strftime "%Y%m%d", localtime($ARGV[0]);
              print $mt;' $when`
echo $answer
1 Like

Thanks Jim.
I need 50 days OLD/ BACK date from the last Friday.
I am trying to tweek the code. Let me know if you can.

Thanks for the help

You specifications are not clear to me.
Please give me sample input (some date) and then sample output.

Hi Jim
I need to get 50 days back date from last friday i.e 9/14/2012
The output should be 20120725

when=$(( $when + $fifty_days )) 
# change to
when=$(( $when - $fifty_days )) 

That is a minus sign.

Also changed the original post to reflect the change.

1 Like

At the high level, 50 days back from last Friday is 1) find the day of week. If it is Friday, add 7 to 50 and now it is in "days back" (or 1 to 6 as appropriate for the day of the week. Be careful about day of week zero or one based and week systems starting on different days!) Now calculate that date and format it.

If you want to write your own calendar code, the best way is to move your epoch form 1/1/1970 to 3/1/1968 or any othe day right after a leap year day. Now, every dats is a number of 4 year leaps plus 0-3 365 day years plus 0-11 months. You can subtract 365 day years and normal day count months ony. February is never subtracted, as it is at the top of every 4 year cycle, and its day count is just what remains. You only have to worry about the 100/400 year thing if you will calculate outside 1901-2099. Converting to Julian is tougher, especially with the short, rent riot month! Lunar calendars have their own rules, usually aligning to a solar-earth event like a solstice, and have to dispose of loose change somewhere. Those seconds they dump in the clock now and then as the earth slows down are only an issue to astronomers and others that deal in really precise time over long intervals. Leap second - Wikipedia, the free encyclopedia

One really messy aspect is determining DST in the past. I recall never finding a good way to deal with shift changes shifting when writing per-shift aggregate reports for nominally 24x7 wafer fab shifts. It did not occur to them to start the shifts the same EST time all year, so day shift might start at 7 or 8, for instance. Maybe that was against DST law? Even if you know where thr 9 and 7 hour shifts are, it is a mess when they are aggregated in weeks!

Usually, you find or write a tool or import a library. Google shell time date arithmetic and get: http://www.unix.com/answers-frequently-asked-questions/13785-yesterdays-date-date-arithmetic.html