Resources Numerical accuracy Calculation policy

Asset service life and maintenance due dates

Stores an asset's service life in the IFC file and reads it back in years, and marks maintenance as overdue or due soon from its next date.

How the precision is kept

Service life is typed in years. An IFC4 file gets the ISO duration text P<years>Y; an IFC2x3 file gets seconds, the years times 31,557,600 rounded to a whole second. Reading back divides by the same constant and rounds to one decimal of a year. Due dates are compared as whole day numbers.

Calculations under this policy

4 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

assets-bim.js BimCraft 0.8.1 64-bit 4 calculations Reviewed

Tests tools/bimcraft-test/ops-docs.mjs, tools/bimcraft-test/ops-sensors.mjs

Service life read from the file

64-bit

The service life shown in the asset form, in years.

years = seconds ÷ 31557600, or Y + M ÷ 12; rounded to 0.1

A number is taken as seconds and divided by 365.25 × 86400; an ISO duration is read from its year and month parts. Either way the result is rounded with Math.round(y × 10) ÷ 10 and returned as text.

  • assets-bim.js
  • lines 81 to 91
  • BimCraft 0.8.1
/** A value read back from the file into the form's text: dates 'YYYY-MM-DD', service life in whole years. */
function fromFile(field, v) {
  if (v === null || v === undefined) return '';
  if (field === 'life') {
    if (typeof v === 'number' || /^[\d.]+$/.test(String(v))) { const y = Number(v) / YEAR_S; return y > 0 ? String(Math.round(y * 10) / 10) : ''; }
    const m = /^P(?:(\d+(?:\.\d+)?)Y)?(?:(\d+)M)?/.exec(String(v));
    return m && (m[1] || m[2]) ? String(Math.round(((Number(m[1]) || 0) + (Number(m[2]) || 0) / 12) * 10) / 10) : '';
  }
  const s = String(v);
  return DATE_FIELDS.has(field) ? (isDay(s.slice(0, 10)) ? s.slice(0, 10) : '') : s;
}

Service life written to the file

64-bit

The service life as the IFC property holds it.

IFC2x3: seconds = round(years × 31557600); IFC4: 'P' + years + 'Y'

For IFC2x3 the product is rounded to a whole second, a change of at most half a second. For IFC4 the typed text is written unchanged inside the duration.

  • assets-bim.js
  • lines 231 to 236
  • BimCraft 0.8.1
function typed(w, field, v) {
  const [, , t4, t3] = MAP[field];
  const type = w.v4 ? t4 : t3;
  if (field === 'life') return [type, w.v4 ? 'P' + v + 'Y' : Math.round(Number(v) * YEAR_S)];
  return [type, v];
}

Day number of a date

Exact

A calendar date as a count of days since 1970-01-01.

day = round(ms at 00:00 UTC ÷ 86400000)

The date is parsed at midnight UTC, a whole multiple of 86,400,000 ms, so the quotient is an integer and Math.round changes nothing.

  • assets-bim.js
  • line 77
  • BimCraft 0.8.1
const dayNum = (s) => Math.round(Date.parse(s + 'T00:00:00Z') / 86400000);

Overdue or due soon

Exact

Whether an asset's next maintenance date has passed or falls within 30 days.

d = day(next due) − day(today); overdue if d < 0; soon if d ≤ 30

A difference of two integer day numbers.

  • assets-bim.js
  • line 183
  • BimCraft 0.8.1
if (nextDue && isDay(today)) { const d = dayNum(nextDue) - dayNum(today); due = d < 0 ? 'overdue' : d <= SOON_DAYS ? 'soon' : ''; }

In detail

Method
YEAR_S = 365.25 × 86400 seconds. Due: d = day number of the next date − day number of today; negative is overdue, 30 or less is due soon.
Number types
64-bit numbers; day numbers are integers.
Limits
A life read from a file is rounded to 0.1 year: 12.25 years written by another program reads as 12.3. An ISO duration is read from its year and month parts only.

Approach: 64-bit, direct

Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.

Every policy that takes this approach