Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by CometPathfinder385

How can I prevent a leading apostrophe when inserting date strings using Google Apps Script BatchUpdate?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I'm using Google Apps Script's batchUpdate method to update cell values in a sheet. One column in my 2D array contains date values formatted as strings, so they look like this:

JAVASCRIPT
["4 October 2025", "6 January 2025"]

I set up my request as follows:

JAVASCRIPT
{ updateCells: { range: { sheetId: sheetID, startRowIndex: startRow - 1, endRowIndex: startRow + array.length, startColumnIndex: startColumn - 1, endColumnIndex: startColumn - 1 + array[0].length }, rows: _get_batch_update_type(array), fields: "userEnteredValue" } }

Here is the helper function I'm using:

JAVASCRIPT
function _get_batch_update_type(input) { //Dealing with array if (input.constructor === Array) { return input.map(row => ({ values: row.map(element => ({ userEnteredValue: (typeof element === "string" || Number.isNaN(element) ? { stringValue: element } : { numberValue: element }) })) })); } return [{ values: [{ userEnteredValue: (typeof input === "string" || Number.isNaN(input) ? { stringValue: input } : { numberValue: input }) }]}]; }

However, when I run the request, the output values in the sheet include a leading apostrophe:

BASH
+----------------+ | A | +----------------+ |'4 October 2025 | +----------------+ |'6 January 2025 | +----+-----------+

The relevant column in the sheet is formatted as a date. How can I adjust my request to avoid the apostrophe?

EDIT:

Based on a suggestion, I've modified my _get_batch_update_type() function to:

JAVASCRIPT
function _get_batch_update_type(input) { //Dealing with array if (input.constructor === Array) { return input.map(row => ({ values: row.map(element => ({ userEnteredValue: (typeof element === "string" || Number.isNaN(element) ? { stringValue: element } : element instanceof Date ? {formulaValue: `=--"${_convert_date_to_string(element)}"`} : { numberValue: element }) })) })); } return [{ values: [{ userEnteredValue: (typeof input === "string" || Number.isNaN(input) ? { stringValue: input } : input instanceof Date ? {formulaValue: `=--"${_convert_date_to_string(input)}"`} : { numberValue: input }) }]}]; }

This adjustment prevents the insertion of the leading apostrophe by converting the date string to a formula that Sheets can parse as a date.

1

Comments 0

Answers 6

Views 107

6 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

Below is an explanation and solution using a modified version of your request that converts date strings into formulas so that Sheets parses them as actual dates rather than raw strings with a preceding apostrophe.


Explanation

When you supply a date as a string with the property stringValue, Sheets treats it as plain text—even if the cell format is set to Date—which leads to the insertion of a leading apostrophe. To avoid this, you can instead:

  • Use the formulaValue property and transform your date string into a formula that forces its conversion to a date (e.g. using double unary operators or a built-in date conversion function).
  • The formula (like =--"4 October 2025") evaluates to the proper serial number that Sheets recognizes as a date, thus preventing the apostrophe from being inserted.

Your updated _get_batch_update_type() function implements this approach by checking if an element is an instance of Date. If so, it sets formulaValue to a string that converts the date string into a numeric value that Sheets will then format as a date.


Modified Code Example

JAVASCRIPT
function _get_batch_update_type(input) { // Check if the input is an array of rows if (input.constructor === Array) { return input.map(row => ({ values: row.map(element => ({ userEnteredValue: (typeof element === "string" || Number.isNaN(element)) ? { stringValue: element } : element instanceof Date ? { formulaValue: `=--"${_convert_date_to_string(element)}"` } : { numberValue: element } })) })); } // Handle single value case return [{ values: [{ userEnteredValue: (typeof input === "string" || Number.isNaN(input)) ? { stringValue: input } : input instanceof Date ? { formulaValue: `=--"${_convert_date_to_string(input)}"` } : { numberValue: input } }] }]; }

How This Works

  • For non-date values:
    The function continues to set stringValue for strings and numberValue for numbers as before.

  • For Date objects:
    The function uses a helper (like _convert_date_to_string(element)) to convert the date into a formatted string (for example, "4 October 2025"). It then prefixes it with =--" and suffixes the double quote so that when Sheets evaluates the cell, the leading =-- coerces the string into a number (the internal representation of the date). This prevents Sheets from inserting an apostrophe, and it displays the date according to the cell’s date format.


Final Note

Remember to implement the helper function _convert_date_to_string() according to your desired format so that the date string is recognized correctly by Sheets. This solution leverages the power of formula evaluation in Google Sheets via the batchUpdate method.

This approach should resolve the issue with the leading apostrophe while maintaining the correct date formatting in your sheet.

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by UranianScholar570 1 month ago

0

If all of the input is going to be parseable dates, then try formulaValue type, and forcing it to parse dates as serial numbers using doubleunary:

JAVASCRIPT
userEnteredValue: { formulaValue: `=--"${element}"` }

If you use stringValue, dates or even numbers won't be parsed as numbers, as written in the docs:

Represents a string value. Leading single quotes are not included. For example, if the user typed '123 into the UI, this would be represented as a stringValue of "123".

A better option would be to not use updateCells request, but use spreadsheets.values.batchUpdate with valueInputOption set to USER_ENTERED

No comments yet.

Answer by SupernovaScholar323 1 month ago

0

I use a function like this when setting rows:

JAVASCRIPT
const valuesToRowData = (values) => { return values.map((row) => { return { values: row.map((cell) => { const value = {}; if (cell === null || cell === undefined) { value.stringValue = ""; } else if (cell instanceof Date) { value.numberValue = dateToSerial_(cell); } else if (typeof cell === "string" && cell.startsWith("=")) { value.formulaValue = cell; } else if (typeof cell === "boolean") { value.boolValue = cell; } else if (typeof cell === "number") { value.numberValue = cell; } else if (typeof cell === "object") { // Handle JSON objects by stringify them value.stringValue = JSON.stringify(cell); } else if (typeof cell === "string") { value.stringValue = cell; } else { value.stringValue = String(cell); } return { userEnteredValue: value, }; }), }; }); }; const dateToSerial_ = (date) => { if (!(date instanceof Date)) { date = new Date(date); } const timestamp = date.getTime(); let serial = timestamp / MILLISECONDS_IN_A_DAY + DAYS_OFFSET_BETWEEN_SERIAL_AND_UNIX; // Subtract ET offset to align with Eastern Time serial -= ET_OFFSET_HOURS / HOURS_IN_DAY; return serial; };

No comments yet.

Answer by VoidScout520 1 month ago

0

Please you can use this code

JAVASCRIPT
function _get_batch_update_type(input) { if (Array.isArray(input)) { return input.map(row => ({ values: row.map(element => ({ userEnteredValue: convertToSheetValue(element) })) })); } return [{ values: [{ userEnteredValue: convertToSheetValue(input) }] }]; } function convertToSheetValue(value) { if (typeof value === "string") { let parsedDate = new Date(value); if (!isNaN(parsedDate.getTime())) { return { numberValue: parsedDate.getTime() / 86400000 + 25569 }; } return { stringValue: value }; // If not a valid date, keep as string } return { numberValue: value }; }

No comments yet.

Answer by AsteroidNomad770 1 month ago

0

PLease Flow this

JAVASCRIPT
function _get_batch_update_type(input) { if (Array.isArray(input)) { return input.map(row => ({ values: row.map(element => ({ userEnteredValue: convertToSheetValue(element) })) })); } return [{ values: [{ userEnteredValue: convertToSheetValue(input) }] }]; } function convertToSheetValue(value) { if (typeof value === "string") { let dateSerial = parseDateToSerial(value); if (dateSerial !== null) { return { numberValue: dateSerial }; } return { stringValue: value }; // Keep as string if not a valid date } return { numberValue: value }; } // Convert a date string (e.g., "4 October 2025") into a Google Sheets serial number function parseDateToSerial(dateString) { let parts = dateString.match(/^\(\d{1,2}\) (\w+) (\d{4})$/); if (!parts) return null; // Return null if format is invalid let day = parseInt(parts[1], 10); let month = getMonthIndex(parts[2]); let year = parseInt(parts[3], 10); if (month === -1) return null; // Invalid month name // Calculate Google Sheets serial number (ignoring timezone issues) let date = new Date(year, month, day); return Math.floor(date.getTime() / 86400000) + 25569; } // Map month names to their index (0 = Jan, 11 = Dec) function getMonthIndex(monthName) { const months = [ "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" ]; return months.indexOf(monthName.toLowerCase()); }

Manually extracts the date components (day, month, year) to avoid timezone shifts.

✅ Calculates the Google Sheets serial number manually using Math.floor(date.getTime() / 86400000) + 25569.

✅ Ensures date-only values (no hidden time component).

✅ Works regardless of the spreadsheet's timezone settings.

No comments yet.

Answer by UranianCommander594 1 month ago

0
JAVASCRIPT
function convtodates() { const mA = ["January","February","March","April","May","June","July","August","September","October","November","December"] const ss = SpreadsheetApp.getActive(); const sh = ss.getSheetByName("Sheet0"); const vs = sh.getDataRange().getDisplayValues(); const dts = vs.map(e => { let t = e.toString().split(" "); let d = Number(t[0].trim()); let m = mA.indexOf(t[1].trim()); let y = Number(t[2].trim()); return [new Date(y,m,d)] }) Logger.log(JSON.stringify(dts).replace(/],/,'],\n')) } Execution log 10:44:34AM Notice Execution started 10:44:32AM Info [["2025-10-04T06:00:00.000Z"], ["2025-01-06T07:00:00.000Z"]] 10:44:36AM Notice Execution completed

Try it in your code this way:

JAVASCRIPT
function convtodates(datestring) { const mA = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] let t = datestring.split(" "); let d = Number(t[0].trim()); let m = mA.indexOf(t[1].trim()); let y = Number(t[2].trim()); return new Date(y, m, d); }

No comments yet.

Discussion

No comments yet.