Repository: prisma/prisma
File: packages/client-engine-runtime/src/interpreter/data-mapper.ts (TypeScript)

Code before:
  if (matches === null) {
    // We found no time part, so we return it as a plain zulu date,
    // e.g. '2023-10-01Z'.
    return `${dt}Z`
  }

  let dtWithTz = dt
  const [timeTz, tz, tzMinuteOffset] = matches
  if (tz !== undefined && tz !== 'Z' && tzMinuteOffset === undefined) {
    // If the timezone is specified as +HH or -HH (without minutes),
    // we need to suffix it with ':00' to make it a valid Date input.
    dtWithTz = `${dt}:00`
  } else if (tz === undefined) {
    // If the timezone is not specified at all, we suffix it with 'Z'.
    dtWithTz = `${dt}Z`
  }

  if (timeTz.length === dt.length) {
    // If the entire datetime was just the time, we prepend the unix epoch date.
    return `1970-01-01T${dtWithTz}`
  }

  // Handle 2-digit year interpretation issues for historical dates
  // JavaScript's Date constructor interprets 2-digit years as 1900-1999
  // We need to extract the year and handle it explicitly if it's less than 100
  const yearMatch = dtWithTz.match(/^(\d{1,4})-/)
  if (yearMatch) {
    const year = parseInt(yearMatch[1], 10)
    if (year < 100) {
      // For years 0-99, we need to parse manually to avoid JS Date's 2-digit year interpretation
      // Parse the datetime string manually
      const match = dtWithTz.match(
        /^(\d{1,4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(Z|[+-]\d{2}:?\d{2})?$/,
      )
      if (match) {
        const [, yearStr, month, day, hour, minute, second, fraction = '0', timezone] = match
        const ms = fraction.padEnd(3, '0').slice(0, 3)

        // Parse timezone offset if present (in minutes)
        let offsetMinutes = 0
        if (timezone && timezone !== 'Z') {
          const tzMatch = timezone.match(/^([+-])(\d{2}):?(\d{2})?$/)
          if (tzMatch) {
            const [, sign, hours, minutes = '0'] = tzMatch
            offsetMinutes = (parseInt(hours, 10) * 60 + parseInt(minutes, 10)) * (sign === '+' ? 1 : -1)
          }
        }

        // Use a safe year (2000) to avoid 2-digit year interpretation, then set the actual year
        const date = new Date(
          Date.UTC(

Review comment (performance):
at this point we know it's a date, so we could maybe just do `.split("-", 1)` and check the length of the first part
it'd probably be much more efficient than using a regex

Code after:
  if (timeTzMatches === null) {
    // We found no time part, so we return it as a plain zulu date,
    // e.g. '2023-10-01T00:00Z'.
    // We append the time because the JS Date constructor can't parse
    // pre-1000 dates with a timezone, for example '0032-01-01Z' parses
    // as '2032-01-01T00:00:00.000Z'.
    return `${dt}T00:00:00Z`
  }

  let dtWithTz = dt
  const [timeTz, tz, tzMinuteOffset] = timeTzMatches
  if (tz !== undefined && tz !== 'Z' && tzMinuteOffset === undefined) {
    // If the timezone is specified as +HH or -HH (without minutes),
    // we need to suffix it with ':00' to make it a valid Date input.
    dtWithTz = `${dt}:00`
  } else if (tz === undefined) {
    // If the timezone is not specified at all, we suffix it with 'Z'.
    dtWithTz = `${dt}Z`
  }

  if (timeTz.length === dt.length) {
    // If the entire datetime was just the time, we prepend the unix epoch date.
    return `1970-01-01T${dtWithTz}`
  }

  const timeSeparatorIndex = timeTzMatches.index - 1
  // If the time part is preceded by a space, we replace it with 'T'.
  if (dtWithTz[timeSeparatorIndex] === ' ') {
    dtWithTz = `${dtWithTz.slice(0, timeSeparatorIndex)}T${dtWithTz.slice(timeSeparatorIndex + 1)}`
  }

  return dtWithTz
}