0

Using JavaScript it is not easy to set the value of an html input of the type datetime-local.

input.valueAsNumber

document.getElementById("dateInput").valueAsNumber = new Date("Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)").valueOf();

The following does not work unless you happen to be in the UTC timezone. valueAsNumber accepts a numeric representation of the datetime but it doesn't convert the UTC numeric representation to the local timezone.

input.valueAsDate

document.getElementById("dateInput").valueAsDate = new Date("Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)");

The following returns "Uncaught DOMException: Failed to set the 'valueAsDate' property on 'HTMLInputElement': This input element does not support Date values."

input.value

document.getElementById("dateInput").value = "Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)";

The following returns "The specified value "Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)" does not conform to the required format. The format is "yyyy-MM-ddThh:mm" followed by optional ":ss" or ":ss.SSS""

Bill Christo
  • 1,223
  • 9
  • 8
  • 1
    If you are to use the output of *Date.prototype.toString*, then you should parse the string and create a timestamp that suits your purpose. Only the month name needs to be converted to a number, the rest of what you need is in the string without modification. See [*Date.toISOString() but local time instead of UTC*](https://stackoverflow.com/questions/49330139/date-toisostring-but-local-time-instead-of-utc) to use a *Date* object directly. – RobG Mar 31 '23 at 01:18

3 Answers3

1

The following is best IMHO because there is no library, no parsing and no new functions. (Though you could of course put this in a function if you use it in many places.)

let newdt = new Date("Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)");
document.getElementById("dateInput").valueAsNumber = (newdt.valueOf()-newdt.getTimezoneOffset()*60000);

I too have found this a very annoying gap in JS functionality. I would have expected an option in Date.toISOString() to specify the timezone of the output, or perhaps another method to return the ISO format in the local timezone.

Alternatively, as a function to set INPUT.value instead of INPUT.valueAsNumber (which I do so as to handle all INPUTs with the same code):

function toISOLocal(adate) {
    var localdt = new Date(adate - adate.getTimezoneOffset()*60000);
    return localdt.toISOString().slice(0, -1); 
}

newdt = new Date("Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)");
document.getElementById("dateInput").value = toISOLocal(newdt);
AllAboutMike
  • 121
  • 7
0
let date = new Date("Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)");
    
const formatDate = (date) => {
      return date.getFullYear() + "-" + (date.getMonth()+1).toString().padStart(2, '0') + "-" + date.getDate() + "T" + date.getHours().toString().padStart(2, '0') + ":" + date.getMinutes().toString().padStart(2, '0');
}

document.getElementById("dateInput").value = formatDate(date);

The following is how this would be accomplished. I posted this question/answer to save someone else the trouble of getting to this solution.

Bill Christo
  • 1,223
  • 9
  • 8
  • Why not just use `.toISOString()`??? – Bergi Mar 31 '23 at 10:01
  • toISOString is in UTC. When you set the value of a ```datetime-local``` type input it assumes local time so with toISOString you would inadvertently offset the time by the difference between local time and UTC. – Bill Christo Mar 31 '23 at 18:52
0

If you are to use the output of Date.prototype.toString, then you should parse the string and create a timestamp that suits your purpose. Only the month name needs to be converted to a number, the rest of what you need is in the string without modification.

See Date.toISOString() but local time instead of UTC to use a Date object directly.

Below is an example of parsing the output of Date.prototype.toString and reformatting it.

/* Reformat timestamp in Date#toString format to ISO 8601 local
 * i.e. without offset.
 *
 * @param {string} s - timestamp in ddd MMM DD YYYY HH:mm:ss format
 *                     default is current date
 * @returns {string} timestamp reformatted as YYYY-MM-DDTHH:mm:ss
 */
function reformatDateAsISO(s = new Date().toString()) {
  let pad = n => (n < 10? '0':'') + n;
  let months = [,'Jan','Feb','Mar','Apr','May','Jun',
                 'Jul','Aug','Sep','Oct','Non','Dec'];
  let [day, mon, date, year, time, rest] = s.split(' ');
  return `${year}-${pad(months.indexOf(mon))}-${date}T${time}`;
}

["Thu Mar 30 2023 12:54:17 GMT+0000 (UTC)",
 new Date().toString()
].forEach(s => console.log(s + '\n' + reformatDateAsISO(s)));
RobG
  • 142,382
  • 31
  • 172
  • 209
  • Thanks for the reply. Yes, I suppose this function achieves the goal as well. However, why reinvent the wheel by parsing the date strings generated from toString() when calling new Date already does this for us by means of Date.parse()? Furthermore, strings have a padStart function so why are you creating a function for that? – Bill Christo Mar 31 '23 at 18:45
  • @bchr02— 1. Because the question is "*…using a date string generated from Date.prototype.toString()*". If you just want to use a *Date*, see this is a duplicate, see second paragraph. 2. Because. ;-) – RobG Mar 31 '23 at 20:32
  • you’re right, my question was not properly phrased. I corrected it via an edit. But still this exact question has not been asked or answered before. The link you mention provides an answer which contains the timezone information which cannot be interpreted by a datetime-local html input value. – Bill Christo Apr 01 '23 at 01:18