186

I have a server running with the time zone set to UTC. It seemed like that was generally a good practice (please correct me if I'm wrong).

Anyhow, one of the servers I connect to, in order to scp files, is running on EDT and stores files that I need to copy in the format /path/to/filename/data20120913.

I looked at trying to rsync files using something like find's -mtime -1 flag for files modified in the last day, but I didn't have any luck.

I don't mind just using scp to copy the current day's file, but as of right now there is a 4-hour window where running date +%Y%m%d will give a different day on each server and that bugs me a little.

Looking through man date I see that I can have the time output as UTC, but I don't see a way to have it output as another time zone like EDT

I suppose I could also use something like the GNU date extension date -d 20100909 +%s to get the date in seconds since the epoch, apply a manual 4 * 60 * 60 second calculation, and see about rendering that as a date - but then when daylight time kicks in it will still be an hour off.

Is there a simpler way to output the date in a YYYYMMDD format for EDT on a server that is set to UTC?

2
  • EDT is not a recognized timezone- in Linux, at least. See my "Be careful!" answer below for the whole ugly story. If EDT is recognized on your brand of *NIX, you should still exercise caution and double-check your timezone string.
    – Mike S
    Mar 17, 2015 at 15:27
  • See also this answer which searches /usr/share/zoneinfo and shows the time in zones matching your query.
    – mivk
    Jan 15, 2020 at 12:17

7 Answers 7

264

You can set a time zone 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 shells, that sets the TZ variable for the current command only. 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. time zones 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 time zone 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 time zone 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 time zones using a path 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 time zones 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 time zones by inspecting the following directory: /usr/share/zoneinfo.

7
  • not sure if am I wrong, but export looks better than env command
    – insign
    Dec 23, 2017 at 15:58
  • 1
    @Motivated If your city or state isn't included, choose one that uses the same zone info as yours. For instance, I'm in Florida, which uses the same timezone as New York, so my machines synchronize to New York time.
    – JRFerguson
    Jan 31, 2019 at 17:45
  • 2
    @JRFerguson - That assumes that the person is aware of the various timezones and is able to use an alternative e.g. New York in your case. Would that be the only option? For example, i don't live in Europe and i won't know the overlapping timezones.
    – Motivated
    Jan 31, 2019 at 17:49
  • 2
    @Motivated You can use something like this site to assist you in finding other points in your zone.
    – JRFerguson
    Jan 31, 2019 at 17:53
  • 2
    @JRFerguson Maybe you can. But then that shouldn't be necessary. What if there is no Internet connectivity? What if the person is unaware of such a website? What if ... It shouldn't be necessary and at best what you propose is a workaround. That's not the right way to go about it. I'm not saying that you're behind this I'm just saying that it's not the right way (I hope that makes sense - I'm dead tired).
    – Pryftan
    Sep 20, 2019 at 17:08
47

You can do this by manipulating the TZ environment variable. The following will give you the local time for US/Eastern, which will also be smart enough to handle DST when that rolls around:

# all on one line
TZ=":US/Eastern" date +%Y%m%d

The zone name comes from the files and directories inside /usr/share/zoneinfo.

0
28

Be careful! Date will happily spit out the time in your CURRENT timezone, if you give it a timezone it doesn't recognize.

Check this out:

-bash-4.2$ env TZ=EDT date
Wed Feb 18 19:34:41 EDT 2015
-bash-4.2$ date
Wed Feb 18 19:34:43 UTC 2015

Note that there is no timezone called EDT. As a matter of fact,

-bash-4.2$ find /usr/share/zoneinfo -name "*EDT*"

returns

/usr/share/zoneinfo/EST5EDT
/usr/share/zoneinfo/posix/EST5EDT
/usr/share/zoneinfo/right/EST5EDT

And this works:

-bash-4.2$ TZ=EST5EDT date
Wed Feb 18 14:36:59 EST 2015
-bash-4.2$ date
Wed Feb 18 19:37:01 UTC 2015

However, if your friend lives in the mystic land of Gobbledygook and its zone info coincides with your own, you can have date output the time in Gobbledygook's zone and it will be happy to do so with nary an exit value to let you know that the zone is not known to it:

-bash-4.2$ TZ=Gobbledygook date
Wed Feb 18 19:37:36 Gobbledygook 2015
-bash-4.2$ echo $?
0
2
  • 3
    YMMV: on my MacOS/BSD box, malformed TZ string returns UTC time. Sep 20, 2019 at 17:40
  • @MarkHudson: Yes, also date from GNU coreutils 9.3 on Arch Linux uses UTC when TZ is set to an invalid value. For example, TZ="Gobbledygook" date +"%z %Z" produces "+0000 Gobbledygook". My current time zone is +0200 CEST according to date +"%z %Z". Jul 7 at 15:41
14
TODAY=$(TZ=":US/Eastern" date)
echo $TODAY
0
13

The date syntax is arcane and error-prone, which makes a command-line invocation a pain. I therefore wrote a small script (I named it worldtime), which will print the specified (or current) time from base time zome (your local one) in some other time zones and the converse.

Here it is. Adjust it to match your needs, put it in your path, and make it executable.

#!/bin/sh
#
# Print the specified (or current) time from base time in other time zones
# and the converse
#

# Base time zone from/to which to convert
TZBASE=Europe/Athens

# Time zones to display
# See /usr/share/zoneinfo/ for more names
TZONES='UTC America/Los_Angeles America/New_York Europe/London Europe/Paris'

# Display format
FORMAT='%H:%M (%p) %Z %a %m %b %Y'

if [ "$1" ] ; then
  time="$1"
else
  time=`date +%T`
fi

# Show the time from the specified input time zone in the specified output
# time zone
showtime()
{
  TZIN=$1
  TZOUT=$2

  TZ=$TZOUT date --date='TZ="'$TZIN'"'" $time" +"$time $TZIN is $TZOUT $FORMAT"
}

for tz in $TZONES ; do
  showtime $TZBASE $tz
done

echo

for tz in $TZONES ; do
  showtime $tz $TZBASE
done

5

Often you have timestamp in local timezone and you need to convert it to remote tz. It can be done with:

TZ=America/Curacao date -d 'Tue Nov 28 00:07:05 MSK 2016'

where:

America/Curacao - remote timezone
MSK - local timezone
1

Show New York time tomorrow at 3pm

date --date='TZ="America/NewYork" 15:00 tomorrow'

Prints:

ti 3.11.2020 17.00.00 +0200

(ti is Finnish short from tiistai, meaning tuesday in English.)

My local timezone is Finland/Helsinki. So tommorrow at 17 o'clock in Finland/Helsinki is same time: 3pm in New York.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .