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 is fat, zic adds extra data entries that work around bugs or incompatibilities in older software, like software that messes up 64-bit data ๐Ÿ˜ญ if bloat is slim, the output files stay small, which can help you hunt for those same bugs and incompatibilities ๐Ÿ” the default is slim, because software that mishandles 64-bit data usually mishandles timestamps after the year 2038 anyway ๐Ÿ’€ also see the -r option 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 slim if 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 offset 0 and the abbreviation -00 in place of the omitted timestamp data ๐Ÿซถ for example, zic -r @0 skips data meant for negative timestamps (aka before the Epoch), and zic -r @0/@2147483648 only 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 slim option 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:00 or more shows up in the input ๐Ÿ•› pre-1998 versions of zic prohibit 24:00, and pre-2007 versions prohibit times greater than 24: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 %z format ๐ŸŒ 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 L for Link, mi for min, Sa for Sat, and Su for Sun ๐Ÿ˜ญ
    • 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 -L option is used and either an Expires line is present or the -r option 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 word maximum (or an abbreviation of it) means the indefinite future โ™พ๏ธ and the word only (or an abbreviation) can be used to repeat the value of the FROM field ๐Ÿ”
  • - โ€” 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 abbreviated
  • ON โ€” 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 %s shows where the "variable part" of the abbreviation goes. Or you can use the pair %z to 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 -00 is 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) ๐Ÿง โœจ.

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