Bryce
Bryce

Reputation: 383

Javascript - Enumerating key, value pairs in object and converting those that match ISO timestamp format

Overview: I have an array (arr) of objects. I need to convert any value in an object that looks like an ISO timestamp to an epoch. I match via regular expression.

I have an object that looks like:

{
    assignee: null
    color: null
    description: "cool object"
    id: "12234858"
    last_updated: "2021-01-22T15:30:10.495000+00:00"
}

I have some code that does the following:

arr.forEach((item) => {
    let regex = /^[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?[+-][0-2]\d:[0-5]\dZ?)?)?)?/;
    Object.entries(myobject).forEach(([key, value]) => {
        if (value !== null) {
            if (value.match(regex)) {
                value = Date.parse(value) / 1000;
            }
        }
    });
});

The date conversions work while iterating through the key, values of each object, but once the arr.forEach() completes, the values are reset. What is the best way to handle these conversions? Should I map to new object and duplicate?

Upvotes: 0

Views: 94

Answers (2)

Nicholas Carey
Nicholas Carey

Reputation: 74267

I would use a library like Luxon. Like so:

const {DateTime} = require('luxon');

function transformIso8601ToSomethingUsable(arr) {
  for ( const obj of arr ) {
    for ( const [k,v] of Object.entries(obj) ) {
      obj[k] = iso8601DateTime2epochTime(v);
    }
  }
}

function iso8601DateTime2epochTime(s) {
  const dt = DateTime.fromISO(s).toUTC();
  const epochTime = dt.isValid
    ? Math.round(dt.toSeconds())
    : s ;
  return epochTime;
}

Then you can say something like

const arr = [{
  assignee: null,
  color: null,
  description: "cool object",
  id: "12234858",
  last_updated: "2021-01-22T15:30:10.495000+00:00",
}];

transformIso8601ToSomethingUsable(arr);

and get

[
  {
    "assignee": null,
    "color": null,
    "description": "cool object",
    "id": "12234858",
    "last_updated": 1611329410
  }
]

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 191976

The value itself is a primitive that doesn't retain "connection" to the object it was taken from. You need to assign the value back to the item using the key you've destructured.

Note: your regex doesn't actually work, and detects other values as dates. It's easier just to parse, and check if the value is NaN. See this answer.

const arr = [{
  assignee: null,
  color: null,
  description: "cool object",
  id: "12234858",
  last_updated: "2021-01-22T15:30:10.495000+00:00",
}];

arr.forEach((item) => {
  Object.entries(item).forEach(([key, value]) => {
    if (!isNaN(Date.parse(value || ''))) {
      // assign the new value back to the original item
      item[key] = Date.parse(value) / 1000;
    }
  });
});

console.log(arr);

As noted by @NicholasCarey's comment, !isNaN(Date.parse()) might identify other strings as dates. So if you are experiencing false positives, you might want to use regex (taken from this answer) or a stricter library:

const arr = [{
  assignee: null,
  color: null,
  description: "cool object",
  id: "12234858",
  last_updated: "2021-01-22T15:30:10.495000+00:00",
}];

const regex = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;

arr.forEach((item) => {
  Object.entries(item).forEach(([key, value]) => {
    if (regex.test(value || '')) {
      // assign the new value back to the original item
      item[key] = Date.parse(value) / 1000;
    }
  });
});

console.log(arr);

Upvotes: 1

Related Questions