0

I need to convert string: '20211114025320+0000' to JS Date object (2021-11-14T02:53:20.000Z).

I have this format for info ('YYYYMMDDHHmmssZ') maybe I need to use a custom function for this?

RobG
  • 142,382
  • 31
  • 172
  • 209
g---
  • 13
  • 4
  • what effort have you made? – Daniel A. White Nov 14 '21 at 20:04
  • Is it `Z` or `+0000`? – Bergi Nov 14 '21 at 20:06
  • Yes, you need a custom function for it. Get all the parts, then call `new Date(Date.UTC(…))`. If you struggle with details, please [edit] your question to show us your attempt. – Bergi Nov 14 '21 at 20:09
  • 1
    @Bergi I think that'd be unnecessarily complex. All that's missing here are some dashes and colons and a `T`. @g--- could use something like this: ```new Date('20211114025320+0000'.replace(/^(....)(..)(..)(..)(..)(.*)$/, '$1-$2-$3T$4:$5:$6'))``` (the last capture group captures both seconds and timezone because it doesn't need a separator) – CherryDT Nov 14 '21 at 20:19
  • @CherryDT—that means parsing the string, then creating another string that is then parsed by the built–in parser. Alternatively, it can be parsed once and the values passed directly to the Date constructor. – RobG Nov 14 '21 at 20:50
  • @RobG True. But I wasn't wearing processor-colored glasses when I talked about complexity. In my opinion, it's clearer to the humans reading and maintaining the code, doesn't have to do any error-prone month-offsetting, etc., and will work work with _either_ `Z` _or_ any `+XXXX`/`-XXXX` timezone specification, yielding more robust and maintainable code. I always prefer "human simplicity" over "computer simplicity" unless certain requirements (such as this being a super-highly-used code path mandating performance optimizations) are worth the cost of going the other way. – CherryDT Nov 14 '21 at 20:51
  • @CherryDT I suppose you're right. I've reopened the question so that you can post this as an answer – Bergi Nov 14 '21 at 21:04
  • Btw, for the reverse operation: [How to create date in YYYYMMDDHHMMSS format using javascript?](https://stackoverflow.com/q/19448436/1048572) – Bergi Nov 14 '21 at 21:06
  • Does this answer your question? [Parsing a string to a date in JavaScript](https://stackoverflow.com/questions/5619202/parsing-a-string-to-a-date-in-javascript) – Heretic Monkey Nov 16 '21 at 03:05
  • Does this answer your question? [Parsing ISO 8601 date in Javascript](https://stackoverflow.com/questions/4829569/parsing-iso-8601-date-in-javascript) – kmoser Nov 16 '21 at 03:20
  • @HereticMonkey The question you linked doesn't ask for a date that includes a timezone. – CherryDT Nov 16 '21 at 08:53
  • @kmoser This format isn't exactly ISO, it's missing separators, that's what this question is all about. – CherryDT Nov 16 '21 at 08:54

2 Answers2

0

It looks like what you have is an ISO 8601 string with all the separators stripped away.

Therefore, a straight-forward way would be to add these separators back using a regex replace and then parsing it using the built-in parser:

function parseCustomDate (s) {
  const isoString = s.replace(/^(....)(..)(..)(..)(..)(.*)$/, '$1-$2-$3T$4:$5:$6')
  return new Date(isoString)
}

(Note that here the last capture group with the .* captures both seconds and the timezone specifier at once, because those don't need a separator between them anyway. To make it clearer, you could also use (..)(.*) and $6$7 instead of only (.*) and $6 as I did.)


Another way that is faster computationally but also more complex to read, understand and catch bugs in (in my opinion at least) would be to take the individual parts of the string and pass them to the Date.UTC constructor instead of going through the ISO string route:

function parseCustomDate (s) {
  const year = Number(s.slice(0, 4))
  const month = Number(s.slice(4, 6))
  const day = Number(s.slice(6, 8))
  const hour = Number(s.slice(8, 10))
  const minute = Number(s.slice(10, 12))
  const second = Number(s.slice(12, 14))
  const tzSign = s.slice(14, 15)
  const tzHour = Number(tzSign + s.slice(15, 17)) || 0
  const tzMinute = Number(tzSign + s.slice(17, 19)) || 0
  return new Date(Date.UTC(
    year, month - 1, day,
    hour - tzHour, minute - tzMinute, second
  ))
}

Explanation for the timezone handling here: JavaScript accepts "invalid" dates that have individual parts outside of the regular range by rolling them over, so e.g. 11:70:00 would become 12:10:00. This is why we can simply subtract the timezone parts (with each part also capturing the +/- sign), and we don't even have to mess with multiplying the minutes by 60 because we can handle them in the minutes part too.

I added the || 0 so that a string with a Z as timezone which would otherwise make tzHour and tzMinute NaN would also be handled as zero timezone offset.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
0

A function to parse the string and pass the parts directly the Date constructor may be more efficient than parsing the string to generate another string that is then parsed by the built–in parser.

This method also avoids the built–in parser, which is usually considered a good idea.

// Parse YYYYMMDDHHmmss±HHmm or YYYYMMDDHHmmssZ
function parseTS(ts) {
  // Get parts
  let [C,Y,M,D,H,m,s,sign,oH,oM] = ts.match(/\d\d|\D/g);
  // Deal with offset: ±HHmm or Z
  if (sign == 'Z') {
    sign = oH = oM = 0;
  }
  let oSign = sign == '+' ? -1 : +1;
  // Create date from parts, adjust H, m for offset
  return new Date(Date.UTC(C+Y, M-1, D, +H + oH*oSign, +m + oM*oSign, s));
}

['20211114082320+0530',
 '20211114025320+0000',
 '20211114025320Z',
 '20211113225320-0400'
].forEach(ts => console.log(ts + '\n' + parseTS(ts).toISOString()));
RobG
  • 142,382
  • 31
  • 172
  • 209
  • It _is_ more efficient, but more complicated to read/write. I also had an efficient alternative in my question, but not using `match` because that makes it slow yet again. The tricks with `C` and also with `\D` would deserve an explanation in my opinion, and the variable names aren't very descriptive. – CherryDT Nov 16 '21 at 08:56