Search code examples
javascriptjsondate

Why is Date behaving quirkily in JSON.stringify replacer?


I have JS objects that I need to stringify (to insert into Postgres). These objects contain Dates, which need to be saved as timestamps rather than ISO representations.

In the context our my application, this is most conveniently done via a JSON.stringify replacer function (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#syntax).

However, Date behaves very weirdly in there. Consider:

function replacer(key, value) {
    if (key != "temp") {
        return value
    }
    console.log(`[${key}]=${value}`)
    let areWeObjectivelyDating = this[key] instanceof Date
    let areWeSubjectivelyDating = value instanceof Date
    console.log("are we dating?")
    if (areWeObjectivelyDating) {
        console.log("> it's a date!")
    }
    else {
        console.log("> objectively, no")
    }
    if (areWeSubjectivelyDating) {
        console.log("> from my perspective? yes!")
    }
    else {
        console.log("> sorry I don't see us working out")
    }
    console.log()
    return value
}

let json = {
    temp: new Date()
}

console.log("= check replacer solo =")
replacer("temp", json["temp"])

console.log("")

console.log("= check replacer in stringify =")
JSON.stringify(json, replacer)

The output is:

= check replacer solo =
[temp]=Wed Jun 26 2024 09:20:53 GMT+0000 (Coordinated Universal Time)
are we dating?
> objectively, no
> from my perspective? yes!

= check replacer in stringify =
[temp]=2024-06-26T09:20:53.371Z
are we dating?
> it's a date!
> sorry I don't see us working out

The solo check works as expected. But when replacer is called by JSON.stringify, I can access json["temp"] via this, which gives me the actual Date object. However, value is the date already converted to an ISO string.

Why is this the case? Where is this (unexpected) behavior documented?


Solution

  • As usual, this is already answered:

    What does instanceof behave differently inside JSON.stringify()?

    In short: Date has a toJSON method which serializes before the value is passed to the replacer.