Skip to main content
1 of 4
le_m
  • 1.9k
  • 10
  • 15

First of all, your given sample features zero-padded 2-digit months and milliseconds which you currently don't reproduce.

The mentioned 'smell' is probably caused by

  1. the 'manual' zero-padding of the timezone offset and its many if-else branches
  2. the many hardcoded numbers and strings
  3. the long illegible string concatenation

We can get rid of the self-made zero-padding by using String.padStart() or - if compatibility is a concern - one of its many alternative implementations.

We can't really get rid of the many hardcoded constants, but we can name them to make them meaningful and less magic in appearance:

const seperators = ['/', '/', ' ', ':', ':', ':', ' ', '', '', ''];

We can then replace the large string concatenation expression by leveraging one of those array's reduce or map method:

function formatDate(date) {
  const values = [
    date.getMonth() + 1,
    date.getDay(),
    date.getFullYear(), 
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds(), 
    date.getTimezoneOffset() > 0 ? '-' : '+',
    Math.abs(date.getTimezoneOffset() / 60),
    Math.abs(date.getTimezoneOffset() % 60)
  ];
  const digits = [2, 2, 4, 2, 2, 2, 3, 0, 2, 2];
  const seperators = ['/', '/', ' ', ':', ':', ':', ' ', '', '', ''];
  
  return values.map((value, i) => 
    value.toString().padStart(digits[i], '0') + seperators[i]
  ).join('');
}

console.log(formatDate(new Date()));

That's it. I don't see how we can leverage any other built-in method to shorten above task. Using JavaScript's built-in Date.toLocaleTimeString('en-US', options) gets us pretty far, but it is missing timezone offset and millisecond options and introduces unwanted separators:

const options = {
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false
};

console.log(new Date().toLocaleString('en-US', options));

le_m
  • 1.9k
  • 10
  • 15