"date" difference between FreeBSD & Linux

Hi there.
I used to use

lastdate=`date -v-14d %F`

on my old server with FreeBSD, and now got to get the same result(current date -14 or -X days) in script running at another server, with Linux, but there's no such option for "date".
How can i solve the prob(counting with absolute day number is not a variant because result is used when workin with dirs YYYY-MM-DD format)?
Thank You.

date -d "-14 days" +%F
1 Like

Oh, Lord... Tryed -d but didn't know how to use it. Thanks a lot!

-d in open source date, nice, except my date commands never have it! I took all the C date/time routines and wrote the last date time tool you will ever need:

$ tm2tm

Usage: tm2tm { -c | { - | <tm_str> } <in_fmt> } <delta> <out_fmt>
 First, gets dates and time(s):
  - when '-c' is used, from gettimeofday() (microsecond system clock)
  - when '-' is used, from the front of each line of stdin per <in_fmt>
  - else, from the front of <tm_str> per <in_fmt>
 The default year is 2000, and for other elements, minimum values.
 The <in_fmt> is either one of these or composed per strptime():
    %s       Absolute Unix time in integer seconds
    %s.%F    Unix time in integer and fractional 6 place seconds
    %s.%f    Unix time in integer and fractional 1-6 place seconds
 Modify each time by <delta>, an optionally sign, integer number,
  and optional suffix indicating the time unit (default seconds):
    Y or y   years           m        months
    D or d   days            H or h   hours
    M        minutes         S or s   seconds
 Format the time by <out_fmt>, which supports all of the strftime() values,
  plus the following:
    %s       Absolute Unix time in seconds
    %F       Fractional 6 place seconds
    %f       Fractional 1-6 place, zero suppressed seconds
 Write the converted time plus any following input data to standard out.
 For example: tm2tm '5/7/05 15:34' '%m/%d/%y %H:%M' -8h '%Y-%m-%d %r %Z'
  prints '2005-05-07 07:34:00 AM EDT'
$
1 Like

Nice, here are some enhancements to consider:

  • Ability to get first/last dow of current month or year (eg last Friday in 2010 could be "1/1/2011" -1Fri)
  • Next full/new moon from date (Easter sunday 2011 - 'Mar-21-2011' +1FullMoon +1Sun)

Some shells,e.g. ksh93, already have comprehensive builtin date arithmetic

$ printf "%(%Y-%m-%d %r %Z)T\n"  "5/7/05 15:34 -0800"
2005-05-07 07:34:00 PM EDT

$ printf "%(%Y-%m-%d)T\n" "final friday dec 2010"
2010-12-31
2 Likes

The moon is a whole new family of calculations, perhaps best left to the rabbi, imam or Pope!

Isn't day of week a strftime() value? You can check the first/last day of month/year and calculate from there, right? Of course, you need a function to give access to the internal calendar, to get last day of month for month x, but that is pretty easy to write, I just need to steal another % code or two, not used by strftime(), to intercept and pre-process. Thirty days has September, . . . , leap year every 4 except 100 except 400 and off you go. Too bad the UNIX time will overflow signed int in 2038.

$ tm2tm '5/7/37 15:34' '%m/%d/%y %H:%M' -8h '%Y-%m-%d %r %Z>
2037-05-07 07:34:00 AM EDT
$ tm2tm '5/7/38 15:34' '%m/%d/%y %H:%M' -8h '%Y-%m-%d %r %Z>

Error converting date-time '5/7/38 15:34' using format '%m/%d/%y %H:%M': Result too large
$ 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 );
}

$

---------- Post updated at 12:32 PM ---------- Previous update was at 12:23 PM ----------

Yes, the David Korn is still with us, and getting the newer ksh opens a lot of new doors. Maybe BASH will pick up more ksh-isms. I am still a ksh guy, by immersion and satisfaction, especially on systems with <() = systems with /dev/fd/# like Solaris.

Interestingly, there is such a class for PHP: Moon Phase

I guess you can get very close with UNIX time, a sine function and the right floating point factor, but if your calc puts Ramadan, Lent, Rosh Hashanah a month off because it varies by observation longitude and such and occasionally comes very close to falling either way . . . . :smiley:

---------- Post updated at 11:29 AM ---------- Previous update was at 11:17 AM ----------

Lunar calendar - Wikipedia, the free encyclopedia

Your utility assumes a 32-bit time type, and has lots of bugs on 64-bit platforms where the 2038 limit no longer applies; but is so complicated I'm not sure where to begin fixing it. I've fixed it to the point where it outputs random times instead of segfaulting..

I agree -- it's very frustrating to work with bash after enjoying the features of Kshell.

If anybody is interested in keeping up with Kshell or AST (a set of software tools from AT&T Labs Research) you can join one of the mailing lists listed on this page:

AT&T Research AST and UWIN mailing groups

I think this is a worthwhile mailing list to belong to.