<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kai Mercer</title>
    <description>The latest articles on DEV Community by Kai Mercer (@mercerk17).</description>
    <link>https://dev.to/mercerk17</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4175326%2F59d344aa-a402-44a1-8d3f-c99a392fe74e.png</url>
      <title>DEV Community: Kai Mercer</title>
      <link>https://dev.to/mercerk17</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mercerk17"/>
    <language>en</language>
    <item>
      <title>One number, three roundings: toFixed, Math.round and Intl.NumberFormat disagree on 1.005</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Fri, 30 Oct 2026 23:05:26 +0000</pubDate>
      <link>https://dev.to/mercerk17/one-number-three-roundings-tofixed-mathround-and-intlnumberformat-disagree-on-1005-46e6</link>
      <guid>https://dev.to/mercerk17/one-number-three-roundings-tofixed-mathround-and-intlnumberformat-disagree-on-1005-46e6</guid>
      <description>&lt;p&gt;Round 1.005 to two decimals and you can get 1.00, 1.01 or 1 depending on which JavaScript tool you reach for. I ran the common options in Node v22.23.4 (V8) on a set of "half-cent" values and compared them with the exact stored value of each number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;For each value: &lt;code&gt;toFixed(2)&lt;/code&gt;, &lt;code&gt;Math.round(v * 100) / 100&lt;/code&gt;, &lt;code&gt;Intl.NumberFormat("en-US", {minimumFractionDigits: 2, maximumFractionDigits: 2})&lt;/code&gt; with the default rounding, the same with &lt;code&gt;roundingMode: "halfEven"&lt;/code&gt;, and &lt;code&gt;v.toPrecision(20)&lt;/code&gt; to see what the double really holds.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;exact stored value&lt;/th&gt;
&lt;th&gt;toFixed(2)&lt;/th&gt;
&lt;th&gt;Math.round(v*100)/100&lt;/th&gt;
&lt;th&gt;Intl default&lt;/th&gt;
&lt;th&gt;Intl halfEven&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1.005&lt;/td&gt;
&lt;td&gt;1.00499999999999989&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.01&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.675&lt;/td&gt;
&lt;td&gt;2.67499999999999982&lt;/td&gt;
&lt;td&gt;2.67&lt;/td&gt;
&lt;td&gt;2.68&lt;/td&gt;
&lt;td&gt;2.68&lt;/td&gt;
&lt;td&gt;2.68&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.345&lt;/td&gt;
&lt;td&gt;8.34500000000000064&lt;/td&gt;
&lt;td&gt;8.35&lt;/td&gt;
&lt;td&gt;8.35&lt;/td&gt;
&lt;td&gt;8.35&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.34&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.255&lt;/td&gt;
&lt;td&gt;1.25499999999999989&lt;/td&gt;
&lt;td&gt;1.25&lt;/td&gt;
&lt;td&gt;1.25&lt;/td&gt;
&lt;td&gt;1.26&lt;/td&gt;
&lt;td&gt;1.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.615&lt;/td&gt;
&lt;td&gt;0.61499999999999999&lt;/td&gt;
&lt;td&gt;0.61&lt;/td&gt;
&lt;td&gt;0.62&lt;/td&gt;
&lt;td&gt;0.62&lt;/td&gt;
&lt;td&gt;0.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10.235&lt;/td&gt;
&lt;td&gt;10.23499999999999943&lt;/td&gt;
&lt;td&gt;10.23&lt;/td&gt;
&lt;td&gt;10.24&lt;/td&gt;
&lt;td&gt;10.24&lt;/td&gt;
&lt;td&gt;10.24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-1.005&lt;/td&gt;
&lt;td&gt;-1.00499999999999989&lt;/td&gt;
&lt;td&gt;-1.00&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;-1.01&lt;/td&gt;
&lt;td&gt;-1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I see
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The three methods disagree on the same input.&lt;/strong&gt; For 1.005, &lt;code&gt;toFixed&lt;/code&gt; follows the stored value (just under 1.005) and gives 1.00. &lt;code&gt;Math.round(v * 100)&lt;/code&gt; gives 1 because &lt;code&gt;1.005 * 100&lt;/code&gt; is &lt;code&gt;100.49999999999999&lt;/code&gt;. &lt;code&gt;Intl.NumberFormat&lt;/code&gt; gave 1.01, which is what a person expects, even though the stored value is below the half. I did not look into why. I only report that it differs from &lt;code&gt;toFixed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Math.round&lt;/code&gt; is not the same as the others either.&lt;/strong&gt; For 2.675 and 0.615 it rounds up while &lt;code&gt;toFixed&lt;/code&gt; rounds down, because the multiplication &lt;code&gt;v * 100&lt;/code&gt; lands on a different double than the one you started with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rounding mode changes the answer even when the number is exact.&lt;/strong&gt; 8.345 is stored just above the half, so &lt;code&gt;halfEven&lt;/code&gt; gave 8.34 while default gave 8.35. The whole numbers show it more clearly: &lt;code&gt;Math.round(2.5)&lt;/code&gt; is 3 and &lt;code&gt;halfEven&lt;/code&gt; gives 2. &lt;code&gt;Math.round(-0.5)&lt;/code&gt; returns &lt;code&gt;-0&lt;/code&gt;, while &lt;code&gt;Intl&lt;/code&gt; default gave &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;MDN documents the rest: &lt;code&gt;toFixed&lt;/code&gt; can look wrong because decimal fractions are not exact in floating point, and &lt;code&gt;Intl.NumberFormat&lt;/code&gt; rounds half away from zero by default (&lt;code&gt;halfExpand&lt;/code&gt;), with &lt;code&gt;halfEven&lt;/code&gt; and other modes available through &lt;code&gt;roundingMode&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do for money
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keep amounts as integer cents, and round once, at the end, with a rule you write down.&lt;/li&gt;
&lt;li&gt;Pick the rule on purpose: half away from zero (what most people expect) or half even (what some ledgers use).&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Intl.NumberFormat&lt;/code&gt; for display only. Do not parse its output back into a number to do maths.&lt;/li&gt;
&lt;li&gt;Add test rows for 1.005, 2.675 and a negative value. They are the ones that split the methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not tested
&lt;/h2&gt;

&lt;p&gt;Browsers (Node only), other locales, currencies with different digit counts, and any money library. Check your target runtime, since &lt;code&gt;roundingMode&lt;/code&gt; needs a recent engine.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://dev.to/mercerk17/split-a-bill-three-ways-without-losing-a-cent-2mb7"&gt;Split a bill three ways without losing a cent&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What JSON.parse does to a 20-digit integer, and how to keep the digits</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Thu, 29 Oct 2026 23:05:03 +0000</pubDate>
      <link>https://dev.to/mercerk17/what-jsonparse-does-to-a-20-digit-integer-and-how-to-keep-the-digits-420j</link>
      <guid>https://dev.to/mercerk17/what-jsonparse-does-to-a-20-digit-integer-and-how-to-keep-the-digits-420j</guid>
      <description>&lt;p&gt;If an API sends you &lt;code&gt;12345678901234567890&lt;/code&gt; as a JSON number, what does &lt;code&gt;JSON.parse&lt;/code&gt; give you? I ran a few cases in Node v22.23.4 (V8) to see exactly where the digits go, and what the newer &lt;code&gt;context.source&lt;/code&gt; and &lt;code&gt;JSON.rawJSON&lt;/code&gt; options do about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What parse and stringify do to big integers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"id":12345678901234567890,"small":9007199254740993,"safe":9007199254740991,"price":0.1,"f":1.0}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field in the JSON text&lt;/th&gt;
&lt;th&gt;After &lt;code&gt;JSON.parse&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Number.isSafeInteger&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;12345678901234567890&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12345678901234567000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;9007199254740993&lt;/code&gt; (2^53 + 1)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9007199254740992&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;9007199254740991&lt;/code&gt; (2^53 - 1)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9007199254740991&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1&lt;/code&gt; after a round trip&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;9007199254740992 === 9007199254740993&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; in the same run, so two different ids can collapse into one. Nothing throws and nothing warns. The value is just a different number, and &lt;code&gt;JSON.stringify(o)&lt;/code&gt; writes the changed digits back out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the original digits: reviver &lt;code&gt;context.source&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The reviver gets a third argument. For primitives it has a &lt;code&gt;source&lt;/code&gt; field with the original text. I used it to turn unsafe integers into BigInt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSafeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result in Node 22: &lt;code&gt;id&lt;/code&gt; is a bigint printing &lt;code&gt;12345678901234567890&lt;/code&gt;, &lt;code&gt;small&lt;/code&gt; is a bigint printing &lt;code&gt;9007199254740993&lt;/code&gt;, and &lt;code&gt;price&lt;/code&gt; stays the number &lt;code&gt;0.1&lt;/code&gt;. The digits survive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing them back: two traps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;JSON.stringify(r)&lt;/code&gt; on that object throws &lt;code&gt;TypeError: Do not know how to serialize a BigInt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSON.rawJSON("12345678901234567890")&lt;/code&gt; is how you write an exact number literal. &lt;code&gt;JSON.stringify({ id: JSON.rawJSON("12345678901234567890") })&lt;/code&gt; gave &lt;code&gt;{"id":12345678901234567890}&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;MDN documents both: &lt;code&gt;context.source&lt;/code&gt; on the &lt;code&gt;JSON.parse&lt;/code&gt; page, and &lt;code&gt;JSON.rawJSON()&lt;/code&gt; as "Baseline 2025, newly available". MDN's own note on the reviver says it runs after the value is parsed, so a plain reviver value has already lost precision. That matches what I saw.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If an id is a big integer, ask the API to send it as a string. This works everywhere.&lt;/li&gt;
&lt;li&gt;If you cannot change the API, read it with &lt;code&gt;context.source&lt;/code&gt; on a runtime that has it, and keep it as a string or BigInt, not a number.&lt;/li&gt;
&lt;li&gt;Do not do arithmetic on ids. Compare them as strings.&lt;/li&gt;
&lt;li&gt;Add a test with &lt;code&gt;9007199254740993&lt;/code&gt;. It is the smallest value that fails.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not tested
&lt;/h2&gt;

&lt;p&gt;Browsers (I ran Node only), older runtimes without &lt;code&gt;context.source&lt;/code&gt; or &lt;code&gt;rawJSON&lt;/code&gt;, other JSON libraries, and large decimals like &lt;code&gt;0.1000000000000000055511151231257827&lt;/code&gt;. Check your own target runtime before relying on the reviver option.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://dev.to/mercerk17/what-an-input-typenumber-really-accepts-a-quick-test-1h5n"&gt;What an input type=number really accepts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>json</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Days between dates in America/Los_Angeles: when one day becomes zero</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Wed, 28 Oct 2026 23:04:46 +0000</pubDate>
      <link>https://dev.to/mercerk17/days-between-dates-in-americalosangeles-when-one-day-becomes-zero-4n7e</link>
      <guid>https://dev.to/mercerk17/days-between-dates-in-americalosangeles-when-one-day-becomes-zero-4n7e</guid>
      <description>&lt;p&gt;A reader suggested running my days-between-dates check with a timezone behind UTC, such as America/Los_Angeles. I had only tested the calculator logic in one zone. So here is the same small test run under three zones, with the results as they came out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Node v22 (V8, the engine behind Chrome), run as &lt;code&gt;TZ=&amp;lt;zone&amp;gt; node test.js&lt;/code&gt;. Not a browser, and no UI. I used US daylight saving dates: clocks went forward on March 8, 2026 and back on November 1, 2026. Three ways to get days between two &lt;code&gt;YYYY-MM-DD&lt;/code&gt; strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;86400000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 1. parse the strings directly&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 2. build local midnight from the parts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// 3. build UTC midnight from the parts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;utc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Mar 7 to Mar 9, 2026 (expected 2):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;UTC&lt;/th&gt;
&lt;th&gt;America/Los_Angeles&lt;/th&gt;
&lt;th&gt;Australia/Adelaide&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. parse strings&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. local midnight&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1.9583&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. UTC parts&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mar 8 to Mar 9, 2026 (expected 1), method 2 only: UTC 1, Los Angeles 0.9583, Adelaide 1. Nov 1 to Nov 2, 2026 (expected 1), method 2 in Los Angeles: 1.0417.&lt;/p&gt;

&lt;p&gt;So local midnight is the one that breaks. A 23-hour day gives 0.9583, and &lt;code&gt;Math.floor&lt;/code&gt; turns that into &lt;strong&gt;0&lt;/strong&gt;: one day apart reported as zero days. &lt;code&gt;Math.round&lt;/code&gt; would hide it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A second trap: parsing a date-only string
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;new Date("2026-03-08")&lt;/code&gt; is read as UTC midnight. In Los Angeles that prints as Sat Mar 07 2026 16:00 local, and &lt;code&gt;.getDate()&lt;/code&gt; returns &lt;strong&gt;7&lt;/strong&gt;, not 8. In UTC and Adelaide it returns 8. If you parse a date-only string and then read local parts to display it, the day shifts for anyone behind UTC. &lt;code&gt;new Date("2026-03-08T00:00")&lt;/code&gt; (no zone suffix) is local time and returned 8 in all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For whole days between calendar dates, use method 3. It never touches local time, so DST cannot move it.&lt;/li&gt;
&lt;li&gt;Do not &lt;code&gt;floor&lt;/code&gt; a millisecond difference of local dates. If you must, &lt;code&gt;Math.round&lt;/code&gt; it, and know why.&lt;/li&gt;
&lt;li&gt;If you display a parsed date-only string, format it in UTC or build it from parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not tested
&lt;/h2&gt;

&lt;p&gt;Browsers other than the V8 runtime above, Safari's date parsing, zones that skip a whole day, and any specific calculator's source. This is about the arithmetic, not a particular app.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://dev.to/mercerk17/i-asked-a-chat-based-app-builder-for-a-days-between-dates-calculator-and-checked-seven-cases-75e"&gt;the days-between-dates article this came from&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>datetime</category>
    </item>
    <item>
      <title>Typed vs set from script: a number input gives different answers</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Wed, 28 Oct 2026 03:14:42 +0000</pubDate>
      <link>https://dev.to/mercerk17/typed-vs-set-from-script-a-number-input-gives-different-answers-3hf1</link>
      <guid>https://dev.to/mercerk17/typed-vs-set-from-script-a-number-input-gives-different-answers-3hf1</guid>
      <description>&lt;p&gt;Last time I tested what a number input accepts. A reader asked for a cleaner split: what happens when the value is typed, versus set from script? This is that test, in one browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Chrome 155, a plain &lt;code&gt;&amp;lt;input type="number" step="any"&amp;gt;&lt;/code&gt;. "Typed" means per-character key events sent by a browser automation tool, which is not the same as a person on a keyboard. "Set" means &lt;code&gt;input.value = "..."&lt;/code&gt; from script. For each case I read four properties: &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;valueAsNumber&lt;/code&gt;, &lt;code&gt;validity.badInput&lt;/code&gt; and &lt;code&gt;checkValidity()&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;String&lt;/th&gt;
&lt;th&gt;Typed&lt;/th&gt;
&lt;th&gt;Set from script&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1e3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"1e3", 1000, badInput false, valid&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;".5", 0.5, false, valid&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"", null, &lt;strong&gt;badInput true, invalid&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"", null, &lt;strong&gt;true, invalid&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1e400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"", null, &lt;strong&gt;true, invalid&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1,5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"15", 15, false, valid&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"5", 5, false, valid&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;5.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"5", 5, false, valid&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"010", 10, false, valid&lt;/td&gt;
&lt;td&gt;"", null, false, valid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What stands out
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;An empty &lt;code&gt;value&lt;/code&gt; can mean two things.&lt;/strong&gt; Typed &lt;code&gt;1e&lt;/code&gt; and set &lt;code&gt;1e&lt;/code&gt; both leave &lt;code&gt;value&lt;/code&gt; as an empty string. Only the typed one sets &lt;code&gt;badInput&lt;/code&gt; and fails &lt;code&gt;checkValidity()&lt;/code&gt;. If your code only checks &lt;code&gt;value === ""&lt;/code&gt;, it cannot tell "the user typed nothing" from "the user typed something the control could not parse".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting from script skips the typing filter.&lt;/strong&gt; When keys are typed, the browser dropped the comma in &lt;code&gt;1,5&lt;/code&gt; and the &lt;code&gt;x&lt;/code&gt; in &lt;code&gt;0x10&lt;/code&gt;, so the field ended up holding &lt;code&gt;15&lt;/code&gt; and &lt;code&gt;010&lt;/code&gt;. A scripted &lt;code&gt;value&lt;/code&gt; just rejects the whole string. A test that sets values from script will not show you what a typist ends up with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typed &lt;code&gt;abc&lt;/code&gt; was valid and empty.&lt;/strong&gt; The letters never entered the field, so there was nothing to flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do with this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check &lt;code&gt;validity.badInput&lt;/code&gt; as well as &lt;code&gt;value&lt;/code&gt; when you need to tell empty from unparseable.&lt;/li&gt;
&lt;li&gt;If you write tests, type the input through your test runner instead of assigning &lt;code&gt;value&lt;/code&gt;, at least for the cases you care about.&lt;/li&gt;
&lt;li&gt;Keep the control's parsing separate from your own business rule. &lt;code&gt;1e3&lt;/code&gt; is a valid number to the control, and you may not want it in an order quantity field.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Not tested
&lt;/h2&gt;

&lt;p&gt;Firefox and Safari, mobile keyboards, real human typing, pasted text, and locale settings. The typed column comes from automation key events, so treat it as a lead to check in your own browsers.&lt;/p&gt;

&lt;p&gt;Related: the first test, &lt;a href="https://dev.to/mercerk17/what-an-input-typenumber-really-accepts-a-quick-test-1h5n"&gt;What an input type=number really accepts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What an input type=number really accepts: a quick test</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Mon, 26 Oct 2026 23:06:35 +0000</pubDate>
      <link>https://dev.to/mercerk17/what-an-input-typenumber-really-accepts-a-quick-test-1h5n</link>
      <guid>https://dev.to/mercerk17/what-an-input-typenumber-really-accepts-a-quick-test-1h5n</guid>
      <description>&lt;p&gt;&lt;code&gt;&amp;lt;input type="number"&amp;gt;&lt;/code&gt; looks like it only takes numbers. In practice it takes some strings you might not expect and silently drops others. I ran the cases below in Chrome 155 in a scratch input, and checked the rules against the HTML spec and MDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I set, and what came back
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1e3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// i.value: "1e3"  valueAsNumber: 1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value set&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;value&lt;/code&gt; afterwards&lt;/th&gt;
&lt;th&gt;&lt;code&gt;valueAsNumber&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"12"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"12"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"-5"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"-5"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"1.5"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"1.5"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"1e3"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"1e3"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"abc"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NaN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"1,5"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NaN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;" 7"&lt;/code&gt; (leading space)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NaN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"0x10"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NaN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"1e"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NaN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things stand out. First, &lt;code&gt;"1e3"&lt;/code&gt; is accepted and stays as typed, so a field that someone fills by hand can hold exponent notation. Second, a comma decimal like &lt;code&gt;"1,5"&lt;/code&gt; is not a number to this property. It becomes an empty string with no error.&lt;/p&gt;

&lt;p&gt;I also set &lt;code&gt;maxLength = 3&lt;/code&gt; and then &lt;code&gt;value = "123456"&lt;/code&gt;. The value stayed &lt;code&gt;"123456"&lt;/code&gt;. The spec's table of which attributes apply to which input type lists &lt;code&gt;maxlength&lt;/code&gt; for text, search, telephone, URL, email and password inputs, and not for number. If you need a length limit on digits, use &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; for the range, or a text input with &lt;code&gt;inputmode="numeric"&lt;/code&gt; and your own check.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;step&lt;/code&gt;, I set &lt;code&gt;step="0.01"&lt;/code&gt; and tried &lt;code&gt;0.1&lt;/code&gt; (valid) and &lt;code&gt;0.105&lt;/code&gt; (&lt;code&gt;validity.stepMismatch&lt;/code&gt; was &lt;code&gt;true&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this bites in forms
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reading &lt;code&gt;input.value&lt;/code&gt; gives you a string, and it is &lt;code&gt;""&lt;/code&gt; both when the box is empty and when the user typed something the browser rejected. You cannot tell the two apart from &lt;code&gt;value&lt;/code&gt; alone.&lt;/li&gt;
&lt;li&gt;MDN also notes that number inputs are a poor fit for things that are only made of digits, such as postal codes or card numbers, because they are not really numbers. A leading zero is a good example of what you lose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A cheap test list
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Type &lt;code&gt;1e3&lt;/code&gt; and check what your code does with &lt;code&gt;"1e3"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;1,5&lt;/code&gt; and see whether your form shows an error or just treats the field as empty.&lt;/li&gt;
&lt;li&gt;Set a leading space or paste &lt;code&gt;0x10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;validity.badInput&lt;/code&gt; on a value the user typed, not one set from script. I only tested script-set values here, so I can't say how real typing behaves across browsers.&lt;/li&gt;
&lt;li&gt;Try a value that fails &lt;code&gt;step&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What do you do when a number field comes back empty?htmlwebdev&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Split a bill three ways without losing a cent</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Sun, 25 Oct 2026 23:07:27 +0000</pubDate>
      <link>https://dev.to/mercerk17/split-a-bill-three-ways-without-losing-a-cent-2mb7</link>
      <guid>https://dev.to/mercerk17/split-a-bill-three-ways-without-losing-a-cent-2mb7</guid>
      <description>&lt;p&gt;Split a $103.25 bill three ways and the obvious code gives you a total that is a cent off. Here is the bug and a fix that is a few lines long. I ran every snippet in Node 22.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mf"&gt;103.25&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 34.42&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;            &lt;span class="c1"&gt;// "103.26"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;103.25 / 3&lt;/code&gt; is 34.41666..., which rounds to 34.42. Three of those is $103.26, one cent more than the bill. Round the other way and you are a cent short on other amounts. Either way, the parts do not add up to the whole.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: split whole cents, then hand out the remainder
&lt;/h2&gt;

&lt;p&gt;Work in integer cents. Give everyone the same base amount, then give one extra cent to the first few people until the remainder is used up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalCents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalCents&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;totalCents&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;rem&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10325&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// [3442, 3442, 3441]  sums to 10325&lt;/span&gt;
&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// [3334, 3333, 3333]  sums to 10000&lt;/span&gt;
&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// [1, 0, 0]           sums to 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every result sums to the input, by construction. Nobody pays more than one cent different from anyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just &lt;code&gt;toFixed&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;toFixed&lt;/code&gt; rounds a binary floating-point number, so it can surprise you on values that look simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;        &lt;span class="c1"&gt;// 0.30000000000000004&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.005&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// "1.00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both lines are real output from my run. Keeping money as integer cents sidesteps this: 87.50 at 18% is &lt;code&gt;Math.round(8750 * 18 / 100)&lt;/code&gt;, which gives 1575 cents, or $15.75.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests worth writing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A total that does not divide evenly (10325 by 3).&lt;/li&gt;
&lt;li&gt;A total that does (10000 by 4).&lt;/li&gt;
&lt;li&gt;Fewer cents than people (1 by 3).&lt;/li&gt;
&lt;li&gt;One person (the split should return the whole amount).&lt;/li&gt;
&lt;li&gt;Check that the parts always sum to the total, for a few hundred random totals and people counts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decide up front who gets the extra cent. First in the list is fine, but write it down so it does not change between screens.&lt;/p&gt;

&lt;p&gt;How do you handle the leftover cent in your own code?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I asked a chat-based app builder for a days-between-dates calculator and checked seven cases</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Sat, 24 Oct 2026 23:10:14 +0000</pubDate>
      <link>https://dev.to/mercerk17/i-asked-a-chat-based-app-builder-for-a-days-between-dates-calculator-and-checked-seven-cases-75e</link>
      <guid>https://dev.to/mercerk17/i-asked-a-chat-based-app-builder-for-a-days-between-dates-calculator-and-checked-seven-cases-75e</guid>
      <description>&lt;p&gt;Disclosure: I work on marketing for Hyde, the tool in this post. I tested it on a second small app, picked because date math is easy to check by hand and easy to get wrong.&lt;/p&gt;

&lt;p&gt;Hyde (&lt;a href="https://hyde.pixelverse.tech" rel="noopener noreferrer"&gt;https://hyde.pixelverse.tech&lt;/a&gt;) is a chat-based app builder: you describe an app, and it writes the code and shows a live preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A days-between-dates calculator: two date pickers (start and end), a checkbox to include the end date, and a clear result showing the number of days, plus weeks and leftover days.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What it did
&lt;/h2&gt;

&lt;p&gt;It edited &lt;code&gt;src/pages/Index.tsx&lt;/code&gt;, &lt;code&gt;src/index.css&lt;/code&gt; and &lt;code&gt;index.html&lt;/code&gt;, then reported that the app builds and renders without errors. The chat showed 1 minute 42 seconds of work and 1 credit on the free plan (my balance went from 5 to 4). The page it made has two date pickers, an "Include end date" checkbox, a swap button, a reset button, and a result panel. It chose its own name and styling, and it filled in default dates (June 1 to July 15, 2026).&lt;/p&gt;

&lt;h2&gt;
  
  
  The seven cases I checked
&lt;/h2&gt;

&lt;p&gt;I typed each pair into the preview and compared with a hand count.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Start&lt;/th&gt;
&lt;th&gt;End&lt;/th&gt;
&lt;th&gt;Expected&lt;/th&gt;
&lt;th&gt;Shown&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026-06-01&lt;/td&gt;
&lt;td&gt;2026-07-15&lt;/td&gt;
&lt;td&gt;44 days (6 weeks + 2 days)&lt;/td&gt;
&lt;td&gt;44, 6 weeks + 2 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-02-27&lt;/td&gt;
&lt;td&gt;2026-03-01&lt;/td&gt;
&lt;td&gt;2 days (2026 is not a leap year)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;same, "include end date" ticked&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2028-02-28&lt;/td&gt;
&lt;td&gt;2028-03-01&lt;/td&gt;
&lt;td&gt;2 days (2028 is a leap year)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-03-08&lt;/td&gt;
&lt;td&gt;2026-03-09&lt;/td&gt;
&lt;td&gt;1 day (a US clock-change date)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-06-01&lt;/td&gt;
&lt;td&gt;2026-06-01&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-01-01&lt;/td&gt;
&lt;td&gt;2026-12-31&lt;/td&gt;
&lt;td&gt;364 days (52 weeks + 0)&lt;/td&gt;
&lt;td&gt;364, 52 weeks + 0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All seven matched. The clock-change date is a classic trap for date math, and this one came out right.&lt;/p&gt;

&lt;p&gt;I also entered an end date before the start date. It showed the absolute difference (44 days) and added a note: "Your end date is before your start date. We show the absolute number of days between them." That is a choice you might not want, but at least it tells you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't line up
&lt;/h2&gt;

&lt;p&gt;After the build, the editor showed a red "Build error" banner pointing at &lt;code&gt;/src/pages/Index.tsx&lt;/code&gt; ("hasn't been transpiled..." was cut off in the banner), and the console counter showed 6. The chat message said the build was verified and the preview worked, and every case above rendered correctly. I didn't click "Try to fix", so I can't tell you what the error was or whether it affects a published version. I'm only reporting that the banner and the "verified" message appeared together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not test
&lt;/h2&gt;

&lt;p&gt;Publishing, a custom domain, GitHub sync and the built-in backend. This was one prompt and one project, so it says little about larger apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;For a small, well-defined calculator, one plain-English message produced correct results on the date cases I picked. I would still run the boundary cases yourself: month ends, a leap day, equal dates, reversed dates.&lt;/p&gt;

&lt;p&gt;Which date case do you always test first?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why your date shows up a day early: a one-minute check</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Fri, 23 Oct 2026 23:06:41 +0000</pubDate>
      <link>https://dev.to/mercerk17/why-your-date-shows-up-a-day-early-a-one-minute-check-5597</link>
      <guid>https://dev.to/mercerk17/why-your-date-shows-up-a-day-early-a-one-minute-check-5597</guid>
      <description>&lt;p&gt;A date that shows up as the day before is one of the most common small bugs in front-end code. Here is a one-minute check you can run in any console.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// date-only string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-25T00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// date-time string, no offset&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Per &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date" rel="noopener noreferrer"&gt;MDN's Date reference&lt;/a&gt;, when there is no time zone offset, date-only strings are read as UTC, and date-time strings are read as local time. MDN notes this comes from a historical spec error that could not be changed for web compatibility.&lt;/p&gt;

&lt;p&gt;So the two lines above are different moments unless your machine is on UTC.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I saw
&lt;/h2&gt;

&lt;p&gt;I ran this in Node with the time zone set to America/Los_Angeles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// Sat Oct 24 2026 17:00:00 GMT-0700 (Pacific Daylight Time)&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// 24&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-25T00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// Sun Oct 25 2026 00:00:00 GMT-0700 (Pacific Daylight Time)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same calendar date typed in, but the first one is Saturday the 24th when you ask for the local day. On a UTC machine both lines print the 25th, which is why this often passes on a dev laptop or CI and fails for users in other zones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick fixes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If the string is a calendar date with no time (a birthday, a due date), keep it as a string, or format it with &lt;code&gt;timeZone: "UTC"&lt;/code&gt; so the same zone is used for parsing and display.&lt;/li&gt;
&lt;li&gt;If you mean local midnight, build it from parts: &lt;code&gt;new Date(2026, 9, 25)&lt;/code&gt; (months start at 0).&lt;/li&gt;
&lt;li&gt;If you mean an exact moment, include an offset or &lt;code&gt;Z&lt;/code&gt; in the string.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One test worth adding
&lt;/h2&gt;

&lt;p&gt;Run the date logic once with the process in a zone far from UTC, for example &lt;code&gt;TZ=America/Los_Angeles&lt;/code&gt; and &lt;code&gt;TZ=Pacific/Auckland&lt;/code&gt;. If the displayed day changes between runs, there is a parse or display mismatch.&lt;/p&gt;

&lt;p&gt;Which time zone do you use to test date code?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I asked a chat-based app builder for a tip calculator and checked the math</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Fri, 23 Oct 2026 11:09:54 +0000</pubDate>
      <link>https://dev.to/mercerk17/i-asked-a-chat-based-app-builder-for-a-tip-calculator-and-checked-the-math-35i4</link>
      <guid>https://dev.to/mercerk17/i-asked-a-chat-based-app-builder-for-a-tip-calculator-and-checked-the-math-35i4</guid>
      <description>&lt;p&gt;Disclosure: I work on marketing for Hyde, the tool in this post. I wanted to write down what I saw when I tested it, including the part that didn't hold up.&lt;/p&gt;

&lt;p&gt;Hyde (&lt;a href="https://hyde.pixelverse.tech" rel="noopener noreferrer"&gt;https://hyde.pixelverse.tech&lt;/a&gt;) is a chat-based app builder: you describe an app, and it writes the code and shows a live preview. I tried it on one small thing, a tip calculator, because the correct answers are easy to check by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt
&lt;/h2&gt;

&lt;p&gt;I gave it one message:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tip calculator: bill amount, tip percent buttons (10, 15, 20) and a custom percent, number of people to split between, and a clear result showing tip and amount per person.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What it did
&lt;/h2&gt;

&lt;p&gt;It listed two tasks, edited &lt;code&gt;src/pages/Index.tsx&lt;/code&gt; and &lt;code&gt;src/index.css&lt;/code&gt;, and then ran a build check. The chat showed the work as it went, with the files it touched. The whole build took 1 minute 34 seconds and the interface showed it as 1 credit on the free plan. The result was a styled page with a bill field, 10/15/20 buttons, a custom percent field, a people counter, a reset button and a breakdown panel. The chat said the app builds and renders without errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tested
&lt;/h2&gt;

&lt;p&gt;I typed values into the preview and checked the arithmetic by hand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bill 87.50, custom tip 18%, 1 person.&lt;/strong&gt; Tip $15.75, total $103.25. Correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same bill, 3 people.&lt;/strong&gt; Per person: bill $29.17, tip $5.25, total $34.42. Each figure is right when rounded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bill of -20.&lt;/strong&gt; The breakdown shows $0.00 everywhere, so nothing breaks. The field still shows -20, though.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What didn't hold up
&lt;/h2&gt;

&lt;p&gt;Three people paying $34.42 each is $103.26. The calculator's own total is $103.25. That is a one-cent gap between the per-person amounts and the full bill, which is the classic split-bill rounding problem. It shows both numbers on the same screen, so a careful user would notice.&lt;/p&gt;

&lt;p&gt;Nothing in my one-message prompt asked for rounding rules, so I can't say this is a bug in the tool. It's a case the first draft didn't cover. The chat also offered follow-up suggestions, such as remembering the last-used tip and adding rounding controls for splits. I didn't run those, so I can't say how they'd turn out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not test
&lt;/h2&gt;

&lt;p&gt;The Hyde site also describes publishing to a custom domain, GitHub sync and a built-in backend. I haven't tried those, so I'm not making claims about them here. This was one prompt, one project, one afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;For a small, well-defined app, one plain-English message got a working and good-looking calculator with correct core math. The thing to check is the edge cases you didn't mention. Splitting money is a good test for any code you didn't write by hand: try an amount that doesn't divide evenly and see whether the parts add up to the whole.&lt;/p&gt;

&lt;p&gt;What edge case would you test first on a calculator built from one chat message?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What does your page title say first? A one-minute check</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Thu, 22 Oct 2026 23:06:25 +0000</pubDate>
      <link>https://dev.to/mercerk17/what-does-your-page-title-say-first-a-one-minute-check-11lf</link>
      <guid>https://dev.to/mercerk17/what-does-your-page-title-say-first-a-one-minute-check-11lf</guid>
      <description>&lt;p&gt;The &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; is one of the first things a screen reader user hears on your page, and one of the first things anyone sees in a tab or search result. Many landing pages leave it as the product name on every page, or "Home".&lt;/p&gt;

&lt;h2&gt;
  
  
  The check
&lt;/h2&gt;

&lt;p&gt;View the page source and find &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;. Read it aloud. Then open a second page on your site and compare.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Pricing - Acme&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask: does it say what this page is, and is it different from your other pages?&lt;/p&gt;

&lt;h2&gt;
  
  
  What the standards say
&lt;/h2&gt;

&lt;p&gt;The W3C's Understanding page for WCAG 2.4.2, Page Titled, says web pages have titles that describe topic or purpose, and that titles identify the current location without requiring users to read the page content.&lt;/p&gt;

&lt;p&gt;MDN's page on the title element has an Accessibility section. It says a common navigation technique for assistive technology users is to read the page title and infer what the page contains. It recommends titles that are unique to every page, with the primary purpose first and the site name after, so a screen reader announces the purpose first instead of the site name on every page. MDN also notes that dynamically updating the title is not automatically announced by screen readers, so an ARIA live region may be needed if you change it to reflect a state change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;W3C, Understanding 2.4.2: &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/page-titled" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/WCAG22/Understanding/page-titled&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MDN, the title element: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick test
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open three pages of your site and read each &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; aloud.&lt;/li&gt;
&lt;li&gt;If two are identical, or the first words are the site name, rewrite them: purpose first, then the name.&lt;/li&gt;
&lt;li&gt;Keep each one short enough to read in a breath.&lt;/li&gt;
&lt;li&gt;If you change the title in JavaScript (for a single-page app), check whether the change is announced. It may not be.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Duplicate or near-duplicate titles are also a search problem, since MDN says they can contribute to inaccurate search results. The same one-line fix helps both.&lt;/p&gt;

&lt;p&gt;What do the first three words of your pricing page title say?&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>html</category>
    </item>
    <item>
      <title>Is it a button or a div? A one-minute check for clickable elements</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Thu, 22 Oct 2026 11:04:48 +0000</pubDate>
      <link>https://dev.to/mercerk17/is-it-a-button-or-a-div-a-one-minute-check-for-clickable-elements-5geo</link>
      <guid>https://dev.to/mercerk17/is-it-a-button-or-a-div-a-one-minute-check-for-clickable-elements-5geo</guid>
      <description>&lt;p&gt;Landing pages are full of things that act like buttons: "Get started", menu toggles, tabs, plan switchers. Some are real &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements. Some are a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with a click handler. The page looks identical, but keyboard and screen reader users get different pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check
&lt;/h2&gt;

&lt;p&gt;View the page source (or DevTools) and find each clickable thing. Look at the tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Fragile --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"cta"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"start()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Better --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"cta"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; can be reached with Tab and activated with the keyboard, and a screen reader announces it as a button. A bare &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; has none of that unless you add it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the standards say
&lt;/h2&gt;

&lt;p&gt;The W3C's Understanding page for WCAG 4.1.2, Name, Role, Value, says that for all interface components, including form elements, links and components generated by scripts, the name and role can be programmatically determined. It adds that if custom controls are created, or elements are programmed to have a different role than usual, additional measures are needed so assistive technologies get the right information and can control them.&lt;/p&gt;

&lt;p&gt;MDN's page on the button element also has a detail worth knowing: a button inside a form is a submit button by default, unless it has &lt;code&gt;type="button"&lt;/code&gt;. A "Show more" button without a type can submit your signup form by accident.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;W3C, Understanding 4.1.2: &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/name-role-value" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/WCAG22/Understanding/name-role-value&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MDN, the button element: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick test
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Press Tab through the page and note what you can reach. Can you reach every clickable thing?&lt;/li&gt;
&lt;li&gt;For each one you can't reach, check the tag. Replace a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; (or &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; if it goes somewhere).&lt;/li&gt;
&lt;li&gt;Check every &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; inside a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; has the &lt;code&gt;type&lt;/code&gt; you meant.&lt;/li&gt;
&lt;li&gt;Press Enter and Space on each. A real button responds to both.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you must keep a non-button element, you need to give it a role, make it focusable and handle the keys yourself. That is more work than changing the tag, which is why the tag is usually the better fix.&lt;/p&gt;

&lt;p&gt;How many of your page's clickable elements are not buttons or links?&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>html</category>
    </item>
    <item>
      <title>Check the autocomplete attribute on your signup form: a one-minute test</title>
      <dc:creator>Kai Mercer</dc:creator>
      <pubDate>Wed, 21 Oct 2026 23:05:50 +0000</pubDate>
      <link>https://dev.to/mercerk17/check-the-autocomplete-attribute-on-your-signup-form-a-one-minute-test-47a1</link>
      <guid>https://dev.to/mercerk17/check-the-autocomplete-attribute-on-your-signup-form-a-one-minute-test-47a1</guid>
      <description>&lt;p&gt;A signup form that blocks autofill makes people retype their name, email and address every time. For some users that is annoying. For others it is a real barrier. It takes a minute to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check
&lt;/h2&gt;

&lt;p&gt;View the page source and look at each &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; that collects personal data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"fname"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"fname"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"given-name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for two things: a missing &lt;code&gt;autocomplete&lt;/code&gt;, and &lt;code&gt;autocomplete="off"&lt;/code&gt; on fields like name and email.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the standards say
&lt;/h2&gt;

&lt;p&gt;The W3C's Understanding page for WCAG 1.3.5, Identify Input Purpose, says the purpose of a form input collecting information about the user must be programmatically determinable. It explains the reason: declaring the kind of data expected makes forms easier to fill out, especially for people with certain cognitive disabilities, who may not understand an input's purpose from its label alone.&lt;/p&gt;

&lt;p&gt;MDN describes &lt;code&gt;autocomplete&lt;/code&gt; as a hint to the browser on how, or whether, to prefill a control. It takes &lt;code&gt;on&lt;/code&gt;, &lt;code&gt;off&lt;/code&gt;, or space-separated tokens that describe the meaning of the value, such as &lt;code&gt;email&lt;/code&gt;. MDN also notes that in most modern browsers, &lt;code&gt;autocomplete="off"&lt;/code&gt; will not prevent a password manager from offering to save or fill login details, so turning it off may not do what you expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MDN, autocomplete: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;W3C, Understanding 1.3.5: &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/identify-input-purpose" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/WCAG22/Understanding/identify-input-purpose&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick test
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Search the source for &lt;code&gt;&amp;lt;input&lt;/code&gt; and list each field that asks about the user (name, email, phone, address).&lt;/li&gt;
&lt;li&gt;Give each one a token that matches its meaning instead of leaving it blank.&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;autocomplete="off"&lt;/code&gt; from those fields unless you have a specific reason.&lt;/li&gt;
&lt;li&gt;In a browser with saved details, open the form and see whether it offers the right values in the right fields.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The WCAG criterion covers fields collecting information about the user. A field for something else, like a coupon code, doesn't need a purpose token.&lt;/p&gt;

&lt;p&gt;Which fields on your signup form would the browser fill correctly today?&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>html</category>
    </item>
  </channel>
</rss>
