javascript converting datestring to epoch returns three digits too much

77 views Asked by At

I am converting a string to epoch like this:

    arrival = $('#aircraft_arrival_time').val();
console.log(arrival); //2023-12-09T14:03
    temp = arrival.split("T");
    arrivalDatePart = temp[0];
    arrivalDate = arrivalDatePart + "T00:00:00.000Z";
console.log(arrivalDate); //2023-12-09T00:00:00.000Z
    chartFrom = Date.parse(arrivalDate); //beginning of that day, UTC
console.log(chartFrom); //1702080000000

    var f = new Date(0); // The 0 there is the key, which sets the date to the epoch
    f.setUTCSeconds(chartFrom);
console.log(f); //Tue Oct 09 55906 02:00:00 GMT+0200 (centraleuropeisk sommartid)

The trouble is that it returns the epoch in milliseconds, and while running that through something like https://www.epochconverter.com/ it will be identified as millisecond format, and correctly interpreted as 9 December 2023 rather than the year 55906 =)

I assume I could check the length of chartFrom and divide by 1000 if the length is unexpectedly long, but is there a clean way to do it right?

enter image description here

enter image description here

2

There are 2 answers

1
Vadim On BEST ANSWER

it's okay, js (for example Date.now()) brings 3 more symbols because of milliseconds dimension

to solve this use:

const jsUnixTime = 1223334444000; // not more than 13 length
const unixTime = (jsUnixTime / 1000) | 0;
console.log(unixTime, jsUnixTime);

So, your code:

const arrivalValue = '2023-12-09T14:03';
// const arrivalValue = $('#aircraft_arrival_time').val();

// 2023-12-09T14:03
console.log(arrivalValue);

const arrivalDatePart = arrivalValue.split('T')[0];
const arrivalDate = arrivalDatePart + 'T00:00:00.000Z';

// 2023-12-09T00:00:00.000Z
console.log(arrivalDate);

// beginning of that day, UTC
const chartFrom = (Date.parse(arrivalDate) / 1000) | 0;

// 1702080000000
console.log(chartFrom);

// The 0 there is the key, which sets the date to the epoch
const finalDate = new Date(0);
finalDate.setUTCSeconds(chartFrom);
console.log(finalDate);
0
zer00ne On

Going from what is posted in OP, there are a few things to point out:

  1. Keep in mind if a user inputs a date and time, they will most likely be referencing local time. Try picking the option today in the datepicker of the <input> and you'll get a local value.

  2. $("#aircraft_arrival_time") is <input id="aircraft_arrival_time" type="datetime-local">, but all you need is the date since time is set to zero hour (T00:00:00.000Z), so it might save you a step if you just use <input id="aircraft_arrival_time" type="date"> instead. The usefulness of zero hour eludes me, I would recommend using type="datetime-local" and include the actual time in the timestamps.

  3. What is the reason to set the time to zero hour? If a user inputs a flight arrival time wouldn't the exact time be a critical part of any calculation? Use .getTimezoneOffset() to get times in relation to the local value of user datetime.

  4. Use .valueAsNumber property to get a timestamp of the <input> value.

  5. If you still need to get zero hour, use .setHours() and/or .setUTCHours().

Details on what was listed above are commented in the JavaScript and displayed in the HTML of the example below.

const main = document.forms.main;
const m = main.elements;

main.oninput = displayValue;

function displayValue(e) {
  const primary = e.target;
  Array.from(m.data).forEach(io => {
    if (io != primary) {
      io.value = "";
      m[io.id + "out"].value = "";
    }
  });
  m[primary.id + "out"].value = primary.value;

  /**
   * This part of the code is relevant the previous 
   * part is for demonstration purposes.
   */
  // Get the local timezone offset in ms.
  const timezone = new Date().getTimezoneOffset() * 60000;
  m.tz.value = timezone;

  /**
   * Convert <input> .value into a timestamp.
   * Since the user will enter a local datetime, subtract
   * the timezone offset to get UTC in relation to local datetime.
   * In contrast, add the local timezone offset to get the 
   * local datetime. 
   * Note: these calculations DO NOT return a true datetime.
   * The timestamps are modified because the Date
   * constructor returns a local value which will be 
   * different than what the user actually entered.
   */
  const utcStamp = primary.valueAsNumber - timezone;
  m.utcTS.value = utcStamp;

  const locStamp = primary.valueAsNumber + timezone;
  m.locTS.value = locStamp;

  // Get strings of the datetime
  let utc = new Date(utcStamp).toUTCString();
  m.utc.value = utc;

  let loc = new Date(locStamp);
  m.loc.value = loc;

  // Set datetime to zero hour.
  let utcZero = new Date(utcStamp)
  utcZero.setUTCHours(0, 0, 0, 0);
  m.utc0.value = utcZero.toUTCString();

  let locZero = new Date(locStamp);
  locZero.setHours(0, 0, 0, 0);
  m.loc0.value = locZero;
}
:root {
  font: 2ch/1.15 "Segoe UI"
}

fieldset {
  margin-bottom: 1rem;
}

label {
  display: block;
  margin: 0.5rem 0 0.75rem
}

label+label {
  margin-top: 1rem;
}

input {
  font: inherit;
}

code {
  color: #0263B7
}

var {
  color: #88552D
}

input,
code,
var {
  font-family: Consolas
}

sup {
  line-height: 0;
  color: tomato;
}

small {
  display: block;
  width: 80%;
  margin-left: 0.7rem;
  text-indent: -0.7rem;
  font-style: oblique;
  font-size: 0.7rem;
}

small::first-letter {
  line-height: 0;
  color: tomato;
}

code b {
  color: #4AAD4E
}

code i {
  font-style: normal;
  color: #FF6EC7;
}

hr {
  margin-top: 1.5rem;
}
<form id="main">
  <fieldset>
    <legend>Applicable Types of Inputs</legend>
    <label for="dateT">
    <pre><code>type=<b>"datetime-local"</b></code></pre>
    This is probably the input OP <em>should</em> use if a flight arrival is entered by an actual user:<sup>✤</sup>
  </label>
    <input id="dateT" name="data" type="datetime-local">
    <label for="dateT">
    <pre><var>value: </var><code><output id="dateTout">yyyy-mm-ddThh:mm:ss</output></code></pre>
  </label>
    <hr>
    <label for="dateX">
    <pre><code>type=<b>"date"</b></code></pre>
    This is probably the input OP <em>should</em> use if time is always <code>T00:00:00.000Z</code>:
  </label>
    <input id="dateX" name="data" type="date">
    <label for="dateX">
    <pre><var>value: </var><code><output id="dateXout">yyyy-mm-dd</output></code></pre>
  </label>
    <small>✤ Recommended</small>
  </fieldset>
  <fieldset>
    <legend>Dates and Times Using Various Methods</legend>
    <label>
    <pre><code>const <i>timezone</i> = new Date()<b>.getTimezoneOffset()</b> * 60000;</code></pre>
    <var>value: </var><code><output id="tz"></output></code></label>
    <hr>
    <label>
    <pre><code>const <i>utcStamp</i> = DOMObject<b>.valueAsNumber</b> - <i>timezone</i></code>;<sup>✱</sup></pre>
    <var>value: </var><code><output id="utcTS"></output></code></label>
    <label>
    <pre><code>const <i>locStamp</i> = DOMObject<b>.valueAsNumber</b> + <i>timezone</i>;</code></pre>
    <var>value: </var><code><output id="locTS"></output></code></label>
    <hr>
    <label>
    <pre><code>let <i>utc</i> = new Date(<i>utcStamp</i>)<b>.toUTCString()</b>;</code></pre>
    <var>value: </var><code><output id="utc"></output></code></label>
    <label>
    <pre><code>let <i>loc</i> = new Date(<i>locStamp</i>);</code></pre>
    <var>value: </var><code><output id="loc"></output></code></label>
    <hr>
    <label>
    <pre><code>let <i>utcZero</i> = new Date(<i>utcStamp</i>);
<i>utcZero</i><b>.setUTCHours(0, 0, 0, 0)</b>;
<i>utcZero</i><b>.toUTCString()</b>;</code></pre>
    <var>value: </var><code><output id="utc0"></output></code></label>
    <label>
    <pre><code>let <i>locZero</i> = new Date(<i>locStamp</i>);
<i>locZero</i><b>.setHours(0, 0, 0, 0)</b>;</code></pre>
    <var>value: </var><code><output id="loc0"></output></code></label>
    <small>✱ <code>DOMObject</code>s are not recognized by jQuery methods and jQuery Objects are not recognized by vanilla JavaScript methods and properties. Dereference jQuery Objects or use JavaScript to reference <code>&lt;input&gt;</code>. <br>ex. <code>$("#ID")[0]<b>.valueAsNumber</b></code> or <code>document.getElementById("ID")<b>.valueAsNumber</b></code></small>
  </fieldset>
</form>