Zerowidth CleanerAll measured guides

CLAUDE WATERMARK REMOVER · PRACTICAL TEST

Why does the cleaned year 24 become 1924 with Date.UTC?

Our numeric year 24 becomes 1924 through Date.UTC, while setUTCFullYear on an epoch Date produces year 0024. The 100 and 2024 controls agree across both paths. Cleanup repairs the marked digits without choosing the intended century.

Tested October 17, 2026 · v24.19.0 · 4 measured runs

Open the Claude text cleaner · Full measured data

Code-point comparison for Marked small year

Measured inputs and outputs

These are locally constructed test strings, not evidence that Claude inserts these characters. We executed the saved homepage script snapshot with a minimal DOM harness and compared exact strings. The invisible-checkbox state and dash mode appear in each row. The observations below test this page's specific question. Destination observations run independently on the exact input and cleaned strings in the recorded Node runtime. We make no detector-score or statistical-watermark removal claim.

Before and after observations; full code points and strings are in the JSON download.
Fixture and modeInput string and code pointsOutput and cleaner statusObserved before / after
Marked small year
direct string / keep / invisible true
"2​4"
U+0032 U+200B U+0034
"24"
Removed 1 invisible character
{"yearLabel":"NaN","utcFactory":"Invalid Date","fullYearSetter":"Invalid Date"}
{"yearLabel":"24","utcFactory":"1924-01-01T00:00:00.000Z","fullYearSetter":"0024-01-01T00:00:00.000Z"}
Small year
direct string / keep / invisible true
"24"
U+0032 U+0034
"24"
No selected invisible characters found
{"yearLabel":"24","utcFactory":"1924-01-01T00:00:00.000Z","fullYearSetter":"0024-01-01T00:00:00.000Z"}
{"yearLabel":"24","utcFactory":"1924-01-01T00:00:00.000Z","fullYearSetter":"0024-01-01T00:00:00.000Z"}
Boundary year
direct string / keep / invisible true
"100"
U+0031 U+0030 U+0030
"100"
No selected invisible characters found
{"yearLabel":"100","utcFactory":"0100-01-01T00:00:00.000Z","fullYearSetter":"0100-01-01T00:00:00.000Z"}
{"yearLabel":"100","utcFactory":"0100-01-01T00:00:00.000Z","fullYearSetter":"0100-01-01T00:00:00.000Z"}
Modern year
direct string / keep / invisible true
"2024"
U+0032 U+0030 U+0032 U+0034
"2024"
No selected invisible characters found
{"yearLabel":"2024","utcFactory":"2024-01-01T00:00:00.000Z","fullYearSetter":"2024-01-01T00:00:00.000Z"}
{"yearLabel":"2024","utcFactory":"2024-01-01T00:00:00.000Z","fullYearSetter":"2024-01-01T00:00:00.000Z"}

Two UTC construction paths disagree for the same small year

The marked year contains U+200B between two and four. Number conversion is NaN before cleanup, and both date paths report Invalid Date. After deletion the year value is twenty-four. Date.UTC with month zero and day one yields an ISO timestamp beginning 1924, while setUTCFullYear on a Date initialized at the epoch yields a timestamp beginning 0024. The ordinary 24 reference repeats that discrepancy without any cleaning. We hold the month, day and UTC basis constant in both paths, so the century difference is not evidence of a timezone shift or a different calendar date supplied by the fixture. Both complete timestamps are retained in the output.

The year-100 control bounds the measured discrepancy

For the 100 reference, both paths produce January first in year 0100; for 2024, both produce January first in 2024. Those successful controls distinguish the small-year behavior from a general inability to represent historical dates. The reference algorithm for Date.UTC defines its legacy treatment of small numeric years, but this four-row experiment measures only twenty-four, one hundred and two thousand twenty-four plus the marked spelling. It does not exhaust all boundary values, test negative years or implement a historical calendar conversion. The earlier epoch guide asks whether a timestamp is in seconds or milliseconds. This guide instead starts with a numeric calendar-year field and constructs a UTC instant.

Choose whether a short year is literal or abbreviated

Before building a date, define whether a field such as 24 denotes the literal year twenty-four, an abbreviation for a modern year, or invalid input. Select a construction path that follows that contract, and verify the resulting full year rather than assuming that successful construction implements it. Avoid silently changing a century based only on how the input looks. Keep a known small-year control when migrating date code because the two APIs can agree for modern dates and still disagree for this case. The cleaner’s one-character removal fixes parsing in the marked fixture, while the destination’s year policy explains the resulting century. No real user record or Claude sample is modified in this experiment.

Reproduce this test

Save reproduce.cjs and tested-app.js in the same folder. Run the command below with Node.js. The harness prints its runtime, script SHA-256 and every measured row. Compare those rows with the original record. Using a newer script or runtime creates a new experiment; retain the version information with your rerun.

node reproduce.cjs

Reference and next check

ECMAScript Date.UTC provides the relevant primary definition. The table and fixture analysis are original measurements. For broader inspection, use our Unicode inspector. Read the scope distinction before interpreting cleanup as a watermark result.