Skip to content
Greg Miller edited this page Apr 11, 2016 · 7 revisions

What is an absolute time?

Absolute time uniquely and universally represents a specific instant in time. It has no notion of calendars, or dates, or times of day. Instead, it is a measure of the passage of real time, typically as a simple count of ticks since some epoch. Absolute times are independent of all time zones and do not suffer from human-imposed complexities such as daylight-saving time (DST). Many C++ types exist to represent absolute times, classically time_t and more recently std::chrono::time_point.

What is a civil time?

Civil time is the legally recognized representation of time for ordinary affairs (cf. http://www.merriam-webster.com/dictionary/civil). It is a human-scale representation of time that consists of the six fields — year, month, day, hour, minute, and second (sometimes shortened to "YMDHMS") — and it follows the rules of the Proleptic Gregorian Calendar, with 24-hour days divided into 60-minute hours and 60-second minutes. Civil times are independent of all time zones and do not suffer from human-imposed complexities such as daylight-saving time (DST).

What is a time zone?

Time zones are geo-political regions within which human-defined rules are shared to convert between the absolute-time and civil-time domains. A time zone's rules include things like the region's offset from the UTC time standard, daylight-saving adjustments, and short abbreviation strings. Time zones often have a history of disparate rules that apply only for certain periods, because the rules may change at the whim of a region's local government. For this reason, time-zone rules are usually compiled into data snapshots that are used at runtime to perform conversions between absolute and civil times. Time zones are named using names defined by the IANA time-zone database. Examples of time-zone names are

  • "America/Los_Angeles"
  • "Europe/London"
  • "Australia/Sydney"
  • "Asia/Tokyo"

Note that "PST" and "EDT" are abbreviations, not time-zone names.

How do I represent a "date"?

Date's (i.e., a year, month, and day following the rules of the Gregorian calendar) are the most common representation of civil time. In the CCTZ civil-time library dates are represented by instances of thecctz::civil_day class. For example:

#include "civil_time.h"
cctz::civil_day google_ipo(2004, 8, 19);
cctz::civil_day early_retirement = google_ipo + 1;

How do I get the offset for a time zone?

Well-written time code should never care about UTC offsets. Seriously. Time-zone offsets can and do change, and they are only valid at particular times. Code that depends on a specific UTC offset is fragile. Printing an offset with cctz::format() is fine, but computing with an offset is almost certainly a mistake. So, the answer to the question is that your application should depend on cctz::time_zone rather than a specific offset.

Oh, come on. Just tell me how to get the offset, please.

OK, fine. We're aware that there are some legacy APIs that require UTC offsets. In these cases you can get the offset from the cctz::time_zone::absolute_lookup struct. But note that the offset is only valid for the specific time point that was used to look it up.

How do I compute a "local" time point?

There is no such thing as "local" absolute time, so you cannot compute a local std::chrono::time_point. However, it is not uncommon to see legacy code that attempts this in order to make the absolute time in UTC appear to be in some other time zone. This mistaken technique is called "epoch shifting". It is done by finding a time-zone offset and adding that offset to, or subtracting it from, an absolute time. The problem is that simply produces a different point in time, not a "local" version of the absolute time. This strategy throws away information, may not be reversible, can be wrong near offset transitions, and should always be avoided. Any library that requires or encourages this should be strictly avoided. For more information about epoch shifting, see the video talk from CppCon 2015.

Fortunately, epoch shifting is never needed when using a proper time-zone library such as the one provided with CCTZ. Anywhere you think you need an offset, you really need a cctz::time_zone. If you follow the concepts and APIs provided by CCTZ, you'll find that you never need to compute with UTC offsets and your code is much simpler.

Rule of thumb: never do arithmetic with a UTC offset.

What exactly is UTC?

UTC is the international standard for civil time. It is defined in terms of the six civil-time fields — year, month, day, hour, minute, second — that follow the rules of the Gregorian calendar. Local times around the world are defined as offsets from this UTC time standard. For example, a time zone with a 1-hour offset from UTC is one civil hour ahead of UTC.

Where is the data used by the CCTZ time-zone library?

The CCTZ time-zone library uses the compiled IANA time-zone database files that exist on the system. These are typically found in /usr/share/zoneinfo or in the directory named in the TZDIR environment variable.

What about leap seconds?

The CCTZ libraries assume the POSIX definition of time_t, which defines minutes as having exactly 60 seconds. This definition is incompatible with leap seconds, allowing CCTZ libraries to present a simplified interface.

Note: Leap-second support could be added to the CCTZ time-zone API, but it would only be applicable for users with a system clock that ticks TAI, and uses the leap-second encoded (i.e., "right") zoneinfo files.