10

Given that UTC is not a time zone, but a time standard (as stated, for example, here), why in my Java application I can use UTC as if it was a time zone (see the code snippet below)?

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("UTC"));

If UTC is not a time zone, why is TimeZone.getTimeZone("UTC") able to return the time zone object?


By the way, on my Windows machine UTC is in the list of time zones also (see the screenshot).

Is the statement "UTC is not a time zone" in reality wrong?

UTC is a time zone in Windows

yaskovdev
  • 1,213
  • 1
  • 12
  • 22
  • 4
    The Java data and time API (introduced in Java 8 and backported to Java 6 and 7) makes the distinction between an *offset* (as UTC or UTC-5:00) and a *time zone* (as Europe/London or Asia/Kolkata). And then “cheats”, as you might call it, by making the `ZoneOffset` a subclass of `ZoneId`, thereby declaring that an offset is also a kind of time zone. – Ole V.V. Jun 26 '17 at 10:02
  • I want to say, because there must be one, no matter which one. And if anyone been chosen, it became the stander one. – tsh Jul 11 '17 at 08:35
  • 1
    `SimpleDateFormat` is one of the terrible date-time classes that were supplanted years ago by the modern *java.time* classes. The legacy classes were built by people who did not understand the complexities and subtleties of date-time handling. The distinction between (a) time zone and (b) offset-from-UTC is one of those important points not understood by the legacy class designers. Do not take any lessons from the legacy classes; simply ignore them and move on to *java.time* as did Sun, Oracle, and the JCP community. – Basil Bourque Nov 26 '20 at 18:07
  • @BasilBourque, fully agree with you that the legacy Date-Time API has a lot of drawbacks. However, if I try the same with the modern API, I still can see that UTC is treated as if it was a time zone: `ZoneId.of("UTC")` returns a valid `ZoneId` object. – yaskovdev Nov 26 '20 at 18:12
  • @yaskovdev Actually, the subclass of `ZoneId`, `ZoneOffset` declares a constant [`ZoneOffset.UTC`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/ZoneOffset.html#UTC). This constant is simply an offset-from-UTC of zero hours, zero minutes, and zero seconds. What might be confusing you is that the word “UTC” is often used as an abbreviation for that phrase, “an offset-from-UTC of zero hours, zero minutes, and zero seconds”. That word “UTC” has two meanings: (a) that abbreviated phrase, and (b) a formally-defined system of time-keeping. – Basil Bourque Nov 26 '20 at 22:28

2 Answers2

13

Because it makes life much, much simpler to regard UTC as a time zone than to treat it as something else, basically.

It's one of those "Yeah, strictly speaking it's not" scenarios. For everything except "Which region of the world is this observed?" you can think of UTC as a time zone and it works fine. So it's simpler to bend it slightly out of shape than to have a whole separate concept.

If you view a time zone as a mapping from "instant in time" to "UTC offset" (or equivalent, from "instant in time" to "locally observed time") then UTC is fine to think of as a time zone - and that's most of what we do within software.

If you view a time zone as a geographical region along with that mapping, then no, it doesn't work as well - but that's more rarely useful in software. (And you can always fake it by saying it's an empty region :)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I read the question, and thought about scrolling down to write up something very close to what you wrote ... just to find that content already there. On the one hand that feels awkward (how can Jon Skeet know what I am thinking 3 minutes later) ... on the other hand, I feel honored that you decided to put what I was thinking ;-) – GhostCat Jun 26 '17 at 09:25
  • Aren't there a stack of countries in West Africa that are permanently on UTC (and being close to the Equator don't use daylight savings) ? – Alnitak Jun 26 '17 at 09:26
  • 1
    @Alnitak: They might be at the moment, but I wouldn't want to label that as "the UTC time zone". In particular, users converting to UTC aren't trying to find out the local time in those places... they're trying to effectively convert to a "location neutral" zone. – Jon Skeet Jun 26 '17 at 09:27
  • @GhostCat: Likewise I'm very happy to know that what I've written makes sense :) – Jon Skeet Jun 26 '17 at 09:27
  • So it would be more accurate to say that those places are on GMT ? – Alnitak Jun 26 '17 at 09:28
  • 4
    @Alnitak: No, it would be more accurate to give those places their own time zone (or collection of time zones) which happen to always have a UTC offset of 0. Note that there may be periods of history where they *didn't* have a UTC offset of 0, which is one reason why it's useful to give them specific IDs. – Jon Skeet Jun 26 '17 at 09:33
9

Is the statement "UTC is not a time zone" in reality wrong?

Technically and strictly speaking, the statement is not wrong. UTC is a standard, not a timezone (as you already linked).

A timezone corresponds to some region in the world and has lots of different rules regarding that region:

  • What's the UTC offset (the difference from UTC) when it's in Daylight Saving time and when it's not
  • When DST starts and ends
  • All the changes in offsets and DST this region had during its history

Example: in 1985, the brazilian state of Acre had standard offset UTC-05:00 (and UTC-04:00 during DST), then in 1988 it was on UTC-05:00 without DST, then in 2008 the standard changed to UTC-04:00 (and no DST), and since 2013 it's back to UTC-05:00 and no DST.

While the timezone keeps track of all of these changes, UTC has no such rules. You can think of UTC in many different ways:

  • a "base" date/time, from where everybody else is relative to - this difference from UTC is called "offset". Today, São Paulo is in UTC-03:00 (the offset is minus 3 hours, or 3 hours behind UTC) while Tokyo is in UTC+09:00 (offset of plus 9 hours, or 9 hours ahead UTC).
  • a "special" timezone that never varies. It's always in the same offset (zero), it never changes, and never has DST shifts.

As the "offset of UTC" (not sure how technically accurate is this term) is always zero, it's common to write is as UTC+00:00 or just Z.

Another difference between UTC and timezone is that a timezone is defined by governments and laws and can change anytime/anywhere. All the changes in Acre described above were defined by politicians, for whatever reasons they thought at that time. (So, even if a region today follows UTC in their timezone, there's no guarantee that it'll stay the same in the future, and that's why even those regions have their own timezones, even if they look redundant).

But no matter how many times politicians change their regions offsets, they must be relative to UTC (until a new standard comes up, of course).


Now, when you see implementations like TimeZone.getTimeZone("UTC"), you can think of it in 2 different ways:

  • a design flaw, because it's mixing 2 different concepts and leading people to think they're the same thing
  • a shortcut/simplification/nice-trick/workaround, that makes things easier (as @JonSkeet explained in his answer).

For me, it's a mix of both (fifty/fifty).


The new java.time API, though, separates the concepts in 2 classes: ZoneRegion and ZoneOffset (actually both are subclasses of ZoneId, but ZoneRegion is not public so actually we use ZoneId and ZoneOffset):

  • if you use a ZoneId with IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin), it will create a ZoneRegion object - a "real" timezone with all the DST rules and offset during its history. So, you can have different offsets depending on the dates you're working with in this ZoneId.
  • if you use a ZoneOffset (with Z, UTC, +03:00 and so on), it will return just an object that represents an offset: the difference from UTC, but without any DST rules. No matter what dates you use this object with, it'll always have the same difference from UTC.

So, the ZoneId (actually ZoneRegion) is consistent with the idea that offsets in some region (in some timezone) change over time (due to DST rules, politicians changing things because whatever, etc). And ZoneOffset represents the idea of difference from UTC, that has no DST rules and never changes.

And there's the special constant ZoneOffset.UTC, which represents a zero difference from UTC (which is UTC itself). Note that the new API took a different approach: instead of saying that everything is a timezone and UTC is special kind, it says that UTC is a ZoneOffset which has a value of zero for the offset.

You can still think it's a "wrong" design decision or a simplification that makes things easier (or a mix of both). IMO, this decision was a great improvement comparing to the old java.util.TimeZone, because it makes clear that UTC is not a timezone (in the sense that it has no DST rules and never changes), it's just a zero difference from the UTC standard (a very technical way of saying "it's UTC").

And it also separates the concepts of timezone and offset (that are not the same thing, although very related to each other). I see the fact that it defines UTC as a special offset as an "implementation detail". Creating another class just to handle UTC would be redundant and confusing, and keeping it as a ZoneOffset was a good decision that simplified things and didn't mess the API (for me, a fair tradeoff).

I believe that many other system's decide to take similar approaches (which explains why Windows have UTC in the timezone list).