3

Code:

  let modifiedValue = attribute_value;
  let isISOFormat = moment(new Date(attribute_value), moment.ISO_8601, true).isValid();
  if (isISOFormat) {
    modifiedValue = formatDateShortCustom(moment(attribute_value).toDate());
  }
  return modifiedValue;
};

In the code above, the attribute value can have

  1. 2021-09-29T18:30:00.000Z
  2. 080921

I want to make sure that when the attribute_value is in (1) format the code
modifiedValue = formatDateShortCustom(moment(attribute_value).toDate()); should execute.

However, this numerical string is also causing the isISOFormat as true hence navigating the formatDateShortCustom method, which I don't want?

Is there anything I am doing wrong?

Terry
  • 63,248
  • 15
  • 96
  • 118
  • 1
    An integer is a valid timestamp since it can represent seconds elapsed since the start of the Unix epoch. If you don't want to allow for numerical string, check it with regex, i.e. `^\d+$` – Terry Sep 28 '21 at 11:21
  • 1
    `new Date(080921)` outputs `Thu Jan 01 1970 01:01:20 GMT+0100 (Central European Standard Time)` (in my central European console at least :). You are passing that to Moment. Of course Moment says it's a valid date, there's no weirdness here. – Jeremy Thille Sep 28 '21 at 11:23
  • `moment(new Date(attribute_value), moment.ISO_8601, true)` doesn't make any sense. `new Date(attribute_value)` returns a Date object, so providing a parse format is redundant, there's nothing to parse (it's done within `new Date(...)`). Same with the strict parameter, it doesn't to anything. If you want to test that *attribute_value* is ISO 8601 format, then do that explicitly, don't try to infer whether it conforms based on what the built–in parser does with it. – RobG Sep 28 '21 at 14:58

2 Answers2

2

I'd suggest wrapping this in a function isISOFormat() and using this to decide whether your input is an ISO 8601 date string.

I'd also suggest passing the input directly to the moment() constructor, rather than creating a Date first:

let attribute_values = ['2021-09-28T11:45:00Z', new Date().toISOString(), 20, null, '28/09/2021', 'is this a date?'];

function testIsISOFormat() {
    for(let attribute_value of attribute_values) {
        console.log(`isISOFormat(${attribute_value}):`, isISOFormat(attribute_value));
    }
}

function isISOFormat(input) {
    return moment(input, moment.ISO_8601, true).isValid();
}

console.log('Testing isISOFormat:');
testIsISOFormat()
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
0

moment.ISO_8601 is undefined below version 2.7.0.

That's why moment attempts to parse the value regardless of your setting the strict parsing option. moment checks if the string matches known ISO 8601 formats.

I recommend passing the format as the second argument explicitly.

console.log(moment('2021-09-29T18:30:00.000Z', 'YYYY-MM-DDTHH:mm:ss.SSSZ', true).isValid());

console.log(moment('080921', 'YYYY-MM-DDTHH:mm:ss.SSSZ', true).isValid());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.5.1/moment.min.js"></script>
Oluwafemi Sule
  • 36,144
  • 1
  • 56
  • 81
  • The moment.js docs do allow you to specify moment.ISO_8601 as of moment 2.7.0+: https://momentjs.com/docs/#/parsing/special-formats/, e.g. moment("2010-01-01T05:06:07", moment.ISO_8601); – Terry Lennox Sep 28 '21 at 12:06
  • 1
    Thanks for pointing that out. OP is likely to be using a version earlier than `2.7.0` where it's `undefined`. The behavior isn't reproducible in 2.7.0 and later versions where `moment.ISO_8601` is defined. – Oluwafemi Sule Sep 28 '21 at 13:43
  • The reason is that in the expression that assigns a value to *isISOFormat*, i.e. `moment(new Date(attribute_value), moment.ISO_8601, true)`, *moment.js* doesn't parse the value at all, it's parsed by the built–in parser and that result (a Date instance) is then passed to *moment.js*. – RobG Sep 28 '21 at 20:45