zic(8)
๐ zic(8) ๐
bestie, this is the manual for zic, the timezone compiler, from the System Manager's Manual ๐ let's get into it โจ
๐ NAME ๐
okay so the whole page is about zic, which is a timezone compiler ๐ง that's literally it, no cap
๐ฆ SYNOPSIS ๐ฆ
zic [ option ... ] [ filename ... ]
๐ธ DESCRIPTION ๐ธ
okay so zic reads text from the file(s) you name on the command line and spits out timezone information format (TZif) files based on that input ๐ซถ if a filename is -, it reads from standard input instead, which is giving very flexible energy โจ
โจ OPTIONS โจ
--versionโ shows the version info and then bounces ๐--helpโ shows a short usage message and then exits, so you can get a quick refresher ๐-b bloatโ outputs backward-compatibility data based on bloat ๐ if bloat isfat, zic adds extra data entries that work around bugs or incompatibilities in older software, like software that messes up 64-bit data ๐ญ if bloat isslim, the output files stay small, which can help you hunt for those same bugs and incompatibilities ๐ the default isslim, because software that mishandles 64-bit data usually mishandles timestamps after the year 2038 anyway ๐ also see the-roption for another way to change output size-d directoryโ puts the time conversion files in the named directory instead of the standard directory (which is listed further down) ๐-l timezoneโ uses timezone as local time ๐ zic acts like the input had a link line that looks like this:
Link timezone localtime
if timezone is -, any link that already exists gets removed ๐ซ
-L leapsecondfilenameโ reads leap second info from the file with that name ๐ if you don't use this option, no leap second info shows up in the output files ๐-p timezoneโ uses timezone's rules when handling nonstandard TZ strings like"EET-2EEST"that don't have transition rules ๐ธ zic acts like the input had a link line that looks like this:
Link timezone posixrules
if timezone is - (the default), any existing link gets removed ๐งน
โ ๏ธ unless timezone is-, this option is obsolete and poorly supported ๐ฌ among other things, it shouldn't be used for timestamps after the year 2037, and it shouldn't be combined with-b slimif timezone's transitions happen at standard time or Universal Time (UT) instead of local time
-r [@lo][/@hi]โ limits where the output files apply to timestamps from lo (inclusive) up to hi (exclusive) ๐ lo and hi are signed decimal counts of seconds since the Epoch (1970-01-01 00:00:00 UTC), and if you leave one out, it defaults to an extreme value ๐ฆ the output files use UT offset0and the abbreviation-00in place of the omitted timestamp data ๐ซถ for example,zic -r @0skips data meant for negative timestamps (aka before the Epoch), andzic -r @0/@2147483648only outputs data for nonnegative timestamps that fit into 31-bit signed integers โจ on platforms with GNU date,zic -r @$(date +%s)skips data meant for past timestamps โฐ this usually shrinks the file, but it can actually grow it, especially if hi makes a TZif file store explicit entries for pre-hi transitions instead of neatly representing them with an extended POSIX.1-2017 TZ string ๐ also see the-b slimoption for another way to shrink output-R @hiโ generates redundant trailing explicit transitions for timestamps that happen less than hi seconds after the Epoch, even though the extended POSIX.1-2017 TZ string could represent them more concisely ๐ง this doesn't change the timestamps being represented ๐ซถ it helps out nonstandard TZif readers that ignore the extended POSIX.1-2017 TZ string, but the altered output files get bigger ๐-t fileโ when making local time info, puts the configuration link in the named file instead of the standard location ๐๏ธ-vโ gets more verbose and complains about the following situations ๐จ- the input specifies a link to a link, which some older parsers don't support, including zic itself through release 2022e ๐ โโ๏ธ
- a year in a data file is outside the range of representable years ๐
- a time of
24:00or more shows up in the input ๐ pre-1998 versions of zic prohibit24:00, and pre-2007 versions prohibit times greater than24:00 - a rule goes past the start or end of the month ๐๏ธ pre-2004 versions of zic prohibit this
- a time zone abbreviation uses a
%zformat ๐ pre-2015 versions of zic don't support this - a timestamp has fractional seconds โฑ๏ธ pre-2018 versions of zic don't support this
- the input has abbreviations that pre-2018 versions of zic mishandle because of a longstanding coding bug ๐ these include
LforLink,miformin,SaforSat, andSuforSun๐ญ - the output file doesn't have all the info about a timezone's long-term future, because the future can't be summarized as an extended POSIX.1-2017 TZ string ๐ฎ for example, as of 2023 this happens with Morocco's daylight-saving rules, since they're based on predictions for when Ramadan will be observed, which an extended POSIX.1-2017 TZ string can't represent ๐
- the output has data that client code made for older zic output formats might not handle properly ๐ง these compatibility issues only affect timestamps before 1970 or after the start of 2038 ๐ซ
- the output has a truncated leap second table, which can make some older TZif readers misbehave ๐ฅด this can happen if the
-Loption is used and either an Expires line is present or the-roption is also used - the output file has more than 1200 transitions, which some clients might mishandle ๐ง the current reference client supports at most 2000 transitions, and pre-2014 versions of the reference client support at most 1200 transitions
- a time zone abbreviation has fewer than 3 or more than 6 characters ๐ค POSIX requires at least 3 and requires implementations to support at least 6
- an output file name has a byte that isn't an ASCII letter,
-,/, or_, or it has a file name component with more than 14 bytes or one that starts with-๐
๐ง FILES ๐ง
okay so input files use the format described in this section ๐ซถ output files use tzfile(5) format ๐
input files should be text files, which means they're a series of zero or more lines, each ending in a newline byte and containing at most 2048 bytes counting the newline, with no NUL bytes at all ๐
โโ๏ธ the input text's encoding is usually UTF-8 or ASCII ๐ค it should have a unibyte representation for the POSIX Portable Character Set (PPCS) โจhttps://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.htmlโฉ, and the encoding's non-unibyte characters should be made entirely of non-PPCS bytes ๐ธ non-PPCS characters usually only show up in comments ๐ฌ output file names and time zone abbreviations can have almost any character, but other software works better if you keep them to the restricted syntax described under the -v option ๐ซถ
input lines are made of fields ๐งฉ fields are separated by one or more white space characters, which are space, form feed, carriage return, newline, tab, and vertical tab โจ leading and trailing white space on input lines gets ignored ๐ซง an unquoted sharp character (#) starts a comment that runs to the end of the line it's on ๐ฌ white space characters and sharp characters can be wrapped in double quotes (") if you want them to be part of a field ๐ any line that's blank (after comments are stripped) gets ignored ๐ด nonblank lines should be one of three types: rule lines, zone lines, and link lines ๐
names must be in English and are case insensitive ๐ฌ๐ง they show up in lots of places, including month and weekday names and keywords like maximum, only, Rolling, and Zone ๐
you can abbreviate a name by dropping everything except an initial prefix, but the abbreviation has to be unambiguous in context ๐
a rule line looks like this:
Rule NAME FROM TO - IN ON AT SAVE LETTER/S
for example:
Rule US 1967 1973 - Apr lastSun 2:00w 1:00d D
the fields that make up a rule line are:
NAMEโ the name of the rule set this line belongs to ๐ท๏ธ the name has to start with a character that's not an ASCII digit,-, or+๐ซ to leave room for future extensions, an unquoted name shouldn't contain characters from the set!$%&'()*,/:;<=>?@[\]^{|}~` ๐ซถFROMโ the first year the rule applies ๐ any signed integer year works, and the proleptic Gregorian calendar is assumed, with year 0 coming right before year 1 ๐๏ธ rules can describe times that aren't representable as time values, and those unrepresentable times just get ignored, which lets rules be portable across hosts with different time value types ๐TOโ the final year the rule applies โณ the wordmaximum(or an abbreviation of it) means the indefinite future โพ๏ธ and the wordonly(or an abbreviation) can be used to repeat the value of theFROMfield ๐-โ a reserved field that should always contain-for compatibility with older versions of zic ๐ซก it used to be called the TYPE field, which could hold values that let a separate script further restrict which "types" of years the rule applies to ๐งINโ the month the rule takes effect ๐ท month names can be abbreviatedONโ the day the rule takes effect ๐ these are the recognized forms:
5 the fifth of the month
lastSun the last Sunday in the month
lastMon the last Monday in the month
Sun>=8 first Sunday on or after the eighth
Sun<=25 last Sunday on or before the 25th
A weekday name (like Sunday) or a weekday name with "last" in front (like lastSunday) can be abbreviated or spelled out in full, bestie ๐๏ธ. There must be no white space characters anywhere in the ON field, so no sneaky spaces! The "<=" and ">=" constructs can totally spill a day into the neighboring month ๐ญ. For example, the IN-ON combo Oct Sun>=31 means the first Sunday on or after October 31, even if that Sunday lands in November. Chaotic, but iconic ๐โจ
AT ๐ฐ๏ธ
AT is where you set the time of day the rule kicks in, measured relative to 00:00, the start of a calendar day. Here are the forms that are recognized:
2 time in hours
2:00 time in hours and minutes
01:28:14 time in hours, minutes, and seconds
00:19:32.13 time with fractional seconds
12:00 midday, 12 hours after 00:00
15:00 3 PM, 15 hours after 00:00
24:00 end of day, 24 hours after 00:00
260:00 260 hours after 00:00
-2:30 2.5 hours before 00:00
- equivalent to 0
Okay, so zic rounds times to the nearest integer second (ties go to the even integer), but the fractions can still be useful for other apps that need more precision ๐ค๐ซถ. The source format doesn't specify any maximum precision, so it's giving open-ended vibes. Any of these forms can end with the letter w if the time is local or "wall clock" time, s if it's standard time with no daylight saving adjustment, or u (or g or z) if it's universal time. If there's no indicator at all, local (wall clock) time is assumed ๐ธ.
These forms ignore leap seconds, so if a leap second happens at 00:59:60 local time, then "1:00" means 3601 seconds after local midnight instead of the usual 3600 seconds. The whole point is that a rule line describes the moments when a clock or calendar set to the AT field's type of time would show the specified date and time of day. Main character timekeeping โฐโจ
SAVE ๐
SAVE tells you how much time gets added to local standard time while the rule is in effect, and whether the result counts as standard or daylight saving time ๐. It has the same format as the AT field, just with different suffix letters: s for standard time and d for daylight saving time. The suffix letter is usually left out, and it defaults to s if the offset is zero and to d otherwise.
Negative offsets are allowed! In Ireland, for example, daylight saving time is observed in winter and has a negative offset relative to Irish Standard Time, which is so unhinged and I love it ๐. The offset is just added to standard time, so zic does not tell apart a 10:30 standard time plus a 0:30 SAVE from a 10:00 standard time plus a 1:00 SAVE. Same result, different vibes ๐ .
LETTER/S ๐ค
LETTER/S holds the "variable part" of time zone abbreviations, like the "S" or "D" in "EST" or "EDT", to be used while this rule is in effect ๐. If this field is -, the variable part is null.
Zone lines ๐
A zone line has this form:
Zone NAME STDOFF RULES FORMAT [UNTIL]
For example:
Zone Asia/Amman 2:00 Jordan EE%sT 2017 Oct 27 01:00
Here's what each field in a zone line does ๐ง:
NAMEโ The name of the timezone. This is the name used when creating the time conversion information file for that timezone. It shouldn't contain a file name component of.or... (A file name component is a maximal substring that doesn't contain/, so be careful, bestie ๐ โโ๏ธ.)STDOFFโ The amount of time to add to UT to get standard time, with no daylight saving adjustment. It uses the same format as the AT and SAVE fields of rule lines, except there are no suffix letters. If time needs to be subtracted from UT, start the field with a minus sign โ.RULESโ The name of the rules that apply in the timezone, or else a field in the same format as a rule line's SAVE column, giving the amount of time to add to local standard time and whether the result is standard or daylight saving. If this field is-, then standard time always applies. When you give an amount of time here, only the sum of standard time and that amount actually matters ๐งฎ.FORMATโ The format for time zone abbreviations. The pair of characters%sshows where the "variable part" of the abbreviation goes. Or you can use the pair%zto stand for the UT offset in the form ยฑhh, ยฑhhmm, or ยฑhhmmss, using the shortest form that doesn't lose information. Here hh, mm, and ss are the hours, minutes, and seconds east (+) or west (-) of UT ๐. You can also use a slash (/) to separate the standard and daylight abbreviations. To conform to POSIX, a time zone abbreviation should contain only alphanumeric ASCII characters,+, and-. By convention, the abbreviation-00is a placeholder that means local time is unspecified ๐.UNTILโ The time when the UT offset or the rules change for a location. It takes the form of one to four fields:YEAR [MONTH [DAY [TIME]]]. If you specify this, the time zone info gets generated from the given UT offset and rule change until that time, which is interpreted using the rules in effect just before the transition. The month, day, and time of day use the same format as the IN, ON, and AT fields of a rule. Trailing fields can be left out, and they default to the earliest possible value for whatever's missing โณ.
The next line must be a "continuation" line. It has the same form as a zone line, except the string Zone and the name are left out, because the continuation line picks up right where the previous line's "until" information stops, in the file that the previous line used ๐ซถ. Continuation lines can have "until" information too, just like zone lines do, and that tells you the next line is yet another continuation.
If a zone changes at the exact same instant that a rule would otherwise take effect in the earlier zone or continuation line, the rule gets ignored ๐ซ. A zone or continuation line L with a named rule set starts with standard time by default. That means any of L's timestamps that come before L's earliest rule use the rule in effect after L's first transition into standard time. In a single zone it's an error if two rules take effect at the same instant, or if two zone changes take effect at the same instant ๐ญ.
If a continuation line subtracts N seconds from the UT offset after a transition that would be interpreted as later using the continuation line's UT offset and rules, then the "until" time of the previous zone or continuation line gets interpreted according to the continuation line's UT offset and rules. Any rule that would otherwise take effect in the next N seconds is instead assumed to take effect at the same time. For example:
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule US 1967 2006 - Oct lastSun 2:00 0 S
Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone America/Menominee -5:00 - EST 1973 Apr 29 2:00
-6:00 US C%sT
An incorrect reading here would be that there were two clock changes on 1973-04-29: the first from 02:00 EST (-05) to 01:00 CST (-06), and the second an hour later from 02:00 CST (-06) to 03:00 CDT (-05). But zic reads it way more sensibly, as a single transition from 02:00 CST (-05) to 02:00 CDT (-05) ๐ง โจ.
Link lines ๐
A link line looks like this:
Link TARGET LINK-NAME
For example:
Link Europe/Istanbul Asia/Istanbul
The TARGET field should show up as the NAME field in some zone line, or as the LINK-NAME field in some link line. The LINK-NAME field is an alternative name for that zone, and it uses the same syntax as a zone line's NAME field ๐. Links can chain together, but the behavior is unspecified if a chain of one or more links doesn't end at a Zone name, so don't leave it hanging ๐. A link line can even come before the line that defines its target. For example:
Link Greenwich G_M_T
Link Etc/GMT Greenwich
Zone Etc/GMT 0 - GMT
The two links are chained together, and G_M_T, Greenwich, and Etc/GMT all name the same zone ๐.
Except for continuation lines, lines can show up in any order in the input. However, the behavior is unspecified if multiple zone or link lines define the same name, so please don't do that ๐.
Leap second lines โฑ๏ธ
The file that describes leap seconds can have leap lines and an expiration line. Leap lines look like this:
Leap YEAR MONTH DAY HH:MM:SS CORR R/S
For example:
Leap 2016 Dec 31 23:59:60 + S
The YEAR, MONTH, DAY, and HH:MM:SS fields tell you when the leap second happened. The CORR field should be + if a second was added, or - if a second was skipped โโ. The R/S field should be (an abbreviation of) "Stationary" if the leap second time given by the other fields should be read as UTC, or (an abbreviation of) "Rolling" if it should be read as local (wall clock) time ๐.
Rolling leap seconds were implemented back when nobody was sure whether common practice was rolling or stationary. People were worried we'd get Times Square ball drops with a "3... 2... 1... leap... Happy New Year" countdown, putting the leap second at midnight New York time instead of midnight UTC ๐ฝ. But that countdown style never really caught on, so rolling leap seconds aren't used in practice. Also, they aren't supported if the -r option is used ๐
โโ๏ธ.
The expiration line, if there is one, looks like this:
Expires YEAR MONTH DAY HH:MM:SS
For example:
Expires 2020 Dec 28 00:00:00
The YEAR, MONTH, DAY, and HH:MM:SS fields give the expiration timestamp in UTC for the leap second table ๐ โจ.
โจ EXTENDED EXAMPLE โจ
okay bestie, this one is a whole vibe ๐ it's an extended zic input example that shows off a bunch of features at once. let's gooo ๐
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Swiss 1941 1942 - May Mon>=1 1:00 1:00 S
Rule Swiss 1941 1942 - Oct Mon>=1 2:00 0 -
Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S
Rule EU 1977 only - Sep lastSun 1:00u 0 -
Rule EU 1978 only - Oct 1 1:00u 0 -
Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
Rule EU 1996 max - Oct lastSun 1:00u 0 -
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16
0:29:45.50 - BMT 1894 Jun
1:00 Swiss CE%sT 1981
1:00 EU CE%sT
Link Europe/Zurich Europe/Vaduz
so the EU rules are for the European Union AND its older sibling, the European Communities ๐ช๐บโจ the zone is called Europe/Zurich and it's got a lowkey alias, Europe/Vaduz ๐ฆ
here's the tea โ Zurich was 34 minutes and 8 seconds east of UT until 1853-07-16 at 00:00. then the legal offset got switched to 7 degrees 26 minutes 22.50 seconds, which works out to 0:29:45.50. zic rounds that to 0:29:46, so don't be shocked ๐ after 1894-06-01 at 00:00 the UT offset became one hour and the Swiss daylight saving rules (the ones with lines starting with โRule Swissโ) kick in. from 1981 until now, the EU daylight saving rules have been running the show, and the UTC offset has stayed at one hour. it's giving consistency ๐
in 1941 and 1942, daylight saving was a thing from the first Monday in May at 01:00 until the first Monday in October at 02:00 ๐ธ the pre-1981 EU daylight-saving rules don't do anything here, but they're included for completeness, so don't panic about them. since 1981, daylight saving starts on the last Sunday in March at 01:00 UTC โญ until 1995 it ended on the last Sunday in September at 01:00 UTC, but then it switched to the last Sunday in October starting in 1996. main character glow-up ๐
for display purposes, โLMTโ and โBMTโ were the initial abbreviations, in that order ๐ง once the Swiss rules and later the EU rules got applied, the abbreviation became CET for standard time and CEST for daylight saving time. iconic ๐
๐ซถ NOTES ๐ซถ
ngl this part is important bestie ๐ญ for areas with more than two kinds of local time, you may need to use local standard time in the AT field of the earliest transition time's rule. that makes sure the earliest transition time recorded in the compiled file is actually correct โจ
also, if for some timezone a clock jump forward from the start of daylight saving happens at the same time as, and is exactly equal to, a clock jump backward from a change in UT offset, zic makes just one transition to daylight saving at the new UT offset. no change in local wall clock time at all ๐ if you want separate transitions, use multiple zone continuation lines that specify the transition instants in universal time. you love to see it ๐
๐ฆ SEE ALSO ๐ฆ
bestie that's the whole page ๐ time zone database, zic(8), all wrapped up with a bow ๐ you're literally a Unix legend now ๐๐ซถ
๐ฆ where this page comes from
- debian trixie: manpages 6.9.1-1 ยท GPL-2.0-or-later
- fedora 43: man-pages 6.13-2.fc43 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND LicenseRef-Fedora-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- fedora 43: man-pages 6.9.1-5.fc43 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND LicenseRef-Fedora-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- fedora 44: man-pages 6.13-3.fc44 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND LicenseRef-Fedora-Public-Domain AND LicenseRef-Fedora-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- opensuse-leap 16.0: man-pages 6.13-160000.2.2 ยท BSD-3-Clause AND GPL-2.0-or-later AND MIT
- ubuntu noble: manpages 6.7-2 ยท GPL-2.0-or-later
- ubuntu questing: manpages 6.9.1-1 ยท GPL-2.0-or-later
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms