Disclaimer

This library is provided as is, without any warantee to suitability or accuracy for any specific purpose. You use this library at your own risk. You modify this library at your own risk.
There is no support provided for this library.
You have the code to review, use and change. You decide on the suitability of this code for your environment.

Overview

This library provides a way for shell scripts to maniplulate dates. It does so by basing every date on the number of minutes since Jan 1 BASEYEAR, where BASEYEAR is a value defined in the script library; currently 2003.
The results of each function call are stored in the shell variable global_result_value, you have to extract the results from that yourself.

You are encouraged to add your own enhancements as required. To facilitate this the file datelib_test has been provided to run tests against the library functions. This should identify very quickly if any of your changes have broken the library.

To use the library in your own scripts, at the start of your scripts include
. PATH/datelib_ksh
replacing PATH with where you put the file of course. For example

#!/bin/bash
year_to_check="$1"
. ./datelib_ksh
is_leap_year ${year_to_check} 
if [ "${global_result_value}." = "1." ];
then
   echo " ${year_to_check} is a leap year"
else
   echo " ${year_to_check} is not a leap year"
fi
exit 0

Function reference

Quick reference

Date Routines:
datestamp_calculate YYYY [M]M|MMM|MMMM... DD HH:MM - returns minutes since baseyear for datetime
datestamp_time_now - returns minutes since baseyear to now
datestamp_to_date - returns the YYYY MM DD for the DATESTAMP
datestamp_offset_by_n_days [-]nn DATESTAMP - returns the datestamp passed offset by [-]nn days
date_n_days_ago nn - returns YYYY [M]M DD date n days back from current day
date_to_datestamp YYYY MM DD - returns the date as a datestamp
date_offset_by_n_days [-]nn YYYY nn|MMM|MMMM... - returns YYYY [M]M DD of the date passed offset by [-]nn
day_of_week [ YYYY nn|MMM|MMMM... DD ] - returns Monday...Sunday
get_minutes_in_year YYYY - returns the number of minutes in a year (used internally)
how_many_days_ago DATESTAMP - returns the number of days in the past a DATESTAMP is for (0 if in future)
is_leap_year_check YYYY - returns 1 if it is leap year, 0 if not
num_days_in YYYY [M]M|MMMM.. - returns the number of days in the year/month

File helpers:
minutes_since_file_modified filename - returns minutes since file was modified
days_since_file_modified filename - returns days since file was modified
CAUTION: you will probably have to change the file helper routines for your site, the date modified time fields in the ls command seem to change between OS releases (ie: FC6 and solaris8 were the same and it worked, FC8 inserted and extra field in ls output before the modified time which broke the parsing). Test script was last run on Fedora 32 without any issues.

Date Routines

datestamp_calculate

Function: create a library timestamp value for the date and time passed.
Syntax: datestamp_calculate YYYY [M]M|MMM|MMMM... DD HH:MM
Result: the variable global_result_value will contain the calculated library timestamp
Notes: to create a datestamp without providing a time see date_to_datestamp.
Example:
   . ./datelib_ksh
   datestamp_calculate 2004 01 28 10:50
   echo "Result is ${global_result_value}"

datestamp_time_now

Function: create a library timestamp value for the current time.
Syntax: datestamp_time_now
Result: the variable global_result_value will contain the calculated library timestamp
Example:
   . ./datelib_ksh
   datestamp_time_now
   echo "Result is ${global_result_value}"

datestamp_to_date

Function: provide the year, month and day of a library timestamp.
Syntax: datestamp_to_date DATESTAMP
Result: the variable global_result_value will contain YYYY MM DD of the datestamp
Example:
   . ./datelib_ksh
   datestamp_calculate 2004 01 28 10:50
   datestamp_value="${global_result_value}"
   echo "Datestamp ${datestamp_value}"
   # get the YYYY MM DD for a datestamp
   datestamp_to_date ${datestamp_value}
   echo "The YYYY MM DD for ${datestamp_value} is ${global_result_value}"

datestamp_offset_by_n_days

Function: adjust the timestamp passed +/- the number of days requested.
Syntax: datestamp_offset_by_n_days [-]nn DATESTAMP
Result: the variable global_result_value will contain the calculated library timestamp
Notes: to adjust a date rather than a timestamp see date_offset_by_n_days or date_n_days_ago.
Example:
   . ./datelib_ksh
   datestamp_calculate 2004 01 28 10:50
   datestamp_offset_by_n_days -3 ${global_result_value}
   # global_result_value now contains datestamp for 25 Jan 2004
   datestamp_offset_by_n_days 4 ${global_result_value}
   # global_result_value now contains datestamp for 29 Jan 2004

date_n_days_ago

Function: returns the YYYY MM DD of the date nn days ago. Only returns days in the past, providing a negative number will always result in 0 as a global_result_value.
Syntax: date_n_days_ago nn
Result: the variable global_result_value will contain the YYYY MM DD for the date nn days ago
Notes: also refer to date_offset_by_n_days.
Example:
   . ./datelib_ksh
   date_n_days_ago 4
   echo "The date four days ago was ${global_result_value}"

date_to_datestamp

Function: returns the library timestamp for a date.
Syntax: date_to_datestamp YYYY MM DD
Result: the variable global_result_value will contain the calculated library timestamp for the date passed.
Notes: if minutes are important to you also see datestamp_calculate.
Example:
   . ./datelib_ksh
   date_to_datestamp 2004 01 28
   echo "The library timestamp for 2004 01 28 is ${global_result_value}"

date_offset_by_n_days

Function: returns the date for the day +/- nn days from the date provided.
Syntax: date_offset_by_n_days [-]nn YYYY nn|MMM|MMMM... DD
Result: the variable global_result_value will contain the YYYY MM DD date for the date offset the requested number of days from the daye provided.
Notes: to adjust using a datastamp instead of a date see datestamp_offset_by_n_days.
Example:
   . ./datelib_ksh
   date_offset_by_n_days -3 2004 Jan 28
   echo "The library date three days before 2004 01 28 was ${global_result_value}"
   date_offset_by_n_days 3 2004 January 28
   echo "The library date three days after 2004 01 28 was ${global_result_value}"

day_of_week

Function: returns the day of the week for the date provided.
Syntax: day_of_week YYYY nn|MMM|MMMM... DD
Result: the variable global_result_value will contain a day name from Sunday through Saturday.
Example:
   . ./datelib_ksh
   day_of_week 2004 01 28
   echo "28 January 2004 was a ${global_result_value}"

get_minutes_in_year

Function: returns the number of minutes for the year provided.
Syntax: get_minutes_in_year YYYY
Result: the variable global_result_value will contain the number of minutes in the year requested.
Notes: This is used internally, it is documented here as you will probably need to use it if you are to include your own functions in the library.
Example:
   . ./datelib_ksh
   get_minutes_in_year 2004
   echo "There are ${global_result_value} minutes in year 2004"

how_many_days_ago

Function: returns the number of days in the past a library timestamp is for.
Syntax: how_many_days_ago DATESTAMP
Result: the variable global_result_value will contain the number of days in the past the datestamp was.
Notes: If a future date is passed the result will be 0.
Example:
   . ./datelib_ksh
   date_to_datestamp 2004 Jan 01
   how_many_days_ago ${global_result_value}
   echo "The 1st of January 2004 was ${global_result_value} days ago"

is_leap_year_check

Function: checks to see if the year passed was a leap year.
Syntax: is_leap_year_check YYYY
Result: the variable global_result_value will be 1 if the year was a leap year, 0 if not.
Example:
   . ./datelib_ksh
   is_leap_year_check 2004
   if [ "${global_result_value}." = "1." ];
   then 
      echo "2004 was a leap year"
   else
      echo "2004 was not a leap year"
   fi

num_days_in

Function: works out the number of days in the month.
Syntax: num_days_in YYYY [M]M|MMM|MMMM...
Result: the variable global_result_value will contain the number of days in the month.
Notes:: The year must be provided. We need this to determine if it is a leap year.
Example:
   . ./datelib_ksh
   num_days_in 2004 02
   echo "There are ${global_result_value} days in February 2004"
   num_days_in 2005 February
   echo "There are ${global_result_value} days in February 2005"

File helpers

minutes_since_file_modified

Function: works out the number of minutes since the file was last modified.
Syntax: minutes_since_file_modified filename
Result: the variable global_result_value will contain the number of minutes since the file was last modified.
Notes:: uses the 'ls -la' command to obtain the last modified file time. If the file was modified in a previous year (no minutes in the ls output, a year instead) the minutes offset will be calculated from 00:00 of the day the file was modified.
Example:
   . ./datelib_ksh
   minutes_since_file_modified /var/log/test
   echo "/var/log/test was modified ${global_result_value} minutes ago"

days_since_file_modified

Function: works out the number of days since the file was last modified.
Syntax: days_since_file_modified filename
Result: the variable global_result_value will contain the number of days since the file was last modified.
Notes:: uses the 'ls -la' command to obtain the last modified file time.
Example:
   . ./datelib_ksh
   days_since_file_modified /var/log/test
   echo "/var/log/test was modified ${global_result_value} days ago"

The datelib_test script

As you are encouraged to enhance this library with your own routines there needs to be a simple way of testing that you have not broken any of the shipped library functions when you have been making changes.

To facilitate this the script datelib_test has been provided to run basic sanity checks against the library. This should be run every time you change the library to ensure it stll functions correctly.

Syntax: ./datelib_test
Notes run this from the same directory the datelib_ksh file is in.

Sample output from a test run is below.

Date library checks.

This script will do fairly minimal checks against the date
library to confirm that all bits hang together properly.
This needs to be run after you make any changes to the library.

All tests in the script PASS OK when the script is run against
the supplied library.
If when you run it you get failed tests, then either fix or
backout the changes YOU or your sysadmins made to the library.

Leap year checks beginning
   OK: 2003 - check passed (0)
   OK: 2004 - check passed (1)
   OK: 2005 - check passed (0)
   OK: 2006 - check passed (0)
   OK: 2007 - check passed (0)
   OK: 2008 - check passed (1)
   OK: 2010 - check passed (0)
   OK: 2012 - check passed (1)
Passed.

Checking quantative value procedures
   Days in years...
   OK: 2004 - check passed (527040 minutes in 2004)
   OK: 2005 - check passed (525600 minutes in 2005)
   OK: 2006 - check passed (525600 minutes in 2006)
   OK: 2007 - check passed (525600 minutes in 2007)
   OK: 2008 - check passed (527040 minutes in 2008)
   OK: 2010 - check passed (525600 minutes in 2010)
   OK: 2012 - check passed (527040 minutes in 2012)
   Days in months...
   (numeric months)
   OK: - check passed, 31 days in 1 2004)
   OK: - check passed, 29 days in 2 2004)
   OK: - check passed, 31 days in 3 2004)
   OK: - check passed, 30 days in 4 2004)
   OK: - check passed, 31 days in 05 2004)
   OK: - check passed, 30 days in 06 2004)
   OK: - check passed, 31 days in 07 2004)
   OK: - check passed, 31 days in 08 2004)
   OK: - check passed, 30 days in 09 2004)
   OK: - check passed, 31 days in 10 2004)
   OK: - check passed, 30 days in 11 2004)
   OK: - check passed, 31 days in 12 2004)
   (short months, mixed case)
   OK: - check passed, 31 days in jan 2004)
   OK: - check passed, 29 days in 2 2004)
   OK: - check passed, 31 days in march 2004)
   OK: - check passed, 30 days in april 2004)
   OK: - check passed, 31 days in may 2004)
   OK: - check passed, 30 days in jun 2004)
   OK: - check passed, 31 days in jul 2004)
   OK: - check passed, 31 days in aug 2004)
   OK: - check passed, 30 days in sep 2004)
   OK: - check passed, 31 days in oct 2004)
   OK: - check passed, 30 days in nov 2004)
   OK: - check passed, 31 days in dec 2004)
   (long months, mixed case)
   OK: - check passed, 31 days in january 2004)
   OK: - check passed, 29 days in 2 2004)
   OK: - check passed, 31 days in march 2004)
   OK: - check passed, 30 days in april 2004)
   OK: - check passed, 31 days in may 2004)
   OK: - check passed, 30 days in june 2004)
   OK: - check passed, 31 days in july 2004)
   OK: - check passed, 31 days in august 2004)
   OK: - check passed, 30 days in september 2004)
   OK: - check passed, 31 days in october 2004)
   OK: - check passed, 30 days in november 2004)
   OK: - check passed, 31 days in december 2004)
   (a few leap year checks via procs tested here)
   OK: - check passed, 29 days in 2 2004)
   OK: - check passed, 28 days in 2 2005)
   OK: - check passed, 28 days in 2 2006)
   OK: - check passed, 28 days in 2 2007)
   OK: - check passed, 29 days in 2 2008)
   OK: - check passed, 28 days in 2 2009)
Passed.


Checking datestamp conversions
   (to and from a datestamp)
      (conversion to datestamp, then back to a date, even & odd days)
      2004 01 18 00:01 method 1 = 551521, method 2 = 551521
   OK - 551521 converts back into 2004 1 18
      2004 01 19 00:01 method 1 = 552961, method 2 = 552961
   OK - 552961 converts back into 2004 1 19
      2004 02 29 00:01 method 1 = 612001, method 2 = 612001
   OK - 612001 converts back into 2004 2 29
      2005 02 28 00:01 method 1 = 1137601, method 2 = 1137601
   OK - 1137601 converts back into 2005 2 28
      2010 02 28 00:01 method 1 = 3767041, method 2 = 3767041
   OK - 3767041 converts back into 2010 2 28
      2010 02 28 23:59 method 1 = 3768479, method 2 = 3767041
   OK - 3768479 converts back into 2010 2 28
      2004 02 28 23:59 method 1 = 611999, method 2 = 610561
   OK - 611999 converts back into 2004 2 28
Passed.

   (day sliding checks)
   datestamp_offset_by_n_days tests
   OK - got 607680 and expected 607680
   OK - got 609120 and expected 609120
   OK - got 1134720 and expected 1134720
   OK - got 613440 and expected 613440
   OK - got 1140480 and expected 1140480
   date_offset_by_n_days tests
   OK - the date three days FORWARD from 2004 2 29 was 2004 3 3
   OK - the date three days FORWARD from 2004 3 1 was 2004 3 4
   OK - the date three days BACKWARD from 2004 3 1 was 2004 2 27
   OK - the date three days FORWARD from 2005 3 1 was 2005 3 4
   OK - the date three days BACKWARD from 2005 3 1 was 2005 2 26
   OK - the date three days FORWARD from 2005 1 1 was 2005 1 4
   OK - the date three days FORWARD from 2008 1 2 was 2008 1 5
   date_n_days_ago test
   OK - the date three days ago was  2004 1 30 [MANUALLY CHECK ME]
Passed.

Day name calculations...
   OK - Expected Wednesday for 2004 01 28, got Wednesday
   OK - Expected Thursday for 2004 01 29, got Thursday
   OK - Expected Friday for 2004 01 30, got Friday
   OK - Expected Friday for 2004 01 02, got Friday
   OK - Expected Sunday for 2004 02 15, got Sunday
   OK - Expected Monday for 2003 11 17, got Monday
   OK - Expected Tuesday for 2005 02 08, got Tuesday
Passed.


File timestamp date routine checks
   (testing days in the past, using 2003 01 01)
-rw-rw-r--    1 mark     mark            0 Jan  1  2003 zzzzz.delme
   WARNING: Response mismatch, expected 571680, got 572938
   If checking on a previous years file there is no hh:mm to use so it will be
   hh:mm minutes out from the expected time.
   If the file being checked is for a previous year, and the next check passes
   then there is no problem.
   OK - got expected result (397)
   (testing current time)
-rw-rw-r--    1 mark     mark            0 Feb  2 20:58 zzzzz.delme
   OK - expected 0, got 0
   OK - expected 0, got 0

-- End of tests --