three-cups
three-cups

Reputation: 4385

Displaying local time to a user when all you have is an offset (from GMT)

I understand that it's pretty easy to display local time to a user given an offset from GMT for the timezone (e.g. -7 hours for Pacific Daylight Time).

But, what if I want to continue to display the correct local time for a long period of time (say 1 year). Given just an offset from GMT, you do not know what timezone the user is in. E.g. given -7, the user may live in the US or in Canada (or in some other country). These countries my have different local times at different points of the year (e.g. if the US changes to daylight time in March and CA in April).

My question is, is the above paragraph correct? Is there a standard way to take a GMT offset and make a good guess as to which timezone the user is in?

Upvotes: 2

Views: 263

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 339362

Your conclusion is correct: There is no reliable way to identify a time zone from an offset-from-UTC.

For your example of an offset of -07:00, I count about three dozen possible time zones in the current list including: America/Boise, America/Chihuahua, and America/Edmonton.

A time zone is actually a collection of offsets, recording changes made over time with a certain offset used in that region for a certain period of time but then changed over another certain period of time.

For example, in America/Los_Angeles part of each year has an offset of -08:00 while another part of the year has -07:00. So that time zone is accumulating a history of at least two offsets per annum. In contrast, the neighboring region using the time zone America/Phoenix is not accumulating changes in its offset, having retained the same -07:00 offset for decades.

So we have a many-to-many relationship between offsets and time zones. An offset may appear in one or more time zones. And each time zone can have one or more offsets (having changed over history).

Include time zone name

This is why the designers of the java.time class ZonedDateTime have taken the liberty of having its toString method extend the standard ISO 8601 format using only offsets to also append the name of the time zone in square brackets.

For example, instead of simply generating the standard format: 2007-12-03T10:15:30+01:00, the class generates 2007-12-03T10:15:30+01:00[Europe/Paris] with the name of the zone Europe/Paris appended.

ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
             .toString()

2007-12-03T10:15:30+01:00[Europe/Paris]

I hope this practice of appending the time zone name catches on. The lack of time zone name is a surprising omission by the standards committees that otherwise did an outstanding job in designing ISO 8601.

You can guess about the time zone using clues from the context of your business scenario. But I advise against that. Guessing is risky, especially because politicians around the world have a penchant for frequently re-defining time zones.

UTC

The best practice in storing, serializing, and exchanging date-time values is generally to adjust into UTC. Assuming a date-time library’s tzdata is up-to-date, adjusting into UTC provides a reliable value that is always correct and unambiguous.

In Java, for example, that means using or extracting an Instant object. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = Instant.now();

…or…

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
Instant instant = zdt.toInstant();

The standard ISO 8601 formatted string representing such a value uses a Z as short for Zulu and meaning UTC.

2007-12-03T09:15:30Z

OffsetDateTime

If you are given a string representing a date-time with only an offset, parse it as a OffsetDateTime object.

OffsetDateTime odt = OffsetDateTime.parse( "2007-12-03T10:15:30+01:00" );

odt.toString(): 2007-12-03T10:15:30+01:00

From there you can extract a value in UTC, an Instant.

Instant instant = odt.toInstant();

instant.toString(): 2007-12-03T09:15:30Z

Or you can adjust into a desired time zone to get the same moment as a ZonedDateTime object.

ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );

zdt.toString(): 2007-12-03T14:45:30+05:30[Asia/Kolkata]

Terminology: “local”

I suggest you avoid the term “local” when referring to a date-time adjusted into a region’s particular wall-clock time. The word “local” in the java.time classes and in other contexts means any locality, rather than a particular locality. A local date-time is not a specific moment on the timeline, only a rough idea about a range of possible moments.

For example the local date-time of the beginning of Christmas this year is 2017-12-25T00:00:00, but that moment of midnight is much earlier in Auckland than in Kolkata, and still hours later in Paris, while even more hours later in Montréal.

I suggest instead you use the terms zoned or wall-clock time when you mean a specific moment seen through the lens of a particular time zone.

Tip: Offset literals

The Question happened to use the letters -7 when referring to an offset. I suggest always:

  • Using double-digits with padding zero, as required by ISO 8601
  • Using both hour and minutes, as expected by some libraries and formats.

So use -07:00 rather than -7.

Upvotes: 1

Related Questions