RFC 9636
The Time Zone Information Format (TZif)
RFC 9636: The Time Zone Information Format (TZif) ๐ฐ๏ธ๐
Okay bestie, RFC 9636 is giving main character energy ๐ . It's a Standards Track doc from October 2024, written by A. Olson, P. Eggert (UCLA), and K. Murchison (Fastmail). Its ISSN is 2070-1721 ๐. It obsoletes RFC 8536 (the older version), and it doesn't update anything else ๐ธ. It's an official IETF document, so this is the real deal โจ.
Abstract ๐
This document specifies the Time Zone Information Format (TZif) for representing and exchanging time zone information, independent of any particular service or protocol. Two media types for this format are also defined ๐ฆ.
This document replaces and obsoletes RFC 8536 ๐ซถ.
Status of This Memo ๐
This is an Internet Standards Track document ๐.
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 7841 โจ.
Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://www.rfc-editor.org/info/rfc9636 ๐.
Copyright Notice ยฉ๏ธ
Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved ๐.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, because they describe your rights and restrictions with respect to this document ๐. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Revised BSD License ๐.
Table of Contents ๐บ๏ธ
1. Introduction
2. Conventions Used in This Document
3. The Time Zone Information Format (TZif)
3.1. TZif Header
3.2. TZif Data Block
3.3. TZif Footer
3.3.1. All-Year Daylight Saving Time
3.3.2. TZ String Extension
4. Interoperability Considerations
5. Internationalization Considerations
6. Use with the Time Zone Data Distribution Service
6.1. Truncating TZif Files
6.2. Example TZDIST Request for TZif Data
7. Security Considerations
8. Privacy Considerations
9. IANA Considerations
9.1. application/tzif
9.2. application/tzif-leap
10. References
10.1. Normative References
10.2. Informative References
Appendix A. Common Interoperability Issues
Appendix B. Example TZif Files
B.1. Version 1 File Representing UTC (with Leap Seconds)
B.2. Version 2 File Representing Pacific/Honolulu
B.3. Truncated Version 2 File Representing Pacific/Johnston
B.4. Truncated Version 3 File Representing Asia/Jerusalem
B.5. Truncated Version 4 File Representing Europe/London
Appendix C. Changes from RFC 8536
Acknowledgments
Authors' Addresses
1. Introduction โจ
Okay so, time zone data usually includes offsets from universal time (UT) ๐, daylight saving transition rules โ๏ธ, one or more local time designations (acronyms or abbreviations) ๐ท๏ธ, and optional leap-second adjustments โ. One format that carries this info is iCalendar [RFC5545] ๐ . It's text-based and used by calendaring and scheduling systems, so it's giving organized ๐๏ธ.
This document specifies the widely deployed Time Zone Information Format (TZif) ๐. It's a binary format that most UNIX systems use to work out local time ๐ป. It came out in the 1980s and has since evolved into several upward-compatible versions, which is honestly iconic ๐ง. Lots of interoperable software can generate and read files in this format [tz-link] ๐.
This specification doesn't define where the data in a TZif file comes from ๐คทโโ๏ธ. One such source is the IANA-hosted time zone database [RFC6557] ๐.
This document obsoletes [RFC8536] ๐ซถ, bringing editorial improvements, new details, and errata fixes, all while keeping full compatibility with the interchange format of [RFC8536] ๐. It also defines a new version of the format ๐ฆ. The changes from [RFC8536] are summarized in Appendix C ๐.
2. Conventions Used in This Document ๐ค
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐ .
Here are the terms used in this document. For more detail about civil timekeeping data and practice, check out "Time zone and daylight saving time data" [tz-link] ๐ง .
Coordinated Universal Time (UTC): The basis for civil time since 1960 โฑ๏ธ. It's approximately equal to mean solar time at the prime meridian (0 degrees longitude) ๐.
Daylight Saving Time (DST): The time according to a location's law or practice, adjusted as necessary from standard time ๐ . The adjustment may be positive or negative, and its amount may vary depending on the date and time. The TZif format even allows the adjustment to be zero, although that isn't common practice ๐.
International Atomic Time (TAI): The time standard based on atomic clocks since 1972 โ๏ธ. It's equal to UTC, but without leap-second adjustments ๐งฎ.
Leap Second: A one-second adjustment that keeps UTC close to mean solar time at the prime meridian (see [ITU-R-TF.460]) ๐. Each inserted or deleted leap second happens at the end of a UTC month, meaning a month using the Gregorian calendar and the UTC timescale ๐.
Leap-Second Correction (LEAPCORR): The value of "TAI - UTC - 10" for timestamps after the first leap second, and zero for timestamps before that ๐ข. The expression "TAI - UTC - 10" comes from the fact that TAI - UTC was defined to be 10 just before the first leap second in 1972. That's why clocks with leap seconds have a zero LEAPCORR before the first leap second ๐ฅน.
Local Time: Civil time for a particular location ๐. Its offset from universal time can depend on the date and time of day ๐ฐ๏ธ.
POSIX Epoch: 1970-01-01 00:00:00 UTC, which is the basis for absolute timestamps in this document ๐.
Standard Time: The time according to a location's law or practice, without any daylight saving adjustment ๐ง.
Time Change: A change to civil timekeeping practice ๐. It happens when one or more of the following occur simultaneously:
- a change in UT offset
- a change in whether daylight saving time is in effect
- a change in time zone abbreviation
- a leap second (i.e., a change in LEAPCORR)
Time Zone Data: The Time Zone Data Distribution Service (TZDIST) [RFC7808] defines "Time zone data" as "data that defines a single time zone, including an identifier, UTC offset values, DST rules, and other information such as time zone abbreviations". The interchange format defined in this document is one such form of time zone data ๐บ๏ธ.
Transition Time: The moment a time change occurs that is not a leap second โฐ. It's identified with a signed integer count of UNIX leap time seconds since the POSIX epoch ๐ข.
Universal Time (UT): The basis of civil time ๐. For timestamps before UTC was introduced in 1960, this is the principal form of mean solar time at the prime meridian (0 degrees longitude). For timestamps after that, it's UTC ๐. Other sources sometimes call UT "UTC" or "GMT", but this specification uses the term "UT" to avoid confusion with UTC or with GMT ๐ โโ๏ธ.
UNIX Time: The time returned by the time() function provided by the C programming language (see Section 3 of the "System Interfaces" volume of [POSIX]) ๐พ. It's an integer number of seconds since the POSIX epoch, not counting leap seconds. As an extension to POSIX, negative values represent times before the POSIX epoch, using UT ๐.
UNIX Leap Time: UNIX time plus all preceding leap-second corrections ๐งฉ. For example, if the first leap-second record in a TZif file occurs at 1972-06-30 23:59:60 UTC, the UNIX leap time for the timestamp 1972-07-01 00:00:00 UTC would be 78796801, which is one greater than the UNIX time for the same timestamp ๐ญ. Similarly, if the second leap-second record occurs at 1972-12-31 23:59:60 UTC, it accounts for the first leap second. So the UNIX leap time of 1972-12-31 23:59:60 UTC would be 94694401, and the UNIX leap time of 1973-01-01 00:00:00 UTC would be 94694402 ๐ฅณ. If a TZif file specifies no leap-second records, UNIX leap time is equal to UNIX time ๐ธ.
Wall Time: Another name for local time, short for "wall-clock time" ๐งฑ.
3. The Time Zone Information Format (TZif) โจ
okay so TZif starts with a fixed 44-octet version 1 header (Section 3.1) and one of its fields tells you which version of the format the file is using ๐ง. the cute part is that readers built for version N can usually handle version N+1 files without much drama. the newer stuff either sits after the version N data so older readers can just skip what they don't understand, or it's a small extension to version N that version N readers will probably tolerate just fine ๐
the version 1 header is followed by a variable-length version 1 data block (Section 3.2). that block holds four-octet (32-bit) transition times and leap-second occurrences ๐ฆ those 32-bit values can only cover time changes from 1901-12-13 20:45:52 through 2038-01-19 03:14:07 UT. the version 1 header and data block are only there for backward compatibility with obsolescent readers, which is covered in "Common Interoperability Issues" (Appendix A) ๐
version 1 files end right after the version 1 data block ๐ files from versions 2 and higher add a second 44-octet version 2+ header, a variable-length version 2+ data block with eight-octet (64-bit) transition times and leap-second occurrences, and a variable-length footer (Section 3.3). those 64-bit values can represent times roughly 292 billion years into the past or future ๐คฏ literally unhinged scale, iykyk.
NOTE: All multi-octet integer values MUST be stored in network octet order format (high-order octet first, otherwise known as big-endian), with all bits significant. Signed integer values MUST be represented using two's complement. ๐ซถ
this is the layout of a TZif file, bestie ๐
Version 1 Versions 2+
+-------------+ +-------------+
| Version 1 | | Version 1 |
| Header | | Header |
+-------------+ +-------------+
| Version 1 | | Version 1 |
| Data Block | | Data Block |
+-------------+ +-------------+
| Version 2+ |
| Header |
+-------------+
| Version 2+ |
| Data Block |
+-------------+
| Footer |
+-------------+
Figure 1: General Format of TZif Files
3.1. TZif Header ๐
the TZif header is laid out like this (the lengths of multi-octet fields are in parentheses) ๐ฆ
+---------------+---+
| magic (4) |ver|
+---------------+---+---------------------------------------+
| [unused - reserved for future use] (15) |
+---------------+---------------+---------------+-----------+
| isutcnt (4) | isstdcnt (4) | leapcnt (4) |
+---------------+---------------+---------------+
| timecnt (4) | typecnt (4) | charcnt (4) |
+---------------+---------------+---------------+
Figure 2: TZif Header
here's what each field does ๐
- magic: a four-octet ASCII [RFC20] sequence
"TZif"(0x54 0x5A 0x69 0x66), which tells you the file uses the Time Zone Information Format ๐ฅ - ver(sion): one octet that identifies the version of the file's format. the value MUST be one of the following:
- NUL (
0x00) Version 1 - the file contains only the version 1 header and data block. Version 1 files MUST NOT contain a version 2+ header, data block, or footer. ๐ธ '2'(0x32) Version 2 - the file MUST contain the version 1 header and data block, a version 2+ header and data block, and a footer. The TZ string in the footer (Section 3.3), if non-empty, MUST strictly adhere to the requirements for the TZ environment variable as defined in Section 8.3 of the "Base Definitions" volume of [POSIX] and MUST encode the POSIX portable character set as ASCII. The leap-second records MUST NOT be truncated at the start (Section 6.1) and MUST NOT contain an expiration time. ๐'3'(0x33) Version 3 - the file MUST conform to all version 2 requirements, except that any TZ string in the footer (Section 3.3) MAY use the TZ string extension described below (Section 3.3.2). โจ'4'(0x34) Version 4 - the file MUST conform to all version 3 requirements, except that the leap-second records MAY be truncated at the start and MAY contain an expiration time. ๐ฆ
- NUL (
- isutcnt: a four-octet unsigned integer specifying the number of UT/local indicators contained in the data block. It MUST either be zero or equal to "typecnt". ๐ซง
- isstdcnt: a four-octet unsigned integer specifying the number of standard/wall indicators contained in the data block. It MUST either be zero or equal to "typecnt". ๐
- leapcnt: a four-octet unsigned integer specifying the number of leap-second records contained in the data block. ๐
- timecnt: a four-octet unsigned integer specifying the number of transition times contained in the data block. โญ
- typecnt: a four-octet unsigned integer specifying the number of local time type records contained in the data block. It MUST NOT be zero. (Although local time type records convey no useful information in files that have non-empty TZ strings but no transitions, at least one such record is nevertheless required because many TZif readers reject files that have zero time types.) ๐
- charcnt: a four-octet unsigned integer specifying the total number of octets used by the set of time zone designations contained in the data block. It MUST NOT be zero. The count includes the trailing NUL (
0x00) octet at the end of the last time zone designation. ๐
ngl the version 1 and 2+ headers have the exact same format, magic number, and version fields ๐ but their count fields can be different, because the version 1 data can be a subset of the version 2+ data. main character differences, lowkey ๐
3.2. TZif Data Block โจ
okay bestie, a TZif data block is made of seven variable-length elements ๐, and each one is just a series of items. The header's count fields tell you how many items each series has. Multiply that number by the size of each item and boom, you get the total length of the element ๐งฎ. This is lowkey so useful, because if you don't wanna parse or use the version 1 data block, you can work out its total length and skip straight to the header of the version 2+ data block ๐ฆ.
In the version 1 data block, time values are 32 bits (TIME_SIZE = 4 octets). In the version 2+ data block, which only shows up in version 2 and higher files, time values are 64 bits (TIME_SIZE = 8 octets) ๐.
Here's how the data block is laid out (the lengths of multi-octet fields are in parentheses, obviously ๐):
+---------------------------------------------------------+
| transition times (timecnt x TIME_SIZE) |
+---------------------------------------------------------+
| transition types (timecnt) |
+---------------------------------------------------------+
| local time type records (typecnt x 6) |
+---------------------------------------------------------+
| time zone designations (charcnt) |
+---------------------------------------------------------+
| leap-second records (leapcnt x (TIME_SIZE + 4)) |
+---------------------------------------------------------+
| standard/wall indicators (isstdcnt) |
+---------------------------------------------------------+
| UT/local indicators (isutcnt) |
+---------------------------------------------------------+
Figure 3: TZif Data Block
Now let's go through the elements of the data block, one by one ๐ :
- transition times: This is a series of four- or eight-octet UNIX leap time values, sorted in strictly ascending order. Each value is used as a transition time, which is a moment when the rules for computing local time may change. The number of time values is set by the "timecnt" field in the header. Each time value SHOULD be at least -2^59. (-2^59 is the greatest negated power of 2 that predates the Big Bang, and avoiding earlier timestamps works around known TZif reader bugs with outlandishly negative timestamps ๐.)
- transition types: This is a series of one-octet unsigned integers that tell you the type of local time for the matching transition time. These values act as zero-based indices into the array of local time type records. The number of type indices is set by the "timecnt" field in the header. Each type index MUST be in the range [0, "typecnt" - 1].
- local time type records: This is a series of six-octet records, each one specifying a local time type. The number of records is set by the "typecnt" field in the header. Each record looks like this (the lengths of multi-octet fields are in parentheses):
+---------------+---+---+
| utoff (4) |dst|idx|
+---------------+---+---+
- utoff: A four-octet signed integer giving the number of seconds to add to UT to get local time. The value MUST NOT be -2^31 and SHOULD be in the range [-89999, 93599], which means it SHOULD be more than -25 hours and less than 26 hours ๐. Skipping -2^31 lets 32-bit clients negate the value without overflow. Keeping it inside [-89999, 93599] makes it easy for implementations that already support the POSIX-required range [-24:59:59, 25:59:59] โจ.
- (is)dst: A one-octet value saying whether local time should count as Daylight Saving Time (DST). The value MUST be 0 or 1. A one (1) means this time type is DST, and a zero (0) means it's standard time ๐ธ.
- (desig)idx: A one-octet unsigned integer that's a zero-based index into the series of time zone designation octets, which picks out one designation string. Each index MUST be in the range [0, "charcnt" - 1]. It points at the NUL-terminated string of octets starting at position "idx" in the time zone designations. (This string MAY be empty.) A NUL octet MUST exist in the time zone designations at or after position "idx". If the designation string is "-00", the time type is a placeholder meaning local time is unspecified ๐.
- time zone designations: This is a series of octets that forms an array of NUL-terminated (0x00) time zone designation strings. The total number of octets is set by the "charcnt" field in the header. Two designations MAY overlap if one is a suffix of the other. The character encoding of time zone designation strings isn't specified, but check out Section 4 of this document for more on that ๐.
- leap-second records: This is a series of eight- or twelve-octet records that specify the corrections that need to be applied to UTC to get TAI, also known as the leap-second table ๐ง. The records are sorted by occurrence time in strictly ascending order. The number of records is set by the "leapcnt" field in the header. Each record has one of these two structures (the lengths of multi-octet fields are in parentheses):
Version 1 Data Block:
+---------------+---------------+
| occur (4) | corr (4) |
+---------------+---------------+
version 2+ Data Block:
+---------------+---------------+---------------+
| occur (8) | corr (4) |
+---------------+---------------+---------------+
- occur(rence): A four- or eight-octet UNIX leap time value that marks when a leap-second correction happens, or when the leap-second table expires. The first value, if there is one, MUST be non-negative, and each leap second MUST occur at the end of a UTC month ๐.
- corr(ection): A four-octet signed integer giving the value of LEAPCORR on or after the occurrence. If "leapcnt" is zero, LEAPCORR is zero for all timestamps. If "leapcnt" is nonzero, then for timestamps before the first occurrence time, LEAPCORR is zero if the first correction is one (1) or minus one (-1). Otherwise it's unspecified, which can only happen in files truncated at the start (Section 6.1) ๐ญ.
The first leap second is a positive leap second if and only if its correction is positive. Each correction after the first MUST differ from the previous correction by either one (1) for a positive leap second or minus one (-1) for a negative leap second. The exception is version 4 files with two or more leap-second records: there, the correction values of the last two records MAY be the same, and the occurrence of the last record tells you when the leap-second table expires โญ.
The leap-second table expiration time is the point when the table stops recording whether future leap-second corrections happen or don't happen. After that, timestamps can't be calculated accurately. For example, a leap-second table published in January that predicts whether there's a leap second at the end of June might expire in mid-December, because nobody knows yet when the next leap second will happen ๐.
If leap seconds get permanently discontinued, as the General Conference on Weights and Measures [CGPM-2022-R4] has requested, then leap-second tables published after the discontinuation time SHOULD NOT expire. They won't be updated in the foreseeable future, so expiring them makes no sense ๐ฆ.
- standard/wall indicators: This is a series of one-octet values showing whether the transition times for local time types were specified as standard time or wall-clock time. Each value MUST be 0 or 1. A one (1) means standard time, and a zero (0) means wall time. The value MUST be set to one (1) if the matching UT/local indicator is set to one (1). The number of values is set by the "isstdcnt" field in the header. If "isstdcnt" is zero (0), all transition times for local time types are assumed to be wall time ๐.
- UT/local indicators: This is a series of one-octet values showing whether the transition times for local time types were specified as UT or local time. Each value MUST be 0 or 1. A one (1) means UT, and the matching standard/wall indicator MUST also be set to one (1). A zero (0) means local time. The number of values is set by the "isutcnt" field in the header. If "isutcnt" is zero (0), all transition times for local time types are assumed to be local time ๐.
Here's how it all clicks together โจ: the type matching a transition time tells you the local time for timestamps starting at that transition time and running up to, but not including, the next transition time. Local time for timestamps before the first transition comes from the first time type (time type 0). Local time for timestamps on or after the last transition comes from the TZ string in the footer (Section 3.3) if one is present and non-empty. Otherwise, it's unspecified. If there are no transitions at all, local time for every timestamp comes from the TZ string in the footer if it's present and non-empty. If not, it comes from time type 0. A time type with a designation string of "-00" stands for unspecified local time ๐ซถ.
A given pair of standard/wall and UT/local indicators says whether the matching transition time was specified as UT, standard time, or wall-clock time. There are only three combinations of the two indicators, because the standard/wall value MUST be one (1) whenever the UT/local value is one (1) ๐ฅ. This info helps when transition times in a TZif file need to be turned into transitions for another time zone, like when you're working out transition times for a simple POSIX-like TZ string such as "AKST9AKDT" ๐.
To cut out unused space in a TZif file, every nonzero local time type index SHOULD appear at least once in the transition type array. Likewise, every octet in the time zone designations array SHOULD be used by at least one time type record ๐ โจ.
3.3. TZif Footer โจ
okay so the TZif footer is structured like this (the lengths of multi-octet fields are in parentheses, bestie ๐):
+---+--------------------+---+
| NL| TZ string (0...) |NL |
+---+--------------------+---+
Figure 4: TZif Footer
here's what each piece does ๐
- NL: an ASCII new line character (
0x0A) ๐ - TZ string: a rule for computing local time changes after the last transition time stored in the version 2+ data block ๐ฐ๏ธ The string is either empty or uses the expanded format of the
TZenvironment variable from Section 8.3 of the "Base Definitions" volume of [POSIX], with ASCII encoding. In version 3 and higher files, it can also use the extension in Section 3.3.2. If the string is empty, the info just isn't available. If the string is non-empty and one or more transitions show up in the version 2+ data, the string MUST be consistent with the last version 2+ transition. Put another way, evaluating the TZ string at the time of the last transition should give you the same time type that was specified in the last transition. The string MUST NOT contain NUL octets or be NUL-terminated, and it SHOULD NOT begin with the ":" (colon) character. no notes, just rules ๐ โโ๏ธ
the footer only shows up in version 2 and higher files, since the old version 1 format was designed before anyone realized a footer was needed ๐ฅน
3.3.1. All-Year Daylight Saving Time ๐
DST counts as in effect all year if its UT offset is less than (i.e., west of) the standard time offset. It starts January 1 at 00:00 and ends December 31 at 24:00 minus the difference between standard and daylight saving time, so there's no room left for standard time on the calendar at all ๐ญ [POSIX] kinda implies this but never actually says it, so it gets spelled out here for clarity โจ
Example: XXX3EDT4,0/0,J365/23 This is a time zone that's perpetually 4 hours west of UT, abbreviated "EDT". The "XXX" gets ignored, bestie ๐
3.3.2. TZ String Extension ๐ฎ
the TZ string in a version 3 or higher TZif file MAY use the following extension to POSIX TZ strings. It's described using the terminology from Section 8.3 of the "Base Definitions" volume of [POSIX] ๐ง
the hours part of the transition times may be signed and can range from -167 through 167 (-167 <= hh <= 167), instead of the POSIX-required unsigned values from 0 through 24. so much more flexibility, it's giving main character energy ๐
Example: <-03>3<-02>,M3.5.0/-2,M10.5.0/-1 This is a time zone that observes daylight saving time from 22:00 on the day before March's last Sunday until 23:00 on the day before October's last Sunday. Standard time is 3 hours west of UT and abbreviated "-03", and daylight saving time is 2 hours west of UT and abbreviated "-02" ๐ธ
a TZif file that uses the extension above MUST be designated as version 3 (or higher), even if a future version of POSIX adopts this extension. no exceptions, periodt ๐
4. Interoperability Considerations ๐ซถ
these practices help keep TZif applications interoperating, so pay attention ๐ฆ
- Version 1 files are considered a legacy format and SHOULD NOT be generated, since they don't support transition times after the year 2038 ๐
- Readers that only understand version 1 MUST ignore any data that extends beyond the calculated end of the version 1 data block.
- Other than version 1, writers SHOULD generate the lowest version number that a file's data needs. This helps with interoperability with older readers โจ For example, a writer SHOULD generate a version 4 file only if its leap-second table either expires or gets truncated at the start. Likewise, a writer that isn't generating a version 4 file SHOULD generate a version 3 file only if the TZ string extension is necessary to model transition times accurately.
- To save space, writers of version 2+ files MAY output a placeholder version 1 data block with all counts at zero, except that "typecnt" and "charcnt" are both one (1). If this is done, obsolescent version-1-only readers MUST interpret these files as lacking time changes and time zone abbreviations ๐ฅบ
- Unless the version 1 data block is a placeholder, the sequence of timestamps defined by the version 1 header and data block SHOULD be a contiguous sub-sequence of the timestamps defined by the version 2+ header and data block and by the footer. This helps obsolescent version 1 readers agree with current readers about timestamps in that contiguous sub-sequence ๐ค
- When a TZif file contains a leap-second table expiration time, TZif readers SHOULD either refuse to process post-expiration timestamps or process them as if the expiration time didn't exist (possibly with an error indication). This cuts down on disagreement between implementations when they process far-future timestamps that can't be handled exactly yet ๐ญ
- Time zone designations MUST consist of at least three (3) and no more than six (6) ASCII characters from the set of alphanumerics, "-", and "+". This is compatible with POSIX requirements for time zone abbreviations ๐
- A reader that runs into a time zone designation with bytes other than ASCII alphanumerics, "-", and "+" SHOULD act as if the designation instead contained a signed numeric string derived from the UT offset. For example, "-10" and "+0530" mean 10 hours west and 5.5 hours east of Greenwich, respectively ๐
- When reading a version 2 or higher file, readers SHOULD ignore the version 1 header and data block, except for skipping over them. This improves compatibility among readers of non-conforming files, where version 2+ data isn't upward compatible with version 1 ๐ง
- Readers SHOULD calculate the total lengths of the headers and data blocks and check that they all fit within the actual file size, as part of a validity check for the file โ
- When a TZif file is used in a MIME message entity, it SHOULD be indicated by one of the following media types:
application/tzif-leap(Section 9.2) indicates that leap-second records are included in the TZif data as necessary. (None are necessary if the file is truncated to a range that comes before the first leap second.)application/tzif(Section 9.1) indicates that leap-second records are not included in the TZif data. "leapcnt" in the header(s) MUST be zero (0) ๐ซง
- Common interoperability issues and possible workarounds are described in Appendix A ๐
5. Internationalization Considerations ๐
TZif time zone designations contain only ASCII alphanumerics, "-", and "+". Commonly used designations include numeric strings like "-10" and "+0530" for UT offsets, plus English language abbreviations like "CEST" for Central European Summer Time and "GMT" for Greenwich Mean Time ๐ฌ๐ง It's the TZif reader's job to swap in different abbreviations when needed for internationalization, like substituting "HNC" (l'heure normale du Centre) for "CST" (Central Standard Time) in French-speaking regions ๐ฅ This substitution can get messy, though, because abbreviations can be ambiguous. For example, "CST" commonly stands for China Standard Time and Cuba Standard Time as well as Central Standard Time ๐ตโ๐ซ One approach to this issue can be found in the time zone charts of the Unicode Common Locale Data Repository (CLDR) Project [CLDR] ๐บ๏ธ
the original TZif design allowed any nonzero octets in time zone designations, and it was common practice until the mid-1990s for designations to contain ASCII spaces. Designations are now limited to ASCII alphanumerics, "-", and "+" to avoid confusion and to make things more portable across a wide variety of locales ๐ธ
6. Use with the Time Zone Data Distribution Service ๐ง
The Time Zone Data Distribution Service (TZDIST) [RFC7808] is a service that delivers time zone data and leap-second rules to client systems, like calendaring and scheduling apps or operating systems, reliably, securely, and fast ๐
a TZDIST service MAY supply time zone data to clients in the Time Zone Information Format. If it does, it MUST indicate that it supports this format by including the media type "application/tzif" (Section 9.1) in its "capabilities" response (Section 5.1 of [RFC7808]). A TZDIST service MAY also include the media type "application/tzif-leap" (Section 9.2) in its "capabilities" response if it can generate TZif files containing leap-second records. A TZDIST service MUST NOT advertise the "application/tzif-leap" media type without also advertising "application/tzif" ๐ โโ๏ธ
TZDIST clients MUST use the HTTP Accept header field ([RFC9110], Section 12.5.1) to say which formats they'd prefer to receive data in: "application/tzif" and/or "application/tzif-leap" ๐
6.1. Truncating TZif Files โ๏ธ
As described in Section 3.9 of [RFC7808], a TZDIST service MAY truncate time zone transition data. A truncated TZif file is valid from its first transition time up to, but not including, its last version 2+ transition time, if one is present ๐ซถ
when truncating the start of a TZif file, the service MUST supply in the version 2+ data a first transition time that is the start point of the truncation range. Just like untruncated TZif files, time type 0 indicates local time immediately before the start point, and the time type of the first transition indicates local time after that. Time type 0 MUST be a placeholder indicating that local time is unspecified, so the reader knows for sure that truncation happened at the start ๐ซฃ
when truncating the start of a TZif file containing leap-second records, the service MUST keep all leap-second records that govern timestamps within the truncation range, even if the first such record comes before the start point of the truncation range. If the truncated leap-second table is non-empty, its first record MUST have a positive correction if and only if it represents a positive leap second โญ
when truncating the end of a TZif file, the service MUST supply in the version 2+ data a last transition time that is the end point of the truncation range, and MUST supply an empty TZ string. Like untruncated TZif files with empty TZ strings, a truncated TZif file doesn't indicate local time after the last transition. So the time type of the last transition MUST be a placeholder indicating that local time is unspecified ๐ฅ
all represented information that falls inside the truncation range MUST be the same as the information represented by a corresponding untruncated TZif file. Super important, bestie ๐
TZDIST clients SHOULD NOT use a truncated TZif file (as described above) to interpret timestamps outside the truncation time range ๐ซโจ
6.2. Example TZDIST Request for TZif Data ๐
okay so this example is giving "client meets server" ๐ The client first asks the server what formats it supports, then asks for one specific time zone identifier and gets it back as TZif. ๐ฆ
This example presumes that the time zone context path has been discovered (see [RFC7808], Section 4.2.1) to be /tzdist. ๐ง
Request <<
GET /tzdist/capabilities HTTP/1.1
Host: tz.example.com
Response <<
HTTP/1.1 200 OK
Date: Fri, 01 Jun 2018 14:52:23 GMT
Content-Type: application/json
Content-Length: xxxx
{
"version": 1,
"info": {
"primary-source": "IANA:2018e",
"formats": [
"text/calendar",
"application/tzif",
"application/tzif-leap"
],
...
},
...
}
Request <<
GET /tzdist/zones/America%2FNew_York HTTP/1.1
Host: tz.example.com
Accept: application/tzif
Response <<
HTTP/1.1 200 OK
Date: Fri, 01 Jun 2018 14:52:24 GMT
Content-Type: application/tzif
Content-Length: xxxx
ETag: "123456789-000-111"
TZif2...[binary data without leap-second records]...
EST5EDT,M3.2.0,M11.1.0
7. Security Considerations ๐
okay the security part is SERIOUS and I'm not playing ๐ญ TZif has no executable code, and it doesn't define any extensible areas where code could hide. Very safe, very cute. ๐
TZif uses counted arrays of data elements. All counts should be checked when processing TZif objects, so nobody reads past the end of the object. ๐จ Please count your arrays, bestie. ๐
TZif provides no confidentiality or integrity protection. Time zone information is normally public, so it doesn't really need confidentiality. But time zone info runs lots of critical apps, so integrity protection may be required, and it must be provided externally. ๐ก๏ธ
As discussed in Section 8 of [RFC7808], sending time zone data over an insecure channel could get it tampered with, and that would mess up calendaring and scheduling. ๐ฑ So TZif data sent over a public communications channel MUST be protected with a security layer, like the one Transport Layer Security (TLS) [RFC8446] gives you. ๐ No shortcuts, periodt. ๐
8. Privacy Considerations ๐
TZif contains publicly available data, and it doesn't define any extensible areas that could be used to store private data. โจ
As discussed in Section 9 of [RFC7808], sending time zone data over an insecure communications channel could leak the past, current, or future location of a device or user. ๐ Yikes. So TZif data sent over a public communications channel MUST be protected with a confidentiality layer, like the one Transport Layer Security (TLS) [RFC8446] provides. ๐ซถ
9. IANA Considerations ๐ธ
IANA has updated the "Media Types" registry (https://www.iana.org/assignments/media-types) as follows. ๐
This document defines two media types [RFC6838] for exchanging data with the Time Zone Information Format. ๐ฆ
9.1. application/tzif ๐
Here's the registration template for application/tzif, copied exactly:
Type name: application
Subtype name: tzif
Required parameters: N/A
Optional parameters: N/A
Encoding considerations: binary
Security considerations: See Section 7 of RFC 9636.
Interoperability considerations: See Section 4 of RFC 9636.
Published specification: RFC 9636.
Applications that use this media type: This media type is designed
for widespread use by applications that need to use or exchange
time zone information relative to UNIX time, such as the Time Zone
Information Compiler (zic) [ZIC] and the GNU C Library [GNU-C].
The Time Zone Distribution Service [RFC7808] can directly use this
media type.
Fragment identifier considerations: N/A
Additional information:
Magic number(s): The first 4 octets are 0x54, 0x5A, 0x69, 0x66
File extensions(s): N/A
Macintosh file type code(s): N/A
Person & email address to contact for further information: Time Zone
Database mailing list <tz@iana.org>
Intended usage: COMMON
Restrictions on usage: N/A
Author: See the "Authors' Addresses" section of RFC 9636.
Change controller: IETF
9.2. application/tzif-leap ๐
Same vibe, but this one is for the leap-time version. Here's the template, verbatim:
Type name: application
Subtype name: tzif-leap
Required parameters: none
Optional parameters: none
Encoding considerations: binary
Security considerations: See Section 7 of RFC 9636.
Interoperability considerations: See Section 4 of RFC 9636.
Published specification: RFC 9636.
Applications that use this media type: This media type is designed
for widespread use by applications that need to use or exchange
time zone information relative to UNIX leap time, such as the Time
Zone Information Compiler (zic) [ZIC] and the GNU C Library
[GNU-C]. The Time Zone Distribution Service [RFC7808] can
directly use this media type.
Fragment identifier considerations: N/A
Additional information:
Magic number(s): The first 4 octets are 0x54, 0x5A, 0x69, 0x66
File extensions(s): N/A
Macintosh file type code(s): N/A
Person & email address to contact for further information: Time Zone
Database mailing list <tz@iana.org>
Intended usage: COMMON
Restrictions on usage: N/A
Author: See the "Authors' Addresses" section of RFC 9636.
Change controller: IETF
10. References ๐
10.1. Normative References ๐
These are the must-read ones, the foundations of the whole spec. ๐ง
[GNU-C] Free Software Foundation, "The GNU C Library",
<https://www.gnu.org/software/libc/>.
[ITU-R-TF.460]
International Telecommunication Union, "Standard-frequency
and time-signal emissions", ITU-R Recommendation TF.460,
February 2002, <https://www.itu.int/rec/R-REC-TF.460/en>.
[POSIX] IEEE, "IEEE Standard for Information Technology--Portable
Operating System Interface (POSIX(TM)) Base
Specifications, Issue 7", POSIX.1-2017, IEEE
Std 1003.1-2017, DOI 10.1109/IEEESTD.2018.8277153, January
2018, <https://pubs.opengroup.org/onlinepubs/9699919799/>.
[RFC20] Cerf, V., "ASCII format for network interchange", STD 80,
RFC 20, DOI 10.17487/RFC0020, October 1969,
<https://www.rfc-editor.org/info/rfc20>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type
Specifications and Registration Procedures", BCP 13,
RFC 6838, DOI 10.17487/RFC6838, January 2013,
<https://www.rfc-editor.org/info/rfc6838>.
[RFC7808] Douglass, M. and C. Daboo, "Time Zone Data Distribution
Service", RFC 7808, DOI 10.17487/RFC7808, March 2016,
<https://www.rfc-editor.org/info/rfc7808>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP Semantics", STD 97, RFC 9110,
DOI 10.17487/RFC9110, June 2022,
<https://www.rfc-editor.org/info/rfc9110>.
[ZIC] Kerrisk, M., "zic(8) - Linux manual page",
<http://man7.org/linux/man-pages/man8/zic.8.html>.
10.2. Informative References ๐
These are the nice-to-know extras that give helpful background. โจ
[CGPM-2022-R4]
General Conference on Weights and Measures, "Resolution 4
of the 27th CGPM (2022)", DOI 10.59161/CGPM2022RES4E,
November 2022,
<https://www.bipm.org/en/cgpm-2022/resolution-4>.
[CLDR] Unicode, Inc., "Unicode CLDR Project",
<https://cldr.unicode.org/>.
[EGGERT-TZ]
"History for tz", commit b5318b5, June 2024,
<https://github.com/eggert/tz/commits/main/tzfile.5>.
[Err6426] RFC Errata, "Erratum ID 6426", RFC 8536,
<https://www.rfc-editor.org/errata/eid6426>.
[Err6435] RFC Errata, "Erratum ID 6435", RFC 8536,
<https://www.rfc-editor.org/errata/eid6435>.
[Err6757] RFC Errata, "Erratum ID 6757", RFC 8536,
<https://www.rfc-editor.org/errata/eid6757>.
[Err7681] RFC Errata, "Erratum ID 7681", RFC 8536,
<https://www.rfc-editor.org/errata/eid7681>.
[RFC5545] Desruisseaux, B., Ed., "Internet Calendaring and
Scheduling Core Object Specification (iCalendar)",
RFC 5545, DOI 10.17487/RFC5545, September 2009,
<https://www.rfc-editor.org/info/rfc5545>.
[RFC6557] Lear, E. and P. Eggert, "Procedures for Maintaining the
Time Zone Database", BCP 175, RFC 6557,
DOI 10.17487/RFC6557, February 2012,
<https://www.rfc-editor.org/info/rfc6557>.
[RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
<https://www.rfc-editor.org/info/rfc8446>.
[RFC8536] Olson, A., Eggert, P., and K. Murchison, "The Time Zone
Information Format (TZif)", RFC 8536,
DOI 10.17487/RFC8536, February 2019,
<https://www.rfc-editor.org/info/rfc8536>.
[tz-link] Eggert, P. and A. Olson, "Time zone and daylight saving
time data",
<https://www.iana.org/time-zones/repository/tz-link.html>.
Appendix A. Common Interoperability Issues โจ
okay bestie, this section is basically the "things that bit people in the wild" list ๐ Most of these are problems with writing TZif files for readers that follow older versions of the spec [EGGERT-TZ]. The goals are to help:
- TZif writers output files that dodge common pitfalls in older or buggy TZif readers,
- TZif readers avoid common pitfalls when reading files from future TZif writers, and
- any future spec authors see what kinds of problems pop up when the TZif format changes ๐
when new TZif versions got defined, the big design goal was that a reader could still use a file even if it's a later version than the reader was built for ๐ซถ when full compatibility wasn't possible, they tried to keep the glitches to rarely used timestamps and let writers make simple partial workarounds so newer-version data is still useful to older-version readers. this section documents those compatibility issues and workarounds, plus other common reader bugs, so nobody has to rediscover them the hard way ๐ญ
Here are the interoperability problems with TZif:
- Some readers only look at version 1 data. As a partial workaround, a writer can output as much version 1 data as possible. However, a reader should ignore version 1 data and use version 2+ data, even if the reader's timestamps have only 32 bits. ๐ธ
- Some readers designed for version 2 might mishandle timestamps after a version 3 or higher file's last transition, because they can't parse extensions to POSIX in the TZ-like string. As a partial workaround, a writer can output more transitions than necessary, so that only far-future timestamps get mishandled by version 2 readers. ๐ฎ
- Some readers designed for version 2 don't support permanent daylight saving time with transitions after 24:00. For example, the TZ string
EST5EDT,0/0,J365/25denotes permanent Eastern Daylight Time (-04), and those readers will choke on it ๐ As a workaround, a writer can substitute standard time for two time zones east. For instance,XXX3EDT4,0/0,J365/23covers a time zone with a never-used standard time (XXX, -03) and negative daylight saving time (EDT, -04) all year. Alternatively, as a partial workaround, a writer can substitute standard time for the next time zone east, likeAST4for permanent Atlantic Standard Time (-04). ๐ง - Some readers designed for version 2 or 3 that require strict conformance to [RFC8536] reject version 4 files whose leap-second tables are truncated at the start or end in expiration times. ๐
- Some readers ignore the footer and instead predict future timestamps from the time type of the last transition. As a partial workaround, a writer can output more transitions than necessary. ๐
- Some readers don't use time type 0 for timestamps before the first transition, because they infer a time type with a heuristic that doesn't always pick time type 0. As a partial workaround, a writer can output a placeholder (no-op) first transition at an early time. ๐
- Some readers mishandle timestamps before the first transition that has a timestamp that is not less than
-2^31. Readers that only support 32-bit timestamps are more likely to have this problem, for example when they process 64-bit transitions, only some of which fit in 32 bits. As a partial workaround, a writer can output a placeholder transition at timestamp-2^31. ๐ - Some readers mishandle a transition if its timestamp has the minimum possible signed 64-bit value. Timestamps less than
-2^59are not recommended. โญ - Some readers mishandle POSIX-style TZ strings that contain "<" or ">". As a partial workaround, a writer can avoid using "<" or ">" for time zone abbreviations that contain only alphabetic characters. ๐
- Many readers mishandle time zone abbreviations that contain non-ASCII characters. These characters are not recommended. ๐ซ
- Some readers may mishandle time zone abbreviations that contain fewer than 3 or more than 6 characters, or that contain ASCII characters other than alphanumerics, "-", and "+". These abbreviations are not recommended. ๐
- This specification doesn't dictate how readers should deal with timestamps when local time is unspecified. Common practice is for readers to report UT with designation string "-00". A reader could return an error indication instead. ๐คทโโ๏ธ
- Some readers mishandle TZif files that specify daylight saving time UT offsets that are less than the UT offsets for the corresponding standard time. These readers don't support locations like Ireland, which uses the equivalent of the POSIX TZ string
IST-1GMT0,M10.5.0,M3.5.0/1, observing standard time (IST, +01) in summer and daylight saving time (GMT, +00) in winter. As a partial workaround, a writer can output data for the equivalent of the POSIX TZ stringGMT0IST,M3.5.0/1,M10.5.0, thus swapping standard and daylight saving time. Although this workaround misidentifies which part of the year uses daylight saving time, it records UT offsets and time zone abbreviations correctly. ๐ - Some readers generate ambiguous timestamps for positive leap seconds that occur when the UTC offset is not a multiple of 60 seconds. For example, with UTC offset +01:23:45 and a positive leap second 78796801 (1972-06-30 23:59:60 UTC), some readers map both 78796800 and 78796801 to 01:23:45 local time the next day instead of mapping the latter to 01:23:46. They also map 78796815 to 01:23:59 instead of to 01:23:60. This hasn't been a practical problem yet, since no civil authority has observed such UTC offsets since leap seconds were introduced in 1972. ๐ฐ๏ธ
Some interoperability problems are reader bugs. They're listed here mostly as warnings to reader developers ๐ฃ
- Some readers don't support negative timestamps. Developers of distributed applications should keep this in mind if they need to deal with pre-1970 data. ๐ฐ๏ธ
- Some readers mishandle timestamps before the first transition that has a non-negative timestamp. Readers that don't support negative timestamps are more likely to have this problem. ๐ฌ
- Some readers mishandle time zone abbreviations like "-08" that contain "+", "-", or digits. ๐
- Some readers mishandle UT offsets that are outside the conventional range of -12 through +12 hours, and so don't support locations like Kiritimati that sit outside this range. ๐๏ธ
- Some readers mishandle UT offsets in the range
[-3599, -1]seconds from UT, because they integer-divide the offset by 3600 to get 0 and then display the hour part as "+00". ๐ - Some readers mishandle UT offsets that aren't a multiple of one hour, 15 minutes, or 1 minute. ๐ซ
Appendix B. Example TZif Files ๐ฆ
The following sections contain annotated hexadecimal dumps of example TZif files.
These examples should only be considered informative. Although the example data entries are current as of the publication date of this document, the data will likely change in the future as leap seconds are added and changes are made to civil time. ๐
B.1. Version 1 File Representing UTC (with Leap Seconds) ๐ธ
Okay bestie, the leap-second parade keeps going ๐โจ
+========+=============+==================+========================+
| File | Hexadecimal | Record Name / | Field Value |
| Offset | Octets | Field Name | |
+========+=============+==================+========================+
| 000 | 54 5a 69 66 | magic | "TZif" |
+--------+-------------+------------------+------------------------+
| 004 | 00 | version | 0 (1) |
+--------+-------------+------------------+------------------------+
| 005 | 00 00 00 00 | |
| | 00 00 00 00 | |
| | 00 00 00 00 | |
| | 00 00 00 | |
+--------+-------------+------------------+------------------------+
| 020 | 00 00 00 01 | isutcnt | 1 |
+--------+-------------+------------------+------------------------+
| 024 | 00 00 00 01 | isstdcnt | 1 |
+--------+-------------+------------------+------------------------+
| 028 | 00 00 00 1b | leapcnt | 27 |
+--------+-------------+------------------+------------------------+
| 032 | 00 00 00 00 | timecnt | 0 |
+--------+-------------+------------------+------------------------+
| 036 | 00 00 00 01 | typecnt | 1 |
+--------+-------------+------------------+------------------------+
| 040 | 00 00 00 04 | charcnt | 4 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[0] | |
+--------+-------------+------------------+------------------------+
| 044 | 00 00 00 00 | utoff | 0 (+00:00) |
+--------+-------------+------------------+------------------------+
| 048 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 049 | 00 | desigidx | 0 |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 050 | 55 54 43 00 | designations[0] | "UTC\0" |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[0] | |
+--------+-------------+------------------+------------------------+
| 054 | 04 b2 58 00 | occurrence | 78796800 |
| | | | (1972-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 058 | 00 00 00 01 | correction | 1 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[1] | |
+--------+-------------+------------------+------------------------+
| 062 | 05 a4 ec 01 | occurrence | 94694401 |
| | | | (1972-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 066 | 00 00 00 02 | correction | 2 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[2] | |
+--------+-------------+------------------+------------------------+
| 070 | 07 86 1f 82 | occurrence | 126230402 |
| | | | (1973-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 074 | 00 00 00 03 | correction | 3 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[3] | |
+--------+-------------+------------------+------------------------+
| 078 | 09 67 53 03 | occurrence | 157766403 |
| | | | (1974-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 082 | 00 00 00 04 | correction | 4 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[4] | |
+--------+-------------+------------------+------------------------+
| 086 | 0b 48 86 84 | occurrence | 189302404 |
| | | | (1975-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 090 | 00 00 00 05 | correction | 5 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[5] | |
+--------+-------------+------------------+------------------------+
| 094 | 0d 2b 0b 85 | occurrence | 220924805 |
| | | | (1976-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 098 | 00 00 00 06 | correction | 6 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[6] | |
+--------+-------------+------------------+------------------------+
| 102 | 0f 0c 3f 06 | occurrence | 252460806 |
| | | | (1977-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 106 | 00 00 00 07 | correction | 7 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[7] | |
+--------+-------------+------------------+------------------------+
| 110 | 10 ed 72 87 | occurrence | 283996807 |
| | | | (1978-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 114 | 00 00 00 08 | correction | 8 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[8] | |
+--------+-------------+------------------+------------------------+
| 118 | 12 ce a6 08 | occurrence | 315532808 |
| | | | (1979-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 122 | 00 00 00 09 | correction | 9 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[9] | |
+--------+-------------+------------------+------------------------+
| 126 | 15 9f ca 89 | occurrence | 362793609 |
| | | | (1981-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 130 | 00 00 00 0a | correction | 10 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[10] | |
+--------+-------------+------------------+------------------------+
| 134 | 17 80 fe 0a | occurrence | 394329610 |
| | | | (1982-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 138 | 00 00 00 0b | correction | 11 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[11] | |
+--------+-------------+------------------+------------------------+
| 142 | 19 62 31 8b | occurrence | 425865611 |
| | | | (1983-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 146 | 00 00 00 0c | correction | 12 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[12] | |
+--------+-------------+------------------+------------------------+
| 150 | 1d 25 ea 0c | occurrence | 489024012 |
| | | | (1985-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 154 | 00 00 00 0d | correction | 13 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[13] | |
+--------+-------------+------------------+------------------------+
| 158 | 21 da e5 0d | occurrence | 567993613 |
| | | | (1987-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 162 | 00 00 00 0e | correction | 14 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[14] | |
+--------+-------------+------------------+------------------------+
| 166 | 25 9e 9d 8e | occurrence | 631152014 |
| | | | (1989-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 170 | 00 00 00 0f | correction | 15 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[15] | |
+--------+-------------+------------------+------------------------+
| 174 | 27 7f d1 0f | occurrence | 662688015 |
| | | | (1990-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 178 | 00 00 00 10 | correction | 16 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
Okay bestie, the table keeps going with more leap-second rows, so let's look at how the big table ends ๐ฆโจ
| | leapsecond[16] | |
+--------+-------------+------------------+------------------------+
| 182 | 2a 50 f5 90 | occurrence | 709948816 |
| | | | (1992-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 186 | 00 00 00 11 | correction | 17 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[17] | |
+--------+-------------+------------------+------------------------+
| 190 | 2c 32 29 11 | occurrence | 741484817 |
| | | | (1993-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 194 | 00 00 00 12 | correction | 18 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[18] | |
+--------+-------------+------------------+------------------------+
| 198 | 2e 13 5c 92 | occurrence | 773020818 |
| | | | (1994-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 202 | 00 00 00 13 | correction | 19 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[19] | |
+--------+-------------+------------------+------------------------+
| 206 | 30 e7 24 13 | occurrence | 820454419 |
| | | | (1995-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 210 | 00 00 00 14 | correction | 20 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[20] | |
+--------+-------------+------------------+------------------------+
| 214 | 33 b8 48 94 | occurrence | 867715220 |
| | | | (1997-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 218 | 00 00 00 15 | correction | 21 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[21] | |
+--------+-------------+------------------+------------------------+
| 222 | 36 8c 10 15 | occurrence | 915148821 |
| | | | (1998-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 226 | 00 00 00 16 | correction | 22 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[22] | |
+--------+-------------+------------------+------------------------+
| 230 | 43 b7 1b 96 | occurrence | 1136073622 |
| | | | (2005-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 234 | 00 00 00 17 | correction | 23 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[23] | |
+--------+-------------+------------------+------------------------+
| 238 | 49 5c 07 97 | occurrence | 1230768023 |
| | | | (2008-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 242 | 00 00 00 18 | correction | 24 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[24] | |
+--------+-------------+------------------+------------------------+
| 246 | 4f ef 93 18 | occurrence | 1341100824 |
| | | | (2012-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 250 | 00 00 00 19 | correction | 25 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[25] | |
+--------+-------------+------------------+------------------------+
| 254 | 55 93 2d 99 | occurrence | 1435708825 |
| | | | (2015-06-30T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 258 | 00 00 00 1a | correction | 26 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | leapsecond[26] | |
+--------+-------------+------------------+------------------------+
| 262 | 58 68 46 9a | occurrence | 1483228826 |
| | | | (2016-12-31T23:59:60Z) |
+--------+-------------+------------------+------------------------+
| 266 | 00 00 00 1b | correction | 27 |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 270 | 00 | standard/wall[0] | 0 (wall) |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 271 | 00 | UT/local[0] | 0 (local) |
+--------+-------------+------------------+------------------------+
Table 1
Now the fun part, the little procedure to figure out TAI ๐
To find TAI for 2000-01-01T00:00:00Z (946684800 in UNIX time), you do this:
- Find the latest leap-second occurrence before your time of interest, which is
leapsecond[21], and jot down its correction value,LEAPCORR = 22๐ - Add
LEAPCORR + 10to your time of interest and boom, you get TAI of2000-01-01T00:00:32๐ธ
B.2. Version 2 File Representing Pacific/Honolulu ๐บ
+========+=============+==================+========================+
| File | Hexadecimal | Record Name / | Field Value |
|---|---|---|---|
| Offset | Octets | Field Name |
+========+=============+==================+========================+
| 000 | 54 5a 69 66 | magic | "TZif" |
+--------+-------------+------------------+------------------------+
| 004 | 32 | version | '2' (2) |
+--------+-------------+------------------+------------------------+
| 005 | 00 00 00 00 | |
|---|---|---|
| 00 00 00 00 | ||
| 00 00 00 00 | ||
| 00 00 00 |
+--------+-------------+------------------+------------------------+
| 020 | 00 00 00 06 | isutcnt | 6 |
+--------+-------------+------------------+------------------------+
| 024 | 00 00 00 06 | isstdcnt | 6 |
+--------+-------------+------------------+------------------------+
| 028 | 00 00 00 00 | leapcnt | 0 |
+--------+-------------+------------------+------------------------+
| 032 | 00 00 00 07 | timecnt | 7 |
+--------+-------------+------------------+------------------------+
| 036 | 00 00 00 06 | typecnt | 6 |
+--------+-------------+------------------+------------------------+
| 040 | 00 00 00 14 | charcnt | 20 |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 044 | 80 00 00 00 | trans time[0] | -2147483648 |
|---|---|---|---|
| (1901-12-13T20:45:52Z) |
+--------+-------------+------------------+------------------------+
| 048 | bb 05 43 48 | trans time[1] | -1157283000 |
|---|---|---|---|
| (1933-04-30T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 052 | bb 21 71 58 | trans time[2] | -1155436200 |
|---|---|---|---|
| (1933-05-21T21:30:00Z) |
+--------+-------------+------------------+------------------------+
| 056 | cb 89 3d c8 | trans time[3] | -880198200 |
|---|---|---|---|
| (1942-02-09T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 060 | d2 23 f4 70 | trans time[4] | -769395600 |
|---|---|---|---|
| (1945-08-14T23:00:00Z) |
+--------+-------------+------------------+------------------------+
| 064 | d2 61 49 38 | trans time[5] | -765376200 |
|---|---|---|---|
| (1945-09-30T11:30:00Z) |
+--------+-------------+------------------+------------------------+
| 068 | d5 8d 73 48 | trans time[6] | -712150200 |
|---|---|---|---|
| (1947-06-08T12:30:00Z) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 072 | 01 | trans type[0] | 1 |
+--------+-------------+------------------+------------------------+
| 073 | 02 | trans type[1] | 2 |
+--------+-------------+------------------+------------------------+
| 074 | 01 | trans type[2] | 1 |
+--------+-------------+------------------+------------------------+
| 075 | 03 | trans type[3] | 3 |
+--------+-------------+------------------+------------------------+
| 076 | 04 | trans type[4] | 4 |
+--------+-------------+------------------+------------------------+
| 077 | 01 | trans type[5] | 1 |
+--------+-------------+------------------+------------------------+
| 078 | 05 | trans type[6] | 5 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[0] |
+--------+-------------+------------------+------------------------+
| 079 | ff ff 6c 02 | utoff | -37886 (-10:31:26) |
+--------+-------------+------------------+------------------------+
| 083 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 084 | 00 | desigidx | 0 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[1] |
+--------+-------------+------------------+------------------------+
| 085 | ff ff 6c 58 | utoff | -37800 (-10:30) |
+--------+-------------+------------------+------------------------+
| 089 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 090 | 04 | desigidx | 4 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[2] |
+--------+-------------+------------------+------------------------+
| 091 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 095 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 096 | 08 | desigidx | 8 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[3] |
+--------+-------------+------------------+------------------------+
| 097 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 101 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 102 | 0c | desigidx | 12 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[4] |
+--------+-------------+------------------+------------------------+
| 103 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 107 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 108 | 10 | desigidx | 16 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[5] |
+--------+-------------+------------------+------------------------+
| 109 | ff ff 73 60 | utoff | -36000 (-10:00) |
+--------+-------------+------------------+------------------------+
| 113 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 114 | 04 | desigidx | 4 |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 115 | 4c 4d 54 00 | designations[0] | "LMT\0" |
+--------+-------------+------------------+------------------------+
| 119 | 48 53 54 00 | designations[4] | "HST\0" |
+--------+-------------+------------------+------------------------+
| 123 | 48 44 54 00 | designations[8] | "HDT\0" |
+--------+-------------+------------------+------------------------+
| 127 | 48 57 54 00 | designations[12] | "HWT\0" |
+--------+-------------+------------------+------------------------+
| 131 | 48 50 54 00 | designations[16] | "HPT\0" |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 135 | 00 | standard/wall[0] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 136 | 00 | standard/wall[1] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 137 | 00 | standard/wall[2] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 138 | 00 | standard/wall[3] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 139 | 01 | standard/wall[4] | 1 (standard) |
+--------+-------------+------------------+------------------------+
| 140 | 00 | standard/wall[5] | 0 (wall) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 141 | 00 | UT/local[0] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 142 | 00 | UT/local[1] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 143 | 00 | UT/local[2] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 144 | 00 | UT/local[3] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 145 | 01 | UT/local[4] | 1 (UT) |
+--------+-------------+------------------+------------------------+
| 146 | 00 | UT/local[5] | 0 (local) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 147 | 54 5a 69 66 | magic | "TZif" |
+--------+-------------+------------------+------------------------+
| 151 | 32 | version | '2' (2) |
+--------+-------------+------------------+------------------------+
| 152 | 00 00 00 00 | |
|---|---|---|
| 00 00 00 00 | ||
| 00 00 00 00 | ||
| 00 00 00 |
+--------+-------------+------------------+------------------------+
| 167 | 00 00 00 06 | isutcnt | 6 |
+--------+-------------+------------------+------------------------+
| 171 | 00 00 00 06 | isstdcnt | 6 |
+--------+-------------+------------------+------------------------+
| 175 | 00 00 00 00 | leapcnt | 0 |
+--------+-------------+------------------+------------------------+
| 179 | 00 00 00 07 | timecnt | 7 |
+--------+-------------+------------------+------------------------+
| 183 | 00 00 00 06 | typecnt | 6 |
+--------+-------------+------------------+------------------------+
| 187 | 00 00 00 14 | charcnt | 20 |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 191 | ff ff ff ff | trans time[0] | -2334101314 |
|---|---|---|---|
| 74 e0 70 be | (1896-01-13T22:31:26Z) |
+--------+-------------+------------------+------------------------+
| 199 | ff ff ff ff | trans time[1] | -1157283000 |
|---|---|---|---|
| bb 05 43 48 | (1933-04-30T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 207 | ff ff ff ff | trans time[2] | -1155436200 |
|---|---|---|---|
| bb 21 71 58 | (1933-05-21T21:30:00Z) |
+--------+-------------+------------------+------------------------+
| 215 | ff ff ff ff | trans time[3] | -880198200 |
|---|---|---|---|
| cb 89 3d c8 | (1942-02-09T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 223 | ff ff ff ff | trans time[4] | -769395600 |
|---|---|---|---|
| d2 23 f4 70 | (1945-08-14T23:00:00Z) |
+--------+-------------+------------------+------------------------+
| 231 | ff ff ff ff | trans time[5] | -765376200 |
|---|---|---|---|
| d2 61 49 38 | (1945-09-30T11:30:00Z) |
+--------+-------------+------------------+------------------------+
| 239 | ff ff ff ff | trans time[6] | -712150200 |
|---|---|---|---|
| d5 8d 73 48 | (1947-06-08T12:30:00Z) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 247 | 01 | trans type[0] | 1 |
+--------+-------------+------------------+------------------------+
| 248 | 02 | trans type[1] | 2 |
+--------+-------------+------------------+------------------------+
| 249 | 01 | trans type[2] | 1 |
+--------+-------------+------------------+------------------------+
| 250 | 03 | trans type[3] | 3 |
+--------+-------------+------------------+------------------------+
| 251 | 04 | trans type[4] | 4 |
+--------+-------------+------------------+------------------------+
| 252 | 01 | trans type[5] | 1 |
+--------+-------------+------------------+------------------------+
| 253 | 05 | trans type[6] | 5 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[0] |
+--------+-------------+------------------+------------------------+
| 254 | ff ff 6c 02 | utoff | -37886 (-10:31:26) |
+--------+-------------+------------------+------------------------+
| 258 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 259 | 00 | desigidx | 0 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[1] |
+--------+-------------+------------------+------------------------+
| 260 | ff ff 6c 58 | utoff | -37800 (-10:30) |
+--------+-------------+------------------+------------------------+
| 264 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 265 | 04 | desigidx | 4 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[2] |
+--------+-------------+------------------+------------------------+
| 266 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 270 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 271 | 08 | desigidx | 8 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[3] |
+--------+-------------+------------------+------------------------+
| 272 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 276 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 277 | 0c | desigidx | 12 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[4] |
+--------+-------------+------------------+------------------------+
| 278 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 282 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 283 | 10 | desigidx | 16 |
+--------+-------------+------------------+------------------------+ +----------------------+------------------+------------------------+
| localtimetype[5] |
+--------+-------------+------------------+------------------------+
| 284 | ff ff 73 60 | utoff | -36000 (-10:00) |
+--------+-------------+------------------+------------------------+
| 288 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 289 | 04 | desigidx | 4 |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 290 | 4c 4d 54 00 | designations[0] | "LMT\0" |
+--------+-------------+------------------+------------------------+
| 294 | 48 53 54 00 | designations[4] | "HST\0" |
+--------+-------------+------------------+------------------------+
| 298 | 48 44 54 00 | designations[8] | "HDT\0" |
+--------+-------------+------------------+------------------------+
| 302 | 48 57 54 00 | designations[12] | "HWT\0" |
+--------+-------------+------------------+------------------------+
| 306 | 48 50 54 00 | designations[16] | "HPT\0" |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 310 | 00 | standard/wall[0] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 311 | 00 | standard/wall[1] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 312 | 00 | standard/wall[2] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 313 | 00 | standard/wall[3] | 0 (wall) |
+--------+-------------+------------------+------------------------+
| 314 | 01 | standard/wall[4] | 1 (standard) |
+--------+-------------+------------------+------------------------+
| 315 | 00 | standard/wall[5] | 0 (wall) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 316 | 00 | UT/local[0] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 317 | 00 | UT/local[1] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 318 | 00 | UT/local[2] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 319 | 00 | UT/local[3] | 0 (local) |
+--------+-------------+------------------+------------------------+
| 320 | 01 | UT/local[4] | 1 (UT) |
+--------+-------------+------------------+------------------------+
| 321 | 00 | UT/local[5] | 0 (local) |
+--------+-------------+------------------+------------------------+ +--------+-------------+------------------+------------------------+
| 322 | 0a | NL | '\n' |
+--------+-------------+------------------+------------------------+
| 323 | 48 53 54 31 | TZ string | "HST10" |
|---|---|---|---|
| 30 |
+--------+-------------+------------------+------------------------+
| 328 | 0a | NL | '\n' |
+--------+-------------+------------------+------------------------+
Table 2
Okay bestie, let's decode this file together ๐ซถ Say we want the local time in this zone at 1933-05-04T12:00:00Z (UNIX time = -1156939200). Here's the move:
- Find the latest time transition before our time of interest. That's trans time[1] โฐ
- Check the matching transition type, trans type[1], to get the local time type index, which is 2 ๐
- Peek at localtimetype[2] to grab the UTC offset (-09:30), the daylight saving flag (1 = yes), and the index into the time zone designation strings (8) โจ
- Look up designations[8] and you get "HDT" ๐บ
- Add the UTC offset to our time of interest and boom, you get a local daylight saving time of 1933-05-04T02:30:00-09:30 (HDT) ๐
Now for the second one, the local time at 2019-01-01T00:00:00Z (UNIX time = 1546300800):
- Find the latest transition before it. There isn't one, bestie ๐
- Read the TZ string in the footer, "HST10". That tells us the designation is "HST" year-round and the offset to UTC is 10:00 ๐
- Subtract the UTC offset to get a standard local time of 2018-12-31T14:00:00-10:00 (HST) ๐
B.3. Truncated Version 2 File Representing Pacific/Johnston โจ
The example file ends on 2004-06-161T00:00:00Z, which is the exact timestamp in the spec, typo and all ๐ซถ. The atoll was abandoned sometime on 2004-06-15, so this file is basically a little time capsule ๐๏ธ๐ literally a ghost island in file form ๐ง
Here's what's cute about this one:
- The version 1 header is giving minimum-viable ๐ฅบ It only has the required minimum data, and readers are going to ignore it anyway. Main character energy? Not really, but it does its job ๐
- The version 2 header is the real star โจ By setting
isutcntandisstdcntto zero, all the transition times that belong to local time types are assumed to be local wall-clock time. It's the kind of trick that's iconic once you get it ๐ญ (If you want the full details on the UT/local and standard/wall indicators, check out Section 3.2 ๐ฆ) - The time type of the last transition is labeled "-00", which means local time is unspecified ๐ธ It's giving "we don't know and we're not pretending to" ๐
- The TZ string is empty, so there are no known future transitions. The file is done, nothing else is coming, and honestly that's very on-brand for a tiny abandoned atoll ๐๏ธ๐ซ
Truncation arc complete!! ๐
okay bestie, this is the last stretch of the truncated Pacific/Johnston file, and the table is literally giving ๐ง๐ every byte gets its own row, so no vibes-only guessing ๐ซถ
+========+=============+==================+========================+
| File | Hexadecimal | Record Name / | Field Value |
| Offset | Octets | Field Name | |
+========+=============+==================+========================+
| 000 | 54 5a 69 66 | magic | "TZif" |
+--------+-------------+------------------+------------------------+
| 004 | 32 | version | '2' (2) |
+--------+-------------+------------------+------------------------+
| 005 | 00 00 00 00 | | |
| | 00 00 00 00 | | |
| | 00 00 00 00 | | |
| | 00 00 00 | | |
+--------+-------------+------------------+------------------------+
| 020 | 00 00 00 00 | isutcnt | 0 |
+--------+-------------+------------------+------------------------+
| 024 | 00 00 00 00 | isstdcnt | 0 |
+--------+-------------+------------------+------------------------+
| 028 | 00 00 00 00 | leapcnt | 0 |
+--------+-------------+------------------+------------------------+
| 032 | 00 00 00 00 | timecnt | 0 |
+--------+-------------+------------------+------------------------+
| 036 | 00 00 00 01 | typecnt | 1 |
+--------+-------------+------------------+------------------------+
| 040 | 00 00 00 01 | charcnt | 1 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[0] | |
+--------+-------------+------------------+------------------------+
| 044 | 00 00 00 00 | utoff | 0 (+00:00) |
+--------+-------------+------------------+------------------------+
| 048 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 049 | 00 | desigidx | 0 |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 050 | 00 | designations[0] | "\0" |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 051 | 54 5a 69 66 | magic | "TZif" |
+--------+-------------+------------------+------------------------+
| 055 | 32 | version | '2' (2) |
+--------+-------------+------------------+------------------------+
| 056 | 00 00 00 00 | |
| | 00 00 00 00 | |
| | 00 00 00 00 | |
| | 00 00 00 | |
+--------+-------------+------------------+------------------------+
| 071 | 00 00 00 00 | isutcnt | 0 |
+--------+-------------+------------------+------------------------+
| 075 | 00 00 00 00 | isstdcnt | 0 |
+--------+-------------+------------------+------------------------+
| 079 | 00 00 00 00 | leapcnt | 0 |
+--------+-------------+------------------+------------------------+
| 083 | 00 00 00 08 | timecnt | 8 |
+--------+-------------+------------------+------------------------+
| 087 | 00 00 00 07 | typecnt | 7 |
+--------+-------------+------------------+------------------------+
| 091 | 00 00 00 18 | charcnt | 24 |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 095 | ff ff ff ff | trans time[0] | -2334101314 |
| | 74 e0 70 be | | (1896-01-13T22:31:26Z) |
+--------+-------------+------------------+------------------------+
| 103 | ff ff ff ff | trans time[1] | -1157283000 |
| | bb 05 43 48 | | (1933-04-30T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 111 | ff ff ff ff | trans time[2] | -1155436200 |
| | bb 21 71 58 | | (1933-05-21T21:30:00Z) |
+--------+-------------+------------------+------------------------+
| 119 | ff ff ff ff | trans time[3] | -880198200 |
| | cb 89 3d c8 | | (1942-02-09T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 127 | ff ff ff ff | trans time[4] | -769395600 |
| | d2 23 f4 70 | | (1945-08-14T23:00:00Z) |
+--------+-------------+------------------+------------------------+
| 135 | ff ff ff ff | trans time[5] | -765376200 |
| | d2 61 49 38 | | (1945-09-30T11:30:00Z) |
+--------+-------------+------------------+------------------------+
| 143 | ff ff ff ff | trans time[6] | -712150200 |
| | d5 8d 73 48 | | (1947-06-08T12:30:00Z) |
+--------+-------------+------------------+------------------------+
| 151 | 00 00 00 00 | trans time[7] | 1087344000 |
| | 40 cf 8d 80 | | (2004-06-16T00:00:00Z) |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 159 | 02 | trans type[0] | 2 |
+--------+-------------+------------------+------------------------+
| 160 | 03 | trans type[1] | 3 |
+--------+-------------+------------------+------------------------+
| 161 | 02 | trans type[2] | 2 |
+--------+-------------+------------------+------------------------+
| 162 | 04 | trans type[3] | 4 |
+--------+-------------+------------------+------------------------+
| 163 | 05 | trans type[4] | 5 |
+--------+-------------+------------------+------------------------+
| 164 | 02 | trans type[5] | 2 |
+--------+-------------+------------------+------------------------+
| 165 | 06 | trans type[6] | 6 |
+--------+-------------+------------------+------------------------+
| 166 | 01 | trans type[7] | 1 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[0] | |
+--------+-------------+------------------+------------------------+
| 167 | ff ff 6c 02 | utoff | -37886 (-10:31:26) |
+--------+-------------+------------------+------------------------+
| 171 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 172 | 04 | desigidx | 4 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[1] | |
+--------+-------------+------------------+------------------------+
| 173 | 00 00 00 00 | utoff | 0 (+00:00) |
+--------+-------------+------------------+------------------------+
| 177 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 178 | 00 | desigidx | 0 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[2] | |
+--------+-------------+------------------+------------------------+
| 179 | ff ff 6c 58 | utoff | -37800 (-10:30) |
+--------+-------------+------------------+------------------------+
| 183 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 184 | 08 | desigidx | 8 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[3] | |
+--------+-------------+------------------+------------------------+
| 185 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 189 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 190 | 0c | desigidx | 12 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[4] | |
+--------+-------------+------------------+------------------------+
| 191 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 195 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 196 | 10 | desigidx | 16 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[5] | |
+--------+-------------+------------------+------------------------+
| 197 | ff ff 7a 68 | utoff | -34200 (-09:30) |
+--------+-------------+------------------+------------------------+
| 201 | 01 | isdst | 1 (yes) |
+--------+-------------+------------------+------------------------+
| 202 | 14 | desigidx | 20 |
+--------+-------------+------------------+------------------------+
+----------------------+------------------+------------------------+
| | localtimetype[6] | |
+--------+-------------+------------------+------------------------+
| 203 | ff ff 73 60 | utoff | -36000 (-10:00) |
+--------+-------------+------------------+------------------------+
| 207 | 00 | isdst | 0 (no) |
+--------+-------------+------------------+------------------------+
| 208 | 08 | desigidx | 8 |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 209 | 2d 30 30 00 | designations[0] | "-00\0" |
+--------+-------------+------------------+------------------------+
| 213 | 4c 4d 54 00 | designations[4] | "LMT\0" |
+--------+-------------+------------------+------------------------+
| 217 | 48 53 54 00 | designations[8] | "HST\0" |
+--------+-------------+------------------+------------------------+
| 221 | 48 44 54 00 | designations[12] | "HDT\0" |
+--------+-------------+------------------+------------------------+
| 225 | 48 57 54 00 | designations[16] | "HWT\0" |
+--------+-------------+------------------+------------------------+
| 229 | 48 50 54 00 | designations[20] | "HPT\0" |
+--------+-------------+------------------+------------------------+
+--------+-------------+------------------+------------------------+
| 233 | 0a | NL | '\n' |
+--------+-------------+------------------+------------------------+
| 234 | | TZ string | "" |
+--------+-------------+------------------+------------------------+
| 234 | 0a | NL | '\n' |
+--------+-------------+------------------+------------------------+
Table 3 ๐ and that's the end of that little hex-picture, bestie! ๐
B.4. Truncated Version 3 File Representing Asia/Jerusalem โจ
okay so this one is a truncated TZif file ๐ฅบ it's been chopped to start on 2038-01-01T00:00:00Z, so it only covers the time from that point onward. no cap, it's giving very "I only want the future" energy ๐ฎ
a few things to clock in this example:
- the start time value can't fit in 32 bits ๐ญ so the version 1 header only has the required minimum data, and readers are going to ignore it. the version 1 header is just there as a placeholder, not the real deal ๐
- the version 3 header is the main character here ๐ by setting
isutcntandisstdcntto zero, all the transition times tied to local time types are assumed to be local wall-clock time. (if you want the full scoop on the UT/local indicators and the standard/wall indicators, go check Section 3.2, it's the source of truth ๐ ) - time type 0 has the designation
"-00"๐ธ which basically says "local time is unspecified before the truncation time." iconic honestly, it's the file being honest about what it doesn't know ๐ซถ - the TZ string value has been line-wrapped, but that's just so it looks nice on the page ๐ it's purely for presentation, the actual value is still the one shown in the table
here's the whole file, byte by byte ๐ฆ
+======+===========+================+==============================+
|File |Hexadecimal|Record Name / | Field Value |
|Offset|Octets |Field Name | |
+======+===========+================+==============================+
|000 |54 5a 69 66|magic | "TZif" |
+------+-----------+----------------+------------------------------+
|004 |33 |version | '3' (3) |
+------+-----------+----------------+------------------------------+
|005 |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 | |
+------+-----------+----------------+------------------------------+
|020 |00 00 00 00|isutcnt | 0 |
+------+-----------+----------------+------------------------------+
|024 |00 00 00 00|isstdcnt | 0 |
+------+-----------+----------------+------------------------------+
|028 |00 00 00 00|leapcnt | 0 |
+------+-----------+----------------+------------------------------+
|032 |00 00 00 00|timecnt | 0 |
+------+-----------+----------------+------------------------------+
|036 |00 00 00 01|typecnt | 1 |
+------+-----------+----------------+------------------------------+
|040 |00 00 00 01|charcnt | 1 |
+------+-----------+----------------+------------------------------+
+------------------+----------------+------------------------------+
| |localtimetype[0]| |
+------+-----------+----------------+------------------------------+
|044 |00 00 00 00|utoff | 0 (+00:00) |
+------+-----------+----------------+------------------------------+
|048 |00 |isdst | 0 (no) |
+------+-----------+----------------+------------------------------+
|049 |00 |desigidx | 0 |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|050 |00 |designations[0] | "\0" |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|051 |54 5a 69 66|magic | "TZif" |
+------+-----------+----------------+------------------------------+
|055 |33 |version | '3' (3) |
+------+-----------+----------------+------------------------------+
|056 |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 | |
+------+-----------+----------------+------------------------------+
|071 |00 00 00 00|isutcnt | 0 |
+------+-----------+----------------+------------------------------+
|075 |00 00 00 00|isstdcnt | 0 |
+------+-----------+----------------+------------------------------+
|079 |00 00 00 00|leapcnt | 0 |
+------+-----------+----------------+------------------------------+
|083 |00 00 00 01|timecnt | 1 |
+------+-----------+----------------+------------------------------+
|087 |00 00 00 02|typecnt | 2 |
+------+-----------+----------------+------------------------------+
|091 |00 00 00 08|charcnt | 8 |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|095 |00 00 00 00|trans time[0] | 2145916800 |
| |7f e8 17 80| | (2038-01-01T00:00:00Z) |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|103 |01 |trans type[0] | 1 |
+------+-----------+----------------+------------------------------+
+------------------+----------------+------------------------------+
| |localtimetype[0]| |
+------+-----------+----------------+------------------------------+
|104 |00 00 00 00|utoff | 0 (+00:00) |
+------+-----------+----------------+------------------------------+
|108 |00 |isdst | 0 (no) |
+------+-----------+----------------+------------------------------+
|109 |00 |desigidx | 0 |
+------+-----------+----------------+------------------------------+
+------------------+----------------+------------------------------+
| |localtimetype[1]| |
+------+-----------+----------------+------------------------------+
|110 |00 00 1c 20|utoff | 7200 (+02:00) |
+------+-----------+----------------+------------------------------+
|114 |00 |isdst | 0 (no) |
+------+-----------+----------------+------------------------------+
|115 |04 |desigidx | 4 |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|116 |2d 30 30 00|designations[0] | "-00\0" |
+------+-----------+----------------+------------------------------+
|120 |49 53 54 00|designations[4] | "IST\0" |
+------+-----------+----------------+------------------------------+
+------+-----------+----------------+------------------------------+
|124 |0a |NL | '\n' |
+------+-----------+----------------+------------------------------+
|125 |49 53 54 2d|TZ string | "IST-2IDT,M3.4.4/26,M10.5.0" |
| |32 49 44 54| | |
| |2c 4d 33 2e| | |
| |34 2e 34 2f| | |
| |32 36 2c 4d| | |
| |31 30 2e 35| | |
| |2e 30 | | |
+------+-----------+----------------+------------------------------+
|151 |0a |NL | '\n' |
+------+-----------+----------------+------------------------------+
Table 4
Table 4 ๐ง that's the whole truncated Asia/Jerusalem picture! โจ
B.5. Truncated Version 4 File Representing Europe/London ๐ฌ๐ง๐ซ
okay so this TZif file got chopped to start on 2022-01-01T00:00:00Z โจ. Here are the highlights ๐ :
- The version 1 header only carries the required minimum data, and readers just ignore it ๐.
- The version 4 header is giving main character ๐. By setting
'isutcnt'and'isstdcnt'to zero, every transition time tied to a local time type is treated as local wall-clock time (see the definitions of UT/local indicators and standard/wall indicators in Section 3.2) ๐ฐ๏ธ. - Time type 0 is labelled "-00", which means local time is unspecified before the truncation point ๐ซฅ.
- The first leap second is the most recent one before the truncation time ๐.
- The last leap-second correction matches the second-to-last one, which marks when the leap-second table expires ๐.
- The TZ string was line-wrapped purely for presentation, nothing else ๐.
+======+===========+==================+============================+
|File |Hexadecimal| Record Name / | Field Value |
|Offset|Octets | Field Name | |
+======+===========+==================+============================+
|000 |54 5a 69 66| magic | "TZif" |
+------+-----------+------------------+----------------------------+
|004 |34 | version | '4' (4) |
+------+-----------+------------------+----------------------------+
|005 |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 | |
+------+-----------+------------------+----------------------------+
|020 |00 00 00 00| isutcnt | 0 |
+------+-----------+------------------+----------------------------+
|024 |00 00 00 00| isstdcnt | 0 |
+------+-----------+------------------+----------------------------+
|028 |00 00 00 00| leapcnt | 0 |
+------+-----------+------------------+----------------------------+
|032 |00 00 00 00| timecnt | 0 |
+------+-----------+------------------+----------------------------+
|036 |00 00 00 01| typecnt | 1 |
+------+-----------+------------------+----------------------------+
|040 |00 00 00 01| charcnt | 1 |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
| | localtimetype[0] | |
+------+-----------+------------------+----------------------------+
|044 |00 00 00 00| utoff | 0 (+00:00) |
+------+-----------+------------------+----------------------------+
|048 |00 | isdst | 0 (no) |
+------+-----------+------------------+----------------------------+
|049 |00 | desigidx | 0 |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|050 |00 | designations[0] | "\0" |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|051 |54 5a 69 66| magic | "TZif" |
+------+-----------+------------------+----------------------------+
|055 |34 | version | '4' (4) |
+------+-----------+------------------+----------------------------+
|056 |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 00| |
| |00 00 00 | |
+------+-----------+------------------+----------------------------+
|071 |00 00 00 00| isutcnt | 0 |
+------+-----------+------------------+----------------------------+
|075 |00 00 00 00| isstdcnt | 0 |
+------+-----------+------------------+----------------------------+
|079 |00 00 00 02| leapcnt | 2 |
+------+-----------+------------------+----------------------------+
|083 |00 00 00 01| timecnt | 1 |
+------+-----------+------------------+----------------------------+
|087 |00 00 00 02| typecnt | 2 |
+------+-----------+------------------+----------------------------+
|091 |00 00 00 08| charcnt | 8 |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|095 |00 00 00 00| trans time[0] | 1640995227 |
| |61 cf 99 9b| | (2022-01-01T00:00:27Z) |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|103 |01 | trans type[0] | 1 |
+------+-----------+------------------+----------------------------+
+------------------+------------------+----------------------------+
| | localtimetype[0] | |
+------+-----------+------------------+----------------------------+
|104 |00 00 00 00| utoff | 0 (+00:00) |
+------+-----------+------------------+----------------------------+
|108 |00 | isdst | 0 (no) |
+------+-----------+------------------+----------------------------+
|109 |00 | desigidx | 0 |
+------+-----------+------------------+----------------------------+
+------------------+------------------+----------------------------+
| | localtimetype[1] | |
+------+-----------+------------------+----------------------------+
|110 |00 00 00 00| utoff | 0 (+00:00) |
+------+-----------+------------------+----------------------------+
|114 |00 | isdst | 0 (no) |
+------+-----------+------------------+----------------------------+
|115 |04 | desigidx | 4 |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|116 |2d 30 30 00| designations[0] | "-00\0" |
+------+-----------+------------------+----------------------------+
|120 |47 4d 54 00| designations[4] | "GMT\0" |
+------+-----------+------------------+----------------------------+
+------------------+------------------+----------------------------+
| | leapsecond[0] | |
+------+-----------+------------------+----------------------------+
|124 |00 00 00 00| occurrence | 1483228826 |
| |58 68 46 9a| | (2016-12-31T23:59:60Z) |
+------+-----------+------------------+----------------------------+
|132 |00 00 00 1b| correction | 27 |
+------+-----------+------------------+----------------------------+
+------------------+------------------+----------------------------+
| | leapsecond[1] | |
+------+-----------+------------------+----------------------------+
|136 |00 00 00 00| occurrence | 1719532827 |
| |66 7d fd 1b| | (2024-06-28T00:00:01Z) |
+------+-----------+------------------+----------------------------+
|144 |00 00 00 1b| correction | 27 |
+------+-----------+------------------+----------------------------+
+------+-----------+------------------+----------------------------+
|148 |0a | NL | '\n' |
+------+-----------+------------------+----------------------------+
|149 |47 4d 54 30| TZ string | "GMT0BST,M3.5.0/1,M10.5.0" |
| |42 53 54 2c| | |
| |4d 33 2e 35| | |
| |2e 30 2f 31| | |
| |2c 4d 31 30| | |
| |2e 35 2e 30| | |
+------+-----------+------------------+----------------------------+
|173 |0a | NL | '\n' |
+------+-----------+------------------+----------------------------+
Table 5
Appendix C. Changes from RFC 8536 ๐
okay, here's the glow-up list from RFC 8536 โจ๐ฆ:
- Added a definition of Leap Second ๐.
- Added the specification of the version 4 format, plus the optional leap-second table truncation and expiration, along with an example and relevant interoperability considerations ๐.
- Documented the longstanding practice that UT with designation string "-00" denotes unspecified local time ๐ซฅ. Added a recommendation that this designation string should be used for timestamps excluded by TZif file truncation ๐.
- Required support in version 2 files for all-year daylight saving time, using POSIX TZ strings with negative DST, as this is not an extension to POSIX (Section 3.3.1) ๐.
- Applied erratum [Err6435] ๐ฉน.
- Addressed errata [Err6426], [Err6757], and [Err7681], as well as several other errors in the examples ๐งน.
- Added additional interoperability considerations and common issues ๐ซถ.
- Added an example of a TZif file truncated at the end (Appendix B.3) ๐.
- Added informational notes to Appendix B.4 ๐ง .
- Miscellaneous editorial changes ๐ .
Acknowledgments ๐ซถ
The authors thank the following individuals for contributing their ideas and support for writing this specification: Michael Douglass, Ned Freed, Guy Harris, Eliot Lear, Alexey Melnikov, and Tim Parenti ๐.
Authors' Addresses ๐ฆ
Arthur David Olson Email: arthurdavidolson@gmail.com
Paul Eggert University of California, Los Angeles Email: eggert@cs.ucla.edu
Kenneth Murchison Fastmail US LLC Email: murch@fastmailteam.com
that's the whole thing, bestie ๐โจ๐ RFC 9636 is a wrap!
๐ฆ where this page comes from
- ietf: rfc9636 2024-10
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms