You can set a timezone for the duration of the query, thusly:
TZ=America/New_York date
Note the whitespace between the TZ
setting and the date
command. In Bourne-like and rc
-like shell, that sets the TZ
variable only for the command line. In other shells (csh
, tcsh
, fish
), you can always use the env
command instead:
env TZ=America/New_York date
tl;dr
On Linux systems. timezones are defined in files in the /usr/share/zoneinfo
directory. This structure is often referred to as the "Olson database" to honor its founding contributor.
The rules for each timezone are defined as text file lines which are then compiled into a binary file. The lines so compiled, define the zone name; a range of data and time during which the zone applies; an offset from UTC for the standard time; and the notation for defining how transition to-and-from daylight saving time occurs, if applicable.
For example, the directory "America" contains the requisite information for New York in the file America/New_York
as used, above.
Beware that the specification of a non-existent zone (file name) is silently ignored and UTC times are reported. For example, this reports an incorrect time:
TZ="America/New York" date ### WRONG ###
The Single UNIX Specification, version-3, known as SUSv3 or POSIX-2001, notes that for portability, the character string that identifies the timezone description should begin with a colon character. Thus, we can also write:
TZ=":America/New_York" date
TZ=":America/Los_Angeles" date
As an alternative method to the specification of timezones using a pathname to a description file, SUSv3 describes the POSIX model. In this format, a string is defined as:
std offset [dst[offset][,start-date[/time],end-date[/time]]]
where std
is the standard component name and dst
is the daylight saving one. Each name consists of three or more characters. The offset
is positive for timezones west of the prime meridian and negative for those east of the meridian. The offset is added to the local time to obtain UTC (formerly known as GMT). The start
and end
time fields indicate when the standard/daylight transitions occur.
For example, in the Eastern United States, standard time is 5-hours earlier than UTC, and we can specify EST5EDT
in lieu of America/New_York
. These alternatives are not always recognized, however, especially for zones outside of the United States and are best avoided.
HP-UX (an SUSv3 compliant UNIX) uses textual rules in /usr/lib/tztab
and the POSIX names like EST5EDT, CST6CDT, MST7MDT, PST8PDT. The file includes all of the historical rules for each time zone, akin to the Olson database.
NOTE: You should be able to find all of the timezones by inspecting the following directory: /usr/share/zoneinfo
.
I didn't find a simple solution to my question, so I've written a small Bash script to solve it. You need to download the leap seconds file given in the link below and put it with the script or change the path to it. I didn't write utc2unix.sh
yet, but it's very easy to adapt. Do not hesitate to comment/give suggestions...
unix2utc.sh:
#!/bin/bash
# Convert a Unix timestamp to the real number of seconds
# elapsed since the epoch.
# Note: this script only manage additional leap seconds
# Download leap-seconds.list from
# https://github.com/eggert/tz/blob/master/leap-seconds.list
# Get current timestamp if nothing is given as first param
if [ -z $1 ]; then
posix_time=$(date --utc +%s)
else
posix_time=$1
fi
# Get the time at which leap seconds were added
seconds_list=$(grep -v "^#" leap-seconds.list | cut -f 1 -d ' ')
# Find the last leap second (see the content of leap-seconds.list)
# 2208988800 seconds between 01-01-1900 and 01-01-1970:
leap_seconds=$(echo $seconds_list | \
awk -v posix_time="$posix_time" \
'{for (i=NF;i>0;i--)
if (($i-2208988800) < posix_time) {
print i-1; exit
}
} END {if (($(i+1)-2208988800) == posix_time)
print "Warning: POSIX time ambiguity:",
posix_time,
"matches 2 values in UTC time!",
"The smallest value is given." | "cat 1>&2"
}')
# echo $leap_seconds
# Add the leap seconds to the timestamp
seconds_since_epoch=$(($posix_time + $leap_seconds))
echo $seconds_since_epoch
Just some tests:
date --utc +%s && ./unix2utc.sh
-> today and at least until June 2015 the difference is 25 sec.
./unix2utc.sh 78796799
-> 78796799
./unix2utc.sh 78796801
-> 78796802
./unix2utc.sh 78796800
-> 78796800
+ on stderr: Warning: POSIX time ambiguity: 78796800 matches 2 consecutive values in UTC time! Only the smallest value is given.
Best Answer
This is an important reason to use the
$( )
instead of` `
(see What's the difference between $(stuff) and `stuff`?)If you nest it like this, you don't even need
let
or a variable: