Converting Date object in CoffeeScript to string (with a weird format) I'm trying to convert a Date object into a weird format, like so:

03/30/2017 11:37:14:082 -0500


The issue that really trips me up is the timezone offset. There's no way that screams at me as easy to do, so here's my implementation (in coffeescript, hopefully it's easy enough to understand without intimate knowledge of coffeescript):

  timeStamp = new Date()
  offsetHours = timeStamp.getTimezoneOffset() / 60 * 100
  if offsetHours &lt;= -1000
    offsetString = "+" + Math.abs(offsetHours)
  else if offsetHours == 0
    offsetString = "+0000"
  else if offsetHours &lt; 0 and offsetHours &gt; -1000
    offsetString = "+0" + Math.abs(offsetHours)
  else if offsetHours &gt;= 1000
    offsetString = "-" + offsetHours
  else
    offsetString = "-0" + offsetHours
  timeStampString = (timeStamp.getMonth() + 1) + '/' + timeStamp.getDay() +
    '/' + timeStamp.getFullYear() + " " + timeStamp.getHours() + ":" +
    timeStamp.getMinutes() + ":" + timeStamp.getSeconds() + ":" +
    timeStamp.getMilliseconds() + " " + offsetString


I realize my implementation isn't handling time-zones that have 30 minute offsets (which will get fixed) but I am looking to see if anyone can poke any other holes they see here. This code kind of smells to me and I feel like there should be an easier way to accomplish this.

I've spoofed the date prototype for JS to test a variety of time-zones and haven't found anything weird yet. This is to support interop with another application so "use a different scheme" unfortunately isn't an option. I'd like to avoid using libraries as well.
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


the 'manual' zero-padding of the timezone offset and its many if-else branches
the many hardcoded numbers and strings
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.getDate(),
    date.getFullYear(), 
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds(), 
    date.getTimezoneOffset() &gt; 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) =&gt; 
    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));




PS: Above code should translate pretty easily to coffeescript, but as I am not very well versed in that language, I chose to give code samples in vanilla JS.

Edit: Instead of getDay() you probably want to use getDate().