Performing date and time operations in a shell script is a fairly common task when automating backup processes or generating scheduled reports. Unfortunately, dealing with date and time operations in shell or trying to format a date is never straightforward as the Linux date and macOS date command line behavior might differ slightly.
This post provides examples on how to do date operations and format dates on Linux and macOS with the date
and awk
command lines and with the printf
bash shell command builtin.
👉 All the Linux options presented in this post are fully compatible with all Linux distributions deployed on Windows 10 with WSL. Read more about Linux on Windows with my post Running Bash Script With Ubuntu On Windows 10 Using WSL.
Introduction to Date and Time
The complexity of dealing with date and time goes beyond the tooling or programming problem. Very often, consideration will need to be taken regarding timezone, daylight saving, leap year, leap second, standard format, and even sometimes the type of calendar.
What are the different calendar types?
Calendars are a way to organize days for various purposes by giving names to given periods like days
, weeks
, months
, and years
. A date
is the representation of a single day in a calendar. There is a lot of calendar systems in use still to date some are based on the motion of the moon (Lunar calendars) or perceived seasons (Solar calendars).
The Gregorian calendar is the most widely used calendar system today and is often considered the international standard for civil use. It is a solar calendar with 12 months of 28 to 31 days each and based on 365 days a year, except for leap years, which add an extra day (a leap day) every 4 years in February.
The following post assumes the use of the Gregorian calendar unless specified otherwise.
What are UTC and Timezone?
Universal Coordinated Time (UTC), also known as Coordinated Universal Time, is the co-ordination of time and frequency around the world which began on January 1st, 1960. It is the basis of current timekeeping and is the baseline of all local times. The timezone offset for UTC is 0 and would be indicated with the letter Z
. UTC is often interchanged with the Greenwich Mean Time (GMT) though this is not correct as GMT is a timezone, used in some European and African countries, while UTC is a time standard, therefore UTC is never used as a local time.
With UTC come the time zones which are regions of the globes that observe a standard time for the day to day purposes. A time zone relates to local time and is offset from UTC. The time zone offset to UTC is not always represented by whole hours, for example, the Indian Standard Time (IST
) is UTC+5:30
. Timezones may be identified with a time zone identifier
like America/Los_Angeles
in the
IANA Time Zone Database (also called tzdata, tz, or zoneinfo). Note that the time zone database from IANA contains critical historical information which is necessary when dealing with the local date and time representation at a given time.
Some local time may switch part of the year to a time zone that includes a notion of daylight saving time (DST
).
What is Unix Time?
The Unix time is a point in time that describes the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), excluding leap seconds. It is part of the POSIX specification. Other frequent names for Unix time are Epoch time, POSIX time, seconds since the Epoch, or UNIX Epoch time. Every day in Unix time assumes an 86,400 seconds day. It is not a true representation of UTC.
👉 Read more about leap seconds and go back in time with our post on the 2012 leap second bug that took down half of the internet: Getting Ready For The Leap Second.
Unix time starts at zero (0
) which is 00:00:00 UTC on 1 January 1970
.
⚠️ Some systems still store this value in as a signed 32-bit integer which may cause large bugs on January 19, 2038 once the upper limit of the integer is reached. This is known as the Y2038 bug (Year 2038).
What is the ISO 8601 standard?
The ISO 8601 is the International Standard for the representation of dates and times to ensure consistent representation across systems in a gregorian calendar. It is a field-based format where dates and times are identified (2020-05-09T03:44:25Z) in contrast to the Unix Time (1547092066).
The standard uses the specifiers from the below table to represent a date and time. Note that the standard calls for a minimum of 4 digits year to avoid a repeat of the Y2K bug (Year 2000).
specifier/token | meaning |
---|---|
YYYY | four-digit year |
MM | two-digit month (01=January, etc.) |
ww | week number from 1 to 53 |
D | week day number from 1 to 7 and beginning with Monday |
DD | two-digit day of month (01 through 31) |
hh | two digits of hour (00 through 23) (am/pm NOT allowed) |
mm | two digits of minute (00 through 59) |
ss | two digits of second (00 through 59) |
s | one or more digits representing a decimal fraction of a second |
Z or +hh:mm or -hh:mm | time zone designator |
/ | used to express a time interval between two time points |
Examples:
2020-05-09T13:49:54+00:00
2020-05-09T13:49:54Z
Using Calendars from the shell command line
Julian and Gregorian calendars with cal and ncal
The command line tools cal
and ncal
on linux and macOS provide a convenient way to display Julian or Gregorian calendar information from a shell. The main difference between the two is with the default calendar view as cal
will show each day of the week as a column while the ncal
command will show, by default, the day of the week on different rows (vertical format or ‘sideways’). That said, ncal
with the option -C
can also display the day of the week in column as cal
does, and cal
itself with the -N
option can show the vertical view.
The
cal
utility displays a simple calendar in a traditional format andncal
offers an alternative layout, more options, and the date of Easter.
Both utility will highlight the current date.
[me@linux ~]$ cal
May 2020
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
[me@linux ~]$ ncal
May 2020
Mo 4 11 18 25
Tu 5 12 19 26
We 6 13 20 27
Th 7 14 21 28
Fr 1 8 15 22 29
Sa 2 9 16 23 30
Su 3 10 17 24 31
[me@linux ~]$ cal 2020
2020
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 1 1 2 3 4 5 6 7
5 6 7 8 9 10 11 2 3 4 5 6 7 8 8 9 10 11 12 13 14
12 13 14 15 16 17 18 9 10 11 12 13 14 15 15 16 17 18 19 20 21
19 20 21 22 23 24 25 16 17 18 19 20 21 22 22 23 24 25 26 27 28
26 27 28 29 30 31 23 24 25 26 27 28 29 29 30 31
...
To get the calendar view of a specific year and month with cal
(or ncal
) you can use the -d
option followed by the year and month.
[me@linux ~]$ cal -d 1991-11
November 1991
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
To display the calendar using Julian days (numbered days from January 1 to December 31) with cal
and ncal
you can use the -j
option, for example, you can see below that 2020 has 366 days and is a leap year and the last day of the year will be a Thursday.
[me@linux ~]$ cal -j -m 12
December 2020
Su Mo Tu We Th Fr Sa
336 337 338 339 340
341 342 343 344 345 346 347
348 349 350 351 352 353 354
355 356 357 358 359 360 361
362 363 364 365 366
Now, to be honest, besides getting a quick calendar view from the command line, I have never found those two utilities being used reasonably in any automation or production systems. This is more for fun or to be informative than anything else.
Holidays and Events with the calendar command line on Linux
The Linux calendar
command line is defined as a reminder service that can send notifications and check a given directory for specified calendars definition to displays lines that will begin with a given date. This can be convenient to list a country’s frequent holidays or create your customized list of recurring events. The tool is available on Linux and will require the cpp
binary to compile the calendar files.
[me@linux ~]$ calendar -f /usr/share/calendar/calendar.usholiday -l 30 -B 30
Apr 15 Income Tax Day, USA.
Apr 28* Arbor Day, USA (varies from state to state)
May 10* Mother's Day (2nd Sunday of May)
May 16* Armed Forces in USA Day (3rd Saturday of May)
May 25* Memorial Day in USA (Last Monday of May)
Display and Format dates with the shell date command line
The most widely used shell command line utility to manipulate a date in Linux and Unix/macOS is certainly to use the shell date
command. Remember that macOS is based on Unix and will come with the Unix version of the date
shell command. Though, there is some important catch to be aware as the implementation between Linux and Unix diverges greatly.
The date
shell command uses the date [options] +FORMAT
where the format is a serie of format specifiers used to define the output format of the date and time. The options and format specifiers may vary between platforms. The date format example below will work across Unix/macOS and Linux platforms.
[me@linux ~]$ date '+Today is %A, %B %d, %Y.'
Today is Saturday, May 09, 2020.
How to ensure consistent usage between Linux and macOS?
One way to guarantee consistent behavior between Linux and macOS to formate a date is to make sure to always use the GNU date version of the date command line utility. It comes pre-installed by default on most Linux distributions, if not you will need to install the coreutils package. On Ubuntu/Debian you can run apt install coreutils
.
The GNU coreutils can be installed on macOS using homebrew brew install coreutils
. The GNU date command line will then be available as gdate
on macOS.
By using the
bash type command, you can define a small wrapper
bash function to test whether GNU date
is installed or fallback to the default version. This is a convenient wrapper to add in your .bashrc
on Mac.
[me@mac ~]$ type -p date
/bin/date
[me@mac ~]$ date() { if type -t gdate &>/dev/null; then gdate "$@"; else date "$@"; fi }
[me@mac ~]$ type -p date
[me@mac ~]$ type date
date is a function
date ()
{
if type -p gdate > /dev/null; then
gdate "$@";
else
date "$@";
fi
}
What are the differences between Linux and Unix/macOS?
It is important to understand that the POSIX standard (POSIX.2) only specifies the -u
option and the operand +format
of the shell date utility. You can find the full specification in
Posix 2 IEEE Std 1003.2. This means that any other options or operands in the date
shell utility are systems specific implementation and may not be portable across platforms or environments.
The Unix and macOS date
shell utility is compatible with the POSIX.2 standard and the -d
, -f
, -j
, -n
, -R
, -r
, -t
, and -v
options are all extensions to the standard.
The Linux date
shell utility is the GNU date shell version which is also compatible with the POSIX.2 standard and also sets a large number of options that are all extensions to the standard. The Linux version of date
is sometime called gdate
when installed on different platforms.
⚠️ The non-standard options are not guaranteed to have the same behavior between Linux (GNU version) and Unix/macOS. A typical example would be the
-d
option which displays the time as described by a string on the Linux GNU version while it is used to set the kernel’s value for daylight saving time on macOS.
The option -u
will set the date in UTC instead of using the local time zone. Since it’s part of the POSIX.2 specification both date
version from Linux and Unix/macOS would display the same output for the command date -u
.
Format a date on Linux using the GNU date command line
Before bash version 5, it was common to use the Linux date command to get the current Unix time, example date '+%s'
. This should now be avoided since you can directly use the $EPOCHSECONDS
shell variable. See
What’s New in GNU Bash 5?.
[me@linux ~]$ date '+%s' && echo $EPOCHSECONDS
1589053840
1589053840
Another variant has been to use date
to get the real-time in microseconds, though GNU date will return nanoseconds while Bash provides $EPOCHREALTIME
which is in microseconds directly. So, depending on the case you may have to do a simple
division in bash to get the correct value. The example below can be easily ported to get milliseconds instead. See the man date
(or man gdate
) pages for the full list of formatting options.
[me@linux ~]$ echo $((`date '+%s%N'`/1000)) && echo $EPOCHREALTIME
1589053840916766
1589053840.918266
# Extra tips to get the same microseconds formatting
[me@linux ~]$ m=$((`date '+%s%N'`/1000)) && echo ${m:0:${#m}-6}.${m:${#m}-6} && echo $EPOCHREALTIME
1589053840.918266
1589053840.918266
# Example to get time with milliseconds and separated with a dot
[me@linux ~]$ m=$((`date '+%s%N'`/1000000)) && ${m:0:${#m}-3}.${m:${#m}-3}
1589054941.851
Another widely used option of GNU date is the -d
option which makes handling dates extremely easy as you can use human-readable words to define a date. The option allows you to easily do operations on dates which is a big strength of the GNU date utility.
[me@linux ~]$ date -d 'last year'
Thu May 9 13:01:43 PDT 2019
[me@linux ~]$ date -d '90 days ago'
Sun Feb 9 12:03:34 PST 2020
[me@linux ~]$ date -d 'Feb 12 + 3 day' -u
Sat Feb 15 00:00:00 UTC 2020
[me@linux ~]$ date -d 'Feb 12 + 13 minutes' -u
Wed Feb 12 00:13:00 UTC 2020
See more examples in the FAQ on How to Format a Date in Bash.
Format a date on Unix/macOS using the BSD date command line
The macOS date
shell command is quite more limited than the GNU version. Though, you can still use it for basic formatting. See the man date
pages for the full list of formatting options. You can have the same behavior as GNU date
-d
option by using the -j
(don’t try to set date, display only) and -v
(adjust date) options.
[me@macos ~]$ date '+%Y/%m/%d %H:%M:%S'
2020/05/09 13:20:2
[me@macos ~]$ date -j -v +3d -f "%b %d" "Feb 10"
Thu Feb 13 12:47:10 PST 2020
Display and Format dates with the GNU awk command line
GNU awk is often used to parse and process logs in an efficient way, luckily it can also be powerful when it comes to manipulating dates. Again, most of those features are extensions and are not specified by the POSIX
standard.
mktime | Turn a datespec (YYYY MM DD HH MM SS) into a timestamp |
strftime | Format a specified time to the given format as defined by strftime() |
systime | Return the Unix Time stamp (Epoch) |
[me@macos ~]$ gawk 'BEGIN { print "Seconds since Epoch: " mktime("2020 05 09 14 47 27") }'
Seconds since Epoch: 1589060689
[me@macos ~]$ gawk 'BEGIN { print "Seconds since Epoch: " systime() }'
Seconds since Epoch: 1589060689
[me@macos ~]$ gawk 'BEGIN { print strftime("Today is %A, %B %d, %Y.", systime()) }'
Today is Saturday, May 09, 2020.
The example below from the gawk
man pages show an example of awk reproducing the date
command behavior and formatting.
#! /bin/sh
#
# date --- approximate the POSIX 'date' command
case $1 in
-u) TZ=UTC0 # use UTC
export TZ
shift ;;
esac
gawk 'BEGIN {
format = PROCINFO["strftime"]
exitval = 0
if (ARGC > 2)
exitval = 1
else if (ARGC == 2) {
format = ARGV[1]
if (format ~ /^\+/)
format = substr(format, 2) # remove leading +
}
print strftime(format)
exit exitval
}' "$@"
Display and Format dates by using the printf Bash builtin
The Bash printf
builtin command support some date formats by using %(datefmt)T
where datefmt is a format string passed to strftime
and the corresponding argument is the Epoch time.
[me@linux ~]$ TZ=UTC printf "%(%F)T\n" 1589053840
2020-05-09
[me@linux ~]$ TZ=UTC printf "This date occurred in week %(%W)T of the year %(%Y)T\n" $EPOCHSECONDS
This date occurred in week 18 of the year 2020
Using printf
makes the formatting to microseconds even simpler than when using the date
command.
[me@linux ~]$ printf "%.3f\n" $EPOCHREALTIME
1589054941.851
[me@linux ~]$ printf "%.3f\n" $EPOCHREALTIME | tr -d .
1589054941851
Detailed Examples & FAQ
How to set the date in shell?
The date
command line allows you to also set your operating system date and time on Linux and Unix systems. Though, on
- To set the date in shell using the
date
command line on Unix and macOS, you do not need any options. By default the datetime format needs to be[[[mm]dd]HH]MM[[cc]yy][.ss]
. Example:date 021211072020.32
. You can also use the-f
options to provide a specific format instead. Example:date -f "%b %d" "Feb 12" +%F
. - To set the date in shell using the GNU version of the
date
command line on Linux, use the-s
or--set
option. Example:date -s "<DATETIME>"
.
⚠️ You should prefer to setup your system to use the
ntp
protocol to synchronize your clocks. Manually setting the date and time on your system is not reliable as time delays will be introduced fairly quickly. On Linux Ubuntu 20.04, you can use the commandchronyd -q
to force a one-time sync andchronyd -Q
to only check the date and time for differences.
How to solve “date: settimeofday (timeval): Operation not permitted”?
If you are getting the error date: settimeofday (timeval): Operation not permitted
, you are probably trying to set the date on your system without administrator privileges. Run the same command using sudo
, example sudo date ...
.
How to solve “date: illegal time format”?
If you are getting the error date: illegal time format
, you are probably not following the correct format for your linux, unix or mac date
command. Double-check that your syntax is correct and that you are not missing options like -j
when using -f
on mac.
How to format a date in Bash?
The following examples use the shell date
command line. The date
command uses case-sensitive format specifiers, so the uppercase or lowercase letters in format would have different results. In the below examples, using %M
instead of %m
would mean minutes instead of month.
Bash Date format MM-DD-YYYY
To format date in MM-DD-YYYY format, use the command date +%m-%d-%Y
or printf "%(%m-%d-%Y)T\n" $EPOCHSECONDS
.
Bash Date format DD-MM-YYYY
To format date in DD-MM-YYYY format, use the command date +%d-%m-%Y
or printf "%(%d-%m-%Y)T\n" $EPOCHSECONDS
.
Bash Date format YYYY-MM-DD
To format date in YYYY-MM-DD format, use the command date +%F
or printf "%(%F)T\n" $EPOCHSECONDS
. The %F
option is an alias for %Y-%m-%d
.
This format is the ISO 8601 format.
Bash date format options
Below is a list of common date format options with examples output. It works with the Linux date command line and the mac/Unix date command line.
Date Format Option | Meaning | Example Output |
---|---|---|
date +%c | locale’s date time | Sat May 9 11:49:47 2020 |
date +%x | locale’s date | 05/09/20 |
date +%X | locale’s time | 11:49:47 |
date +%A | locale’s full weekday name | Saturday |
date +%B | locale’s full month name | May |
date +%m-%d-%Y | MM-DD-YYYY date format | 05-09-2020 |
date +%D | MM/DD/YY date format | 05/09/20 |
date +%F | YYYY-MM-DD date format | 2020-05-09 |
date +%T | HH:MM:SS time format | 11:44:15 |
date +%u | Day of Week | 6 |
date +%U | Week of Year with Sunday as first day of week | 18 |
date +%V | ISO Week of Year with Monday as first day of week | 19 |
date +%j | Day of Year | 130 |
date +%Z | Timezone | PDT |
date +%m | Month of year (MM) | 05 |
date +%d | Day of Month (DD) | 09 |
date +%Y | Year (YY) | 2020 |
date +%H | Hour (HH) | 11 |
date +%H | Hour (HH) in 24-hour clock format | 11 |
date +%I | Hour in 12-hour clock format | 11 |
date +%p | locale’s equivalent of AM or PM | AM |
date +%P | same as %p but in lower case | am |
You can get the full list of supported date format specifiers using the man date
or man gdate
commands.
How to add a day to a date in shell?
To get the date in bash shell and add a date, you can use the GNU date
command as date -d 'Feb 12 +1 day' +%F
which will output 2020-02-13
. See the above section on GNU date for more examples on the -d
option.
On a mac with the Unix date
command, you would need to use the -v
option to adjust the date and -j
to make sure the utility does not try to set the date. Example: date -j -v +1d -f "%b %d" "Feb 12" +%F
.
How to get yesterday’s date in shell?
To get yesterday’s date in bash shell you can use the Linux GNU date
version with date -d yesterday
or the Unix/macOS date
version using date -j -v -1d
.
How to do date comparison in bash?
To compare two dates in bash, you can use the unix timestamp value of both date using the date
command line or the printf
method and a
bash if statement with a
bash arithmetic expansion, or by using a
lexicographical comparison of the two dates string by using the double square bracket conditional construct [[..]]
.
# Example: comparing Unix Timestamp with an arithmetic expansion using ((...))
[me@linux ~]$ firstDate=$(date -d 'Feb 12 UTC' +%s)
[me@linux ~]$ secondDate=$(date -d 'Feb 13 UTC' +%s)
[me@linux ~]$ if (($secondDate > $firstDate)); then echo "Second Date is more recent than First Date"; fi
Second Date is more recent than First Date
# Example: comparing Date Strings by doing a lexical comparion using [[...]]
[me@linux ~]$ firstDate=$(date -d 'Feb 12 UTC' +"%F %T")
[me@linux ~]$ secondDate=$(date -d 'Feb 13 UTC' +"%F %T")
[me@linux ~]$ if [[ $secondDate > $firstDate ]]; then echo "Second Date is more recent than First Date"; fi
Second Date is more recent than First Date
How to sort a list of dates in descending order?
You can easily sort an array of dates using date comparison from the previous example with a bubble sort algorithm and the bash loops constructs. See the detailed example in How to sort the elements of an Array in a shell script?
How to generate a sequence of dates?
This example use a
bash for loop and the GNU date
command to do an addition on a date while using a
brace expansion to generate a sequence of numbers. The result is then assigned to a
bash array.
[me@linux ~]$ start_date="2020-09-01"
[me@linux ~]$ date_seq=($(for i in {1..7}; do echo `date +"%Y/%m/%d" -d "${start_date} +${i} day"`; done))
[me@linux ~]$ printf "%s\n" ${date_seq[@]}
2020/09/02
2020/09/03
2020/09/04
2020/09/05
2020/09/06
2020/09/07
2020/09/08
How to calculate the difference between two dates in shell?
There is a naive way to do this easily by subtracting both dates from their Unix timestamp value and then convert the seconds to hours or days as needed. For a Math in Bash refresher, see my post on
Performing Math Calculation In Bash. With the GNU date
command line, we can use the +%s
format specifier to get the unix timestamp of a date.
Note that if the date difference is expected to be within the same year timeframe, then the date
command line can do the subtraction directly, though the output may be slightly confusing since a full 24 hours would be represented as two different days.
[me@linux ~]$ firstDate=$(date -d 'Feb 12 2020 UTC' +%s)
[me@linux ~]$ secondDate=$(date -d 'Feb 13 2020 UTC' +%s)
[me@linux ~]$ echo $firstDate $secondDate
1581494400 1581552000
[me@linux ~]$ echo "The difference is $(( (secondDate-firstDate) / 3600 )) hours"
The difference is 24 hours
# Alternative option to calculate date difference in the same year timeframe
[me@linux ~]$ date -d "2020-01-01 $secondDate sec - $firstDate sec" +"%j days %H hours %M minutes and %S seconds"
002 days 00 hours 00 minutes and 00 seconds
⚠️ When using this method, make sure to always use the UTC standard for the date, to avoid troubles with daylight saving and possibly get an
invalid date
error. You can convert a date to UTC by using the-u
option. Also, note that this is still a very naive way to diff two dates and it does not consider the more complex scenarios where you may require the support of leap seconds or leap years.
How to calculate the time elapsed in Bash?
The simplest option is to use the special shell variable $SECONDS
to get the number of seconds elapsed. This special variable returns a count of the number of whole seconds since the shell or script has been running. The variable can be reset to zero or any other integer.
[me@linux ~]$ SECONDS=0; sleep 2; echo "Time elapsed since \$SECONDS was reset: $SECONDS seconds";
Time elapsed since $SECONDS was reset: 2 seconds
Alternatively, you can calculate the difference between two dates as described in the section How to calculate the difference between two dates?.
How to convert a date to UTC?
You can use the date
command-line tool with the -u
option to convert a date to UTC. The -u
option is part of the POSIX standard and available on all platforms, see earlier section
What are the differences between Linux and Unix/macOS?
[me@linux ~]$ date && date -u
Wed Feb 12 13:42:17 PST 2020
Wed Feb 12 21:42:17 UTC 2020
An alternative to the date
command line is to use a unix timestamp and printf
, see the next question on
How to convert the Unix Timestamp to UTC in shell? (i.e. Unix to Date format)
How to convert the Unix Timestamp to UTC in shell? (i.e. Unix to Date format)
The easiest way to convert a Unix Timestamp to UTC is to use GNU date
with the @
feature and the -u
option.
[me@linux ~]$ date -d @1547092066 -u
Thu Jan 10 03:47:46 UTC 2019
Another option would be to use the bash printf
builtin and set the TZ
environment variable to UTC
. The %+
specifier uses the date and time format as in the date
command line.
[me@linux ~]$ printf "%(%+)T\n" 1547092066
Wed Jan 9 19:47:46 PST 2019
[me@linux ~]$ TZ=UTC printf "%(%+)T\n" 1547092066
Thu Jan 10 03:47:46 UTC 2019
How to properly assign shell date output to variables?
When using the date
command line on Linux or Mac/Unix, it is not recommended to call it multiple times in a row to assign values to a variable as the command will happen at different times and will represent different date and time. This can lead to major errors in a shell script if it runs a millisecond before midnight and the first command returns one day while the second call returns the following day.
Don’t do month=$(date +%m); day=$(date +%d); year=$(date +%Y)
, instead you can either
- retrieve the date and assign it to a bash array
- retrieve the date as a timestamp then apply a different date format with
printf
ordate
- use
eval
on the output of adate
orprintf
command
👉 In general, I prefer to avoid the use of
eval
at all costs as it can lead to some major security flaws in your shell script. With the possibility offered by the bash arrays, there is no reasons to useeval
anymore. There is often a better and safer alternative toeval
, see the few examples below.
# Example using date and a bash array
[me@linux ~]$ declare -A myDate=$(date +'([month]=%m [day]=%d [year]=%Y)')
[me@linux ~]$ echo "Month=${myDate[month]}, Day=${myDate[day]}, Year=${myDate[year]}"
Month=06, Day=12, Year=2020
# Generate a fixed unix timestamp
[me@linux ~]$ today=$(date +"%s")
[me@linux ~]$ today=$EPOCHSECONDS # Bash 5 and above
# Format a timestamp using printf variable assignment
[me@linux ~]$ printf -v month '%(%m)T' $today; printf -v day '%(%d)T' $today;
[me@linux ~]$ echo $month $day
06 12
# Format a timestamp using linux date command line
[me@linux ~]$ month=$(date -d @$EPOCHSECONDS +"%m"); day=$(date -d @$EPOCHSECONDS +"%d");
[me@linux ~]$ echo $month $day
06 12
# Run eval on a date output to assign to individual variables / not necessary
[me@linux ~]$ eval "$(date +'month=%m day=%d')"
[me@linux ~]$ echo $month $day
06 12
What is the timezone environment variable TZ?
The $TZ
environment variable contains timezone information that is used by internal libraries and utilities to override default timezone information. You shouldn’t normally need to set the $TZ
variable, unless you purposely want to override your current environment Timezone information when executing a command.
The $TZ
variable can be in one of the form TZ=:<characters>
or TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
.
When using the colon :
format, the TZ is handled in an implementation-defined manner. For example, the GNU C library will often default to the value TZ=:/etc/localtime
(or TZ=:/usr/local/etc/localtime
), other libraries may define different defaults and ways to handle this format.
The second format, not starting with a colon :
, can be used to describe a timezone and is often used when overriding a TZ information from the command line. For example: TZ=UTC date
. The format properties from the syntax stdoffset[dst[offset][,start[/time],end[/time]]]
are detailed in the table below.
The stdoffset
represent two field being std
and offset
, there is no space character separating those fields.
std | The std string specify the name of the timezone. It is no less than three characters long and cannot contain a leading colon, embedded digits, commas, nor plus and minus signs. |
offset | This is the timezone offset which correspond to the time value to be addedd to the local time in order to get the UTC value. It follows the format `[+ |
dst[offset][,start[/time],end[/time]] | The dst portion of the syntax is used to specify the daylight saving information. The dst is the name of the daylight saving and the offset is the offset corresponding to the daylight saving with a default value of one hour ahead of the standard time. The remainer is used to define when the daylight saving start and end . |
start and end | The start and end date can be of three different format. 1) Julian day Jn where 1 <= n <= 365 and should not include leap days. 2) Zero based Julian day n where 0 <= n <= 365 and must include leap days. 3) Calendar day Mm.n.d where d is the day (0-6) of the week n of month m of the year. Where 1 <= n <= 5, 1 <= m <= 12, week 5 is the latest week of the month and Sunday is day zero of the week. |
For example, the North American Eastern Standard Time (EST
), used in New-York (NY, USA), use the daylight saving named Eastern Daylight Time (EDT
). The standard offset from the UTC
timezone is 5 hours. It is is west of the prime meridian so the sign is positive +
. The daylight saving start in March (Month 3) on the second (Week 2) Sunday (Day 0) at 2:00am, and ends in November (Month 11) on the first Sunday (Week 1) at 2:00am. The full TZ
format is then EST+5EDT,M3.2.0/2,M11.1.0/2
.