Use the date command with a strftime format specification.
- # Setting environment variables can be helpful in scripts:
- $ STRICT_ISO_8601='%Y-%m-%dT%H:%M:%S%z' # http://greenwichmeantime.com/info/iso.htm
- $ ISO_8601='%Y-%m-%d %H:%M:%S %Z' # Almost ISO-8601, but more human-readable
- $ ISO_8601_1='%Y-%m-%d %T %Z' # %T is the same as %H:%M:%S
- $ DATEFILE='%Y%m%d%H%M%S' # Suitable for use in a file name
- [maxwell@MaxwellDBA Day0801]$ STRICT_ISO_8601='%Y-%m-%dT%H:%M:%S%z'
- [maxwell@MaxwellDBA Day0801]$ ISO_8601='%Y-%m-%d %H:%M:%S %Z'
- [maxwell@MaxwellDBA Day0801]$ ISO_8601_01='%Y-%m-%d %T %Z'
- [maxwell@MaxwellDBA Day0801]$ DATEFILE='%Y%m%d%H%M%S'
- [maxwell@MaxwellDBA Day0801]$ date "+$IS0_8601"
- 2022-08-01 07:50:35 CST
- [maxwell@MaxwellDBA Day0801]$ gawk "BEGIN {print strftime(\"$ISO_8601\")}"
- 2022-08-01 07:50:49 CST
- [maxwell@MaxwellDBA Day0801]$ # Same as previous $ISO_8601
- [maxwell@MaxwellDBA Day0801]$ date '+%Y-%m-%d %H:%M:%S %Z'
- 2022-08-01 07:52:08 CST
- [maxwell@MaxwellDBA Day0801]$ date "+Program starting at: $ISO_8601"
- Program starting at: 2022-08-01 07:52:54 CST
- [maxwell@MaxwellDBA Day0801]$ printf "%b" "Program starting at: $(date '+$ISO_8601')\n"
- Program starting at: $ISO_8601
- [maxwell@MaxwellDBA Day0801]$ echo "I can rename a file like this: mv file.log file_$(date +$DATEFILE).log"
- I can rename a file like this: mv file.log file_20220801075507.log
- [maxwell@MaxwellDBA Day0801]$
Using the GNU date command,assign the most likely date to a variable, then allow the user to change it.
- [maxwell@MaxwellDBA Day0801]$ cat default_date.sh
- #!/usr/bin/env bash
- # cookbook filename: default_date.sh
- #Use Noon time to prevent a script running around midnight and a clock a few seconds off from causing off by one day errors.
- START_DATE=$(date -d 'last week Monday 12:00:00' '+%Y-%m-%d')
- while [ 1 ]; do
- printf "%b" "The starting date is $START_DATE,is that correct? (Y/new date) "
- read answer
-
- # Anything other than ENTER,"Y" or "y" is validated as a new date could use "[Yy]*" to allow the user to spell out "yes"...
- # validate the new date format as: CCYY-MM-DD
- case "$answer" in
- [Yy]) break
- ;;
- [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])
- printf "%b" "Overriding $START_DATE with $answer\n"
- START_DATE="$answer"
- ;;
-
- *) printf "%b" "Invalid date, please try again...\n"
- ;;
- esac
- done
-
- END_DATE=$(date -d "$DATE_DATE +7 days" '+%Y-%m-%d')
-
- echo "START_DATE: $START_DATE"
- echo "END_DATE: $END_DATE"
- [maxwell@MaxwellDBA Day0801]$
The -d option allow you to specify a specific date instead of using now,but not all date commands support it.
- [maxwell@MaxwellDBA Day0801]$ date '+%Y-%m-%d %H:%M:%S %Z'
- 2022-08-01 09:34:58 CST
- [maxwell@MaxwellDBA Day0801]$ date -d 'today' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-01 09:35:42 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'yesterday' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-31 09:35:56 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'tomorrow' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-02 09:36:08 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'Monday' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-01 00:00:00 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'this Monday' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-01 00:00:00 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'last Monday' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-25 00:00:00 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'next Monday' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-08 00:00:00 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'last week' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-25 09:54:57 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d 'next week' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-08 09:55:11 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '2 weeks' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-15 09:55:30 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '-2 weeks' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-18 09:55:39 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '2 weeks ago' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-18 09:55:54 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '+4 days' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-05 09:56:27 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '-6 days' '+%Y-%m-%d %H:%M:%S %z'
- 2022-07-26 09:56:40 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '2022-08-01 +12 days' '+%Y-%m-%d %H:%M:%S %z'
- 2022-08-13 00:00:00 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d '3 months 1 day' '+%Y-%m-%d %H:%M:%S %z'
- 2022-11-02 09:57:59 +0800
- [maxwell@MaxwellDBA Day0801]$ date '+%a %Y-%m-%d'
- Mon 2022-08-01
- [maxwell@MaxwellDBA Day0801]$ date -d 'today''+%a %Y-%m-%d'
- date: invalid date ‘today+%a %Y-%m-%d’
- [maxwell@MaxwellDBA Day0801]$ date -d 'today' '+%a %Y-%m-%d'
- Mon 2022-08-01
- [maxwell@MaxwellDBA Day0801]$ date -d 'Saturday' '+%a %Y-%m-%d'
- Sat 2022-08-06
- [maxwell@MaxwellDBA Day0801]$ date -d 'last Saturday' '+%a %Y-%m-%d'
- Sat 2022-07-30
- [maxwell@MaxwellDBA Day0801]$ date -d 'this Saturday' '+%a %Y-%m-%d'
- Sat 2022-08-06
- [maxwell@MaxwellDBA Day0801]$ date -d 'next Saturday' '+%a %Y-%m-%d'
- Sat 2022-08-06
- [maxwell@MaxwellDBA Day0801]$ date -d 'this week Friday' '+%a %Y-%m-%d'
- Fri 2022-08-05
- [maxwell@MaxwellDBA Day0801]$
The article presents five shell functions:
- pn_month
- Previous and next x months relative to the given month
- end_month
- End of month of the given month
- pn_day
- Previous and next x days of the given day
- cur_weekday
- Day of week for the given day
- pn_weekday
- Previous and next x day of weeks relative to the given day
- And these were added not long before this book went to press:
- pn_day_nr
- (Non-recursive) Previous and next x days of the given day
- days_between
- Number of days between two dates
Use the GNU date command with the nonstandard -d option and a standard %s format:
- [maxwell@MaxwellDBA Day0801]$ # "Now" is easy
- [maxwell@MaxwellDBA Day0801]$ date '+%s'
- 1659319857
- [maxwell@MaxwellDBA Day0801]$ # Some other time needs the non-standard -d
- [maxwell@MaxwellDBA Day0801]$ date -d '2022-08-01 12:00:00 +0000' '+%s'
- 1659355200
- [maxwell@MaxwellDBA Day0801]$ perl -e 'print time, qq(\n);'
- 1659319953
- [maxwell@MaxwellDBA Day0801]$ # Same as above
- [maxwell@MaxwellDBA Day0801]$ perl -e 'use Time::Local; print timelocal(localtime()). qq(\n);'
- 1659320017
- [maxwell@MaxwellDBA Day0801]$ perl -e 'use POSIX qw(strftime); print strftime("%s",localtime()). qq(\n);'
- 1659320091
- [maxwell@MaxwellDBA Day0801]$ # The given time is in local time
- [maxwell@MaxwellDBA Day0801]$ perl -e 'use Time::Local; print timelocal("49","59","06","05","10","105") . qq(\n);'
- 1131145189
- [maxwell@MaxwellDBA Day0801]$ # The given time is in UTC time
- [maxwell@MaxwellDBA Day0801]$ perl -e 'use Time::Local; print timegm("49","59","06","05","10","105") . qq(\n);'
- 1131173989
- [maxwell@MaxwellDBA Day0801]$
1.5 Converting Epoch Seconds to Dates and Times
- [maxwell@MaxwellDBA Day0801]$ EPOCH='1131173989'
- [maxwell@MaxwellDBA Day0801]$ date -d '2022-08-01 UTC $EPOCH seconds' '+%Y-%m-%d %T %z'
- date: invalid date ‘2022-08-01 UTC $EPOCH seconds’
- [maxwell@MaxwellDBA Day0801]$ date -d '2022-08-01 UTC $EPOCH seconds' +'%Y-%m-%d %T %z'
- date: invalid date ‘2022-08-01 UTC $EPOCH seconds’
- [maxwell@MaxwellDBA Day0801]$ date -d '2022-08-01 UTC $EPOCH seconds' + '%Y-%m-%d %T %z'
- date: extra operand ‘%Y-%m-%d %T %z’
- Try 'date --help' for more information.
- [maxwell@MaxwellDBA Day0801]$ date -d "1970-01-01 UTC $EPOCH seconds" +"%Y-%m-%d %T %z"
- 2005-11-05 14:59:49 +0800
- [maxwell@MaxwellDBA Day0801]$ date -d "2022-08-01 UTC $EPOCH seconds" +"%Y-%m-%d %T %z"
- 2058-06-05 14:59:49 +0800
- [maxwell@MaxwellDBA Day0801]$ date --utc --date "2022-08-01 $EPOCH seconds" +"%Y-%m-%d %T %z"
- 2058-06-05 06:59:49 +0000
- [maxwell@MaxwellDBA Day0801]$ perl -e "print scalar(gmtime($EPOCH)), qq(\n);" #UTC
- Sat Nov 5 06:59:49 2005
- [maxwell@MaxwellDBA Day0801]$ perl -e "print scalar(localtime($EPOCH)), qq(\n);" #Your local time
- Sat Nov 5 14:59:49 2005
- [maxwell@MaxwellDBA Day0801]$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d %H:%M:%S',
- > localtime($EPOCH)), qq(\n);"
- 2005-11-05 14:59:49
- [maxwell@MaxwellDBA Day0801]$
- [maxwell@MaxwellDBA Day0801]$ # Yesterday at this same time (note subtraction)
- [maxwell@MaxwellDBA Day0801]$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d', localtime(time - 86400)), qq(\n);"
- 2022-07-31
- [maxwell@MaxwellDBA Day0801]$ # Tomorrow at this same time (note addition)
- [maxwell@MaxwellDBA Day0801]$ perl -e "use POSIX qw(strftime); print strftime('%Y-%m-%d', localtime(time + 86400)),qq(\n);"
- 2022-08-02
- [maxwell@MaxwellDBA Day0801]$
- [maxwell@MaxwellDBA Day0801]$ CORRECTION='172800' # 2 days worth of seconds
- [maxwell@MaxwellDBA Day0801]$ # Code to extract the date portion from the data into $bad_date go here
- [maxwell@MaxwellDBA Day0801]$ # Suppose it's this:
- [maxwell@MaxwellDBA Day0801]$ bad_date='Jan 2 05:13:05' # syslog formated date
- [maxwell@MaxwellDBA Day0801]$ # Convert to Epoch using GNU date
- [maxwell@MaxwellDBA Day0801]$ bad_epoch=$(date -d "$bad_date" '+%s')
- [maxwell@MaxwellDBA Day0801]$ # Apply correction
- [maxwell@MaxwellDBA Day0801]$ good_epoch=$(( bad_epoch + $CORRECTION))
- [maxwell@MaxwellDBA Day0801]$ # Make corrected date human-readable
- [maxwell@MaxwellDBA Day0801]$ good_date=$(date -d "2022-08-01 UTC $good_epoch seconds") # GNU Date
- [maxwell@MaxwellDBA Day0801]$ good_date_iso=$(date -d "1970-01-01 UTC $good_epoch seconds" +'%Y-%m-%d %T') # GNU
- [maxwell@MaxwellDBA Day0801]$ echo "bad_date: $bad_date"
- bad_date: Jan 2 05:13:05
- [maxwell@MaxwellDBA Day0801]$ echo "bad_epoch: $bad_epoch"
- bad_epoch: 1641071585
- [maxwell@MaxwellDBA Day0801]$ echo "Correction: +$CORRECTION"
- Correction: +172800
- [maxwell@MaxwellDBA Day0801]$ echo "good_epoch: +$good_epoch"
- good_epoch: +1641244385
- [maxwell@MaxwellDBA Day0801]$ echo "good_date: +$good_date"
- good_date: +Sat Aug 4 05:13:05 CST 2074
- [maxwell@MaxwellDBA Day0801]$ echo "good_date_iso: $good_date_iso"
- good_date_iso: 2022-01-04 05:13:05
- [maxwell@MaxwellDBA Day0801]$