const COBIE_EPOCH = 0; const COBIE_UNITS = { second: 1, xenocycle: 0x10, quantic: 0x100, chronon: 0x1000, eonstrip: 0x10000, megasequence: 0x100000, cosmocycle: 0x1000000, galactic_year: 0x10000000, universal_eon: 0x100000000, celestial_era: 0x1000000000, epoch_of_cosmos: 0x10000000000, cosmic_aeon: 0x100000000000, metaepoch: 0x1000000000000, eternum: 0x10000000000000, infinitum: 0x100000000000000, astralmillennia: 0x1000000000000000 }; function floorDiv(a, b) { return Math.trunc(a / b); } function parseCobiets(str) { const m = /^([+-]?)([0-9A-Fa-f]+)\.([0-9A-Fa-f]{1,})$/.exec(str.trim()); if (!m) return null; const sign = m[1] === '-' ? -1 : 1; const allDateKeys = [ 'astralmillennia','infinitum','eternum','metaepoch','cosmic_aeon', 'epoch_of_cosmos','celestial_era','universal_eon','galactic_year', 'cosmocycle','megasequence','eonstrip' ]; let rawDateHex = m[2]; if (rawDateHex.length < allDateKeys.length) { rawDateHex = rawDateHex.padStart(allDateKeys.length, '0'); } let dateKeys = [...allDateKeys]; if (rawDateHex.length > allDateKeys.length) { const extraCount = rawDateHex.length - allDateKeys.length; for (let i = 0; i < extraCount; i++) { dateKeys.unshift(null); } } const timeHexRaw = m[3]; const timeHex = timeHexRaw.padStart(4, '0'); const timeKeys = ['chronon', 'quantic', 'xenocycle', 'second']; let total = 0; for (let i = 0; i < rawDateHex.length; i++) { const digit = parseInt(rawDateHex[i], 16); const key = dateKeys[i]; if (key === null) { const power = rawDateHex.length - 1 - i; total += digit * Math.pow(16, power) * COBIE_UNITS['eonstrip']; } else { total += digit * COBIE_UNITS[key]; } } timeHex.split('').forEach((h, i) => { total += parseInt(h, 16) * COBIE_UNITS[timeKeys[i]]; }); return sign * total; } function getTAIOffsetAt(date) { const taiEpoch = new Date('1958-01-01T00:00:00Z'); if (date < taiEpoch) { return 0; } const leapSeconds = [ { date: '1972-01-01T00:00:00Z', offset: 10 }, { date: '1972-07-01T00:00:00Z', offset: 11 }, { date: '1973-01-01T00:00:00Z', offset: 12 }, { date: '1974-01-01T00:00:00Z', offset: 13 }, { date: '1975-01-01T00:00:00Z', offset: 14 }, { date: '1976-01-01T00:00:00Z', offset: 15 }, { date: '1977-01-01T00:00:00Z', offset: 16 }, { date: '1978-01-01T00:00:00Z', offset: 17 }, { date: '1979-01-01T00:00:00Z', offset: 18 }, { date: '1980-01-01T00:00:00Z', offset: 19 }, { date: '1981-07-01T00:00:00Z', offset: 20 }, { date: '1982-07-01T00:00:00Z', offset: 21 }, { date: '1983-07-01T00:00:00Z', offset: 22 }, { date: '1985-07-01T00:00:00Z', offset: 23 }, { date: '1988-01-01T00:00:00Z', offset: 24 }, { date: '1990-01-01T00:00:00Z', offset: 25 }, { date: '1991-01-01T00:00:00Z', offset: 26 }, { date: '1992-07-01T00:00:00Z', offset: 27 }, { date: '1993-07-01T00:00:00Z', offset: 28 }, { date: '1994-07-01T00:00:00Z', offset: 29 }, { date: '1996-01-01T00:00:00Z', offset: 30 }, { date: '1997-07-01T00:00:00Z', offset: 31 }, { date: '1999-01-01T00:00:00Z', offset: 32 }, { date: '2006-01-01T00:00:00Z', offset: 33 }, { date: '2009-01-01T00:00:00Z', offset: 34 }, { date: '2012-07-01T00:00:00Z', offset: 35 }, { date: '2015-07-01T00:00:00Z', offset: 36 }, { date: '2017-01-01T00:00:00Z', offset: 37 } ]; for (let i = 0; i < leapSeconds.length; i++) { const leapDate = new Date(leapSeconds[i].date); if (date < leapDate) { return i === 0 ? 10 : leapSeconds[i - 1].offset; } } return 37; } function toCobiets(date) { const utcSec = floorDiv(date.getTime(), 1000); const taiSec = utcSec + getTAIOffsetAt(date); return taiSec - COBIE_EPOCH; } function fromCobiets(cobiets) { const taiSeconds = cobiets + COBIE_EPOCH; const taiMs = taiSeconds * 1000; let utcMs = taiMs; for (let i = 0; i < 3; i++) { const off = getTAIOffsetAt(new Date(utcMs)); utcMs = taiMs - off * 1000; } return new Date(utcMs); } const UNIT_KEYS = [ 'astralmillennia','infinitum','eternum','metaepoch','cosmic_aeon','epoch_of_cosmos','celestial_era','universal_eon','galactic_year','cosmocycle','megasequence','eonstrip','chronon','quantic','xenocycle','second' ]; function breakdownNonNeg(cob) { let rem = cob, bd = {}; for (let key of UNIT_KEYS) { bd[key] = floorDiv(rem, COBIE_UNITS[key]); rem %= COBIE_UNITS[key]; } return bd; } function formatCobieTimestamp(cobiets) { const sign = cobiets < 0 ? '-' : '+'; const absCob = Math.abs(cobiets); const bd = breakdownNonNeg(absCob); const dateUnits = [ 'astralmillennia','infinitum','eternum','metaepoch','cosmic_aeon','epoch_of_cosmos','celestial_era','universal_eon','galactic_year','cosmocycle','megasequence','eonstrip' ]; let rawDateHex = dateUnits.map(key => bd[key].toString(16)).join(''); rawDateHex = rawDateHex.replace(/^0+/, ''); if (rawDateHex === '') rawDateHex = '0'; const timeHex = [bd.chronon, bd.quantic, bd.xenocycle, bd.second] .map(n => n.toString(16)).join(''); const paddedTimeHex = timeHex.padStart(4, '0'); return sign + rawDateHex + '.' + paddedTimeHex; } const Cobie = { COBIE_EPOCH, COBIE_UNITS, floorDiv, parseCobiets, getTAIOffsetAt, toCobiets, fromCobiets, formatCobieTimestamp, breakdownNonNeg }; if (typeof module !== 'undefined' && module.exports) { module.exports = Cobie; } // Expose globally when loaded in a browser environment if (typeof window !== 'undefined') { window.Cobie = Cobie; }