Can’t set textContent of a customised built-in element except in timeout

I’m making a customised element that automatically localises it’s visual text representation:

class LocalDate extends HTMLTimeElement {
    // Specify observed attributes so that
    // attributeChangedCallback will work
    static get observedAttributes() {
        return ["datetime"];
    }   

    constructor() {
        // Always call super first in constructor
        const self = super();

        this.formatter = new Intl.DateTimeFormat(navigator.languages, { year: "numeric", month: "short", day: "numeric" });

        return self;
    }

    connectedCallback() {
        this._upgradeProperty("datetime");
    }

    attributeChangedCallback(name, oldValue, newValue) {
        if (name === "datetime") {
            this.textContent = "";
            const dateMiliseconds = Date.parse(newValue);
            if (!Number.isNaN(dateMiliseconds)) {
                const dateString = this.formatter.format(new Date(dateMiliseconds));
                // Bizarrly, this doesn't seem to work without doing this in a timeout?!?!
                setTimeout(() => this.textContent = dateString);
            }
        }
    }

    _upgradeProperty(prop) {
        if (this.hasOwnProperty(prop)) {
            let value = this[prop];
            delete this[prop];
            this[prop] = value;
        }
    }

    set datetime(value) {
        if (value instanceof Date) {
            this.setAttribute("datetime", value.toISOString());
        } else {
            this.removeAttribute("datetime");
        }
    }

    get datetime() {
        const dateMiliseconds = Date.parse(this.getAttribute("datetime"));
        if (Number.isNaN(dateMiliseconds)) {
            return null;
        }
        return new Date(dateMiliseconds);
    }
}

customElements.define('local-date', LocalDate, { extends: "time" });
<time is="local-date" datetime="2022-01-13T07:13:00+10:00">13 Jan 2022 - Still here</time>

The kicker is this line of code in the attributeChangedCallback:

setTimeout(() => this.textContent = dateString);

If it’s instead replaced with the more obvious:

this.textContent = dateString

Then instead of appearing as a date, the element displays the date string in addition to the text that was already in the element.

I’ve reproduced this in both Firefox and Chrome – any ideas what’s going on here?