Date Formatting in JavaScript: Not Just "Concatenating Strings"
\n\nThe question "How do I format a date in JavaScript?" is one of the most popular on Stack Overflow. And for good reason. Every developer has at least once encountered a situation where they need to display a date not in the standard format "Fri Feb 14 2025 12:00:00 GMT+0300", but nicely: "February 14, 2025" or "2025-02-14". It seems simple, right? But there are plenty of pitfalls and performance issues here.
\n\nIn this article, we will cover all the ways to format dates in JavaScript: from the simplest to the most performant. You will learn how to avoid common mistakes and make your code not only clean but also fast. Let's go!
\n\nWhy is the Native Date So Inconvenient?
\n\nThe built-in Date object in JavaScript is, to put it mildly, "baggage from the past". It does not provide a built-in format() method like in Python or PHP. Instead, you have to assemble the date manually using getters:
const date = new Date();\nconst day = String(date.getDate()).padStart(2, '0');\nconst month = String(date.getMonth() + 1).padStart(2, '0');\nconst year = date.getFullYear();\nconsole.log(`${year}-${month}-${day}`); // "2025-02-14"\n\nThis works, but it looks cumbersome. And if you also need to localize the date (e.g., to Russian), the code grows to an indecent size. That's why developers look for alternatives.
\n\nThe toLocaleDateString Method: Simple and Fast
\n\nThe simplest way to format a date in JavaScript is to use the toLocaleDateString() method. It takes a locale and an options object:
const date = new Date();\nconst options = { year: 'numeric', month: 'long', day: 'numeric' };\nconsole.log(date.toLocaleDateString('ru-RU', options)); // "14 февраля 2025 г."\n\nThis method automatically adapts to the locale. Want "February 14, 2025"? Just change the locale to 'en-US'.
Pros:
\n- \n
- Ease of use. \n
- Built-in localization. \n
- Code reads like natural language. \n
Cons:
\n- \n
- Performance: each call to
toLocaleDateString()creates a new formatter object. In a loop of 1000 elements, this can be noticeable. \n - Limited control over the format (you cannot, for example, output "14.02.2025" without the year). \n
Intl.DateTimeFormat: Powerful and Efficient
\n\nFor finer control and optimization, use Intl.DateTimeFormat. This is an object that you can create once and reuse multiple times:
const formatter = new Intl.DateTimeFormat('ru-RU', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit'\n});\n\nconst date1 = new Date();\nconst date2 = new Date('2024-12-25');\nconsole.log(formatter.format(date1)); // "14.02.2025"\nconsole.log(formatter.format(date2)); // "25.12.2024"\n\nWhy is this faster? Because the formatter object is created once, not on every call. In performance tests, Intl.DateTimeFormat is 5-10 times faster than toLocaleDateString() in loops.
Moreover, Intl.DateTimeFormat supports additional options such as weekday, hour, minute, second, and even timeZone:
const formatter = new Intl.DateTimeFormat('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n});\nconsole.log(formatter.format(new Date())); // "Friday, Feb 14, 2025, 12:00 PM"\n\nA tricky question: what if you need to output a date in the format "2025-02-14" without localization? Intl.DateTimeFormat cannot output hours, minutes, and seconds separately, but for simple dates this is