2025.1.16: Kinetic Grid Copy/Paste Part Number Formatted as Date

While everyone is very familiar with Excel auto formatting issues when copy/pasting from Epicor Classic Dashboards, I have a different spin issue with Kinetic Dashboards Copy & Paste… but it’s not Excel that is messing with the format… it appears it’s actually copying from the grid reformatted as a date.
So if the value is something like the following examples it will reformat respectively ON THE CLIPBOARD, I can see this by two tests:

  1. Before Pasting in Excel we set all the cell formats to ‘Text’ and the values still paste as a Date
  2. Pasting into Notepad pates as a Date.

Sample Part Numbers and the Copied Value:

  • 0009-01-07 => 1/6/9
  • 0009-04-10 => 4/9/9
  • 0010-01-04 => 1/3/10
  • 0010-01-06 => 1/5/10
  • 0010-01-07 = > 1/6/10

The odd thing is that if we select the data in the cell and copy/paste (with Ctrl-C/Ctrl-V) the values copies fine. I realize this seems very data dependent, but it produces an unreliable situations for users pulling copy pasting data.

I’ve reported this to Epicor Support on Case CS0005428699 but I wanted to check with anyone who has seen this too or if there is a way to avoid it.
The odd thing is that if we select the data in the cell and copy/paste (with Ctrl-C/Ctrl-V) the values copies fine.I realize this seems very data dependent, but it produces an unreliable situations for users pulling copy pasting data.

This seems to be a Grid Control issue with both base apps and custom dashboard apps that we create. For example if we use Order Tracker the part number reformats to the clipboard as well.

Now using the Export To Excel the formatting is fine, so that maybe a workaround, regardless, there is something wrong with how this function works.

Looks like Kinetic grid Copy action pattern matches all values to decide whether it’s a date:

copyAllRows(t) {
  var o;
  let c;
  return this.validateSelectedKeysWithSelector(),
  c = (null !== (o = this.view) && void 0 !== o ? o : this.getParsedBinding()) ? this.executeProcess(this._dataFilter.execute(this.getBindingDataView().data), {
      filter: this.settings.currentState.filter,
      sort: this.settings.currentState.sort
  }) : this.data ? this.data : this.nativeControl.data.data || [],
  c.forEach( (E, S) => {
      const B = this.getSelectorAddedOnCopy(t = 0 === S ? t : t + "\n", S, E);
      t = B.text,
      this.model.columns.filter(G => !G.hidden).forEach( (G, ie) => {
          let ge = null !== E[G.field] ? E[G.field] : "";
          ge = this.processCurrFieldValue(ge, G, E),   //  << PROCESS VALUES
          t = 0 !== ie || B.isAdded ? t + "\t" + ge : t + ge
      }
      )
  }
  ),
  t
              }
...
processCurrFieldValue(t, o, c) {
    const [h,E] = this.customFormatting(t, o, c);
    if (h)
        return E;
    const S = Hr.isDateString(t) ? new Date(t) : t;  // << PATTERN MATCH n CAST
    return t = Hr.isDate(S) ? this.epInternationalizationService.formatDate(S, "d") : t,
    Hr.isString(t) && (t = t.replace(/\r\n/g, " ").replace(/\r/g, " ").replace(/\n/g, " ")),
    Hr.isNumber(t) && !(null != o && o.isLink) && (t = this.epInternationalizationService.formatNumberToCurrentLocale(t)),
    t
}
static isDate(t) {
    return t instanceof Date && !isNaN(t.valueOf())
}
static isISODate(t) {
    return l.isoDateRegEx || (l.isoDateRegEx = new RegExp(/^[0-9]{4}-[0-9]{2}-[0-9]{2}(T[0-9]{2}:[0-9]{2}:[0-9]{2})?(\.[0-9]+)?(([+-][0-9]{2}:[0-9]{2})|Z)?$/i)),
    l.isoDateRegEx.test(t)
}
static isISODateString(t) {
    return l.isoDateRegEx || (l.isoDateRegEx = new RegExp(/^[0-9]{4}-[0-9]{2}-[0-9]{2}(T[0-9]{2}:[0-9]{2}:[0-9]{2})?(\.[0-9]+)?(([+-][0-9]{2}:[0-9]{2})|Z)?$/i)),
    l.isString(t) && l.isoDateRegEx.test(t)
}
static isDateString(t) {
    return l.dateRegEx || (l.dateRegEx = new RegExp(/^(3[01]|[12][0-9]|0[1-9]|[1-9])[-|/](3[01]|[12][0-9]|0[1-9]|[1-9])[-|/][0-9]{4}$/)),
    l.isString(t) && (l.isISODate(t) || l.dateRegEx.test(t))
}

so basically anything that resembles a date string gets cast to date.
examples:

2023-04-15
2023-04-15T12:34:56
2023-04-15T12:34:56.789Z
2023-04-15T12:34:56+02:00
9-1-2024
09-01-2024
31/12/2024
1/1/2024

no idea why you’re getting minus-one-day, that’s further concerning. Probably the internationalization (you in EU?)

I have this issue as well. We have a dashboard with all the lockers for employee clothes. They are numbered in a format like 12-34

When we copy this to Excel, it also makes it into a date field. But when we export to Excell using the button in the action menu (3 dots) it will be in the correct format.

I don’t know why it is doing this, but this has been our workaround for now..

Just noticed this same issue totally breaks search/filter as well. Ugh, inferring dates from strings :roll_eyes:


I also get minus-one-day and I’m EST. what a mess. I guess that could make sense converting from UTC to EST, but PartNums are not dates so…

This is NOT Howie Dewitt folks.

I just ran across this issue on the “Part On Hand Status” dashboard, as well as, a custom panel I added to the Time Phased Inquiry screen for displaying Part Bins. Part numbers like 5613-37-31, 3239-16-25KV-9 seem to be treated like a date and the search breaks. :scream:
Has anyone come up with a work around?