Skip to content
Open
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Added

- Added support for the new license key format. A proprietary key can now grant a subset of the library: a function your key does not include evaluates to a `#LIC!` error, and the matching parts of the API throw a `LicenseCapabilityMissingError`. `getAvailableFunctions()` and `getFunctionDetails()` describe only the functions your key includes. [#1728](https://github.com/handsontable/hyperformula/pull/1728)
- Added new functions: ACCRINTM, DISC, INTRATE, PRICEDISC, RECEIVED, YIELDDISC. [#1799](https://github.com/handsontable/hyperformula/pull/1799)
- Added new functions: COUPDAYBS, COUPDAYS, COUPDAYSNC, COUPNCD, COUPNUM, COUPPCD. [#1804](https://github.com/handsontable/hyperformula/pull/1804)

### Changed

Expand Down
1 change: 1 addition & 0 deletions docs/guide/list-of-differences.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ To remove the differences, create [custom implementations](custom-functions.md)
| LCMP | =LCM(1000000, 1000001, 1000002, 1000003) | NUM | 5.00003E+23 | NUM |
| TBILLPRICE | =TBILLPRICE(0, 180, 1.9) | 5.0000 | NUM | 5.0000 |
| TBILLPRICE | =TBILLPRICE(0, 180, 2) | 0.0000 | NUM | 0.0000 |
| ACCRINTM | =ACCRINTM(DATE(2008,4,1), DATE(2008,6,15), 0.1) | 20.5556 | 20.5556 | Wrong number |
| NPV | =NPV(1, TRUE(), 1) | 0.7500 | 0.5000 | 0.7500 |
| NPV | =NPV(1,B1) where B1 = true | 0.5000 | 0.0000 | 0.0000 |
| POISSON.DIST | =POISSON.DIST(-0.01, 0, FALSE()) | NUM | 1.0000 | NUM |
Expand Down
45 changes: 45 additions & 0 deletions src/DateTimeHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,43 @@ export class DateTimeHelper {
}
}

/**
* Counts the days between two dates under a day-count basis, and returns the number of days in a year under the
* same basis. YEARFRAC and the securities functions (DISC, INTRATE, PRICEDISC, RECEIVED, YIELDDISC, ACCRINTM)
* compute their year fraction as `dayCount / yearDays`.
*
* | `basis` | `dayCount` | `yearDays` |
* |---------|----------------------------------------------|-----------------------------|
* | 0 | US (NASD) 30/360, as adjusted by `toBasisUS` | 360 |
* | 1 | actual days | `yearLengthForBasis` |
* | 2 | actual days | 360 |
* | 3 | actual days | 365 |
* | 4 | European 30/360, as adjusted by `toBasisEU` | 360 |
*
* @param {number} startDate - date serial number, an integer not greater than `endDate`
* @param {number} endDate - date serial number, an integer
* @param {number} basis - day-count basis, an integer from 0 to 4
*/
public dayCountByBasis(startDate: number, endDate: number, basis: number): { dayCount: number, yearDays: number } {
const start = this.numberToSimpleDate(startDate)
const end = this.numberToSimpleDate(endDate)
switch (basis) {
case 0: {
const [adjustedStart, adjustedEnd] = this.toBasisUS({...start}, {...end})
return {dayCount: daysIn30DayMonths(adjustedStart, adjustedEnd), yearDays: 360}
}
case 1:
return {dayCount: endDate - startDate, yearDays: this.yearLengthForBasis(start, end)}
case 2:
return {dayCount: endDate - startDate, yearDays: 360}
case 3:
return {dayCount: endDate - startDate, yearDays: 365}
case 4:
return {dayCount: daysIn30DayMonths(toBasisEU(start), toBasisEU(end)), yearDays: 360}
}
throw new Error('Should not be reachable.')
}

private parseSingleFormat(dateString: string, dateFormat?: string, timeFormat?: string): Maybe<DateTime> {
const dateTime = this.parseDateTime(dateString, dateFormat, timeFormat)
if (instanceOfSimpleDate(dateTime)) {
Expand Down Expand Up @@ -319,3 +356,11 @@ export function timeToNumber(time: SimpleTime): number {
export function toBasisEU(date: SimpleDate): SimpleDate {
return {year: date.year, month: date.month, day: Math.min(30, date.day)}
}

/**
* Counts the days between two dates as if every month had 30 days. The dates must already be adjusted to a 30/360
* basis (`toBasisUS` or `toBasisEU`).
*/
function daysIn30DayMonths(start: SimpleDate, end: SimpleDate): number {
return 360 * (end.year - start.year) + 30 * (end.month - start.month) + end.day - start.day
}
1 change: 1 addition & 0 deletions src/error-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class ErrorMessage {
public static IntegerExpected = 'Value needs to be an integer.'
public static BadMode = 'Mode not recognized.'
public static DateBounds = 'Date outside of bounds.'
public static CouponFrequency = 'Frequency must be 1, 2 or 4.'
public static OutOfSheet = 'Resulting reference is out of the sheet.'
public static WrongType = 'Wrong type of argument.'
public static NaN = 'NaN or infinite value encountered.'
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/languages/csCZ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const dictionary: RawTranslationPackage = {
'ARRAY_CONSTRAIN': 'ARRAY_CONSTRAIN',
ARRAYFORMULA: 'ARRAYFORMULA',
ABS: 'ABS',
ACCRINTM: 'ACCRINTM',
ACOS: 'ARCCOS',
ACOSH: 'ARCCOSH',
ACOT: 'ACOT',
Expand Down Expand Up @@ -66,6 +67,12 @@ const dictionary: RawTranslationPackage = {
COUNTIF: 'COUNTIF',
COUNTIFS: 'COUNTIFS',
COUNTUNIQUE: 'COUNTUNIQUE',
COUPDAYBS: 'COUPDAYBS',
COUPDAYS: 'COUPDAYS',
COUPDAYSNC: 'COUPDAYSNC',
COUPNCD: 'COUPNCD',
COUPNUM: 'COUPNUM',
COUPPCD: 'COUPPCD',
CSC: 'CSC',
CSCH: 'CSCH',
CUMIPMT: 'CUMIPMT',
Expand Down Expand Up @@ -96,6 +103,7 @@ const dictionary: RawTranslationPackage = {
DECIMAL: 'DECIMAL',
DEGREES: 'DEGREES',
DELTA: 'DELTA',
DISC: 'DISC',
DOLLARDE: 'DOLLARDE',
DOLLARFR: 'DOLLARFR',
EDATE: 'EDATE',
Expand Down Expand Up @@ -124,6 +132,7 @@ const dictionary: RawTranslationPackage = {
INDEX: 'INDEX',
INT: 'CELÁ.ČÁST',
INTERVAL: 'INTERVAL', //FIXME
INTRATE: 'INTRATE',
IPMT: 'PLATBA.ÚROK',
IRR: 'MÍRA.VÝNOSNOSTI',
ISBINARY: 'ISBINARY',
Expand Down Expand Up @@ -184,11 +193,13 @@ const dictionary: RawTranslationPackage = {
PRODUCT: 'SOUČIN',
POWER: 'POWER',
PPMT: 'PLATBA.ZÁKLAD',
PRICEDISC: 'PRICEDISC',
PROPER: 'VELKÁ2',
PV: 'SOUČHODNOTA',
RADIANS: 'RADIANS',
RAND: 'NÁHČÍSLO',
RATE: 'ÚROKOVÁ.MÍRA',
RECEIVED: 'RECEIVED',
REPLACE: 'NAHRADIT',
REPT: 'OPAKOVAT',
RIGHT: 'ZPRAVA',
Expand Down Expand Up @@ -259,6 +270,7 @@ const dictionary: RawTranslationPackage = {
XOR: 'XOR',
YEAR: 'ROK',
YEARFRAC: 'YEARFRAC',
YIELDDISC: 'YIELDDISC',
ROMAN: 'ROMAN',
ARABIC: 'ARABIC',
'HF.ADD': 'HF.ADD',
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/languages/daDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const dictionary: RawTranslationPackage = {
'ARRAY_CONSTRAIN': 'ARRAY_CONSTRAIN',
ARRAYFORMULA: 'ARRAYFORMULA',
ABS: 'ABS',
ACCRINTM: 'PÅLØBRENTE.UDLØB',
ACOS: 'ARCCOS',
ACOSH: 'ARCCOSH',
ACOT: 'ARCCOT',
Expand Down Expand Up @@ -66,6 +67,12 @@ const dictionary: RawTranslationPackage = {
COUNTIF: 'TÆL.HVIS',
COUNTIFS: 'TÆL.HVISER',
COUNTUNIQUE: 'COUNTUNIQUE',
COUPDAYBS: 'KUPONDAGE.SA',
COUPDAYS: 'KUPONDAGE.A',
COUPDAYSNC: 'KUPONDAGE.ANK',
COUPNCD: 'KUPONDAG.NÆSTE',
COUPNUM: 'KUPONBETALINGER',
COUPPCD: 'KUPONDAG.FORRIGE',
CSC: 'CSC',
CSCH: 'CSCH',
CUMIPMT: 'AKKUM.RENTE',
Expand Down Expand Up @@ -96,6 +103,7 @@ const dictionary: RawTranslationPackage = {
DECIMAL: 'DECIMAL',
DEGREES: 'GRADER',
DELTA: 'DELTA',
DISC: 'DISKONTO',
DOLLARDE: 'KR.DECIMAL',
DOLLARFR: 'KR.BRØK',
EDATE: 'EDATO',
Expand Down Expand Up @@ -124,6 +132,7 @@ const dictionary: RawTranslationPackage = {
INDEX: 'INDEKS',
INT: 'HELTAL',
INTERVAL: 'INTERVAL', //FIXME
INTRATE: 'RENTEFOD',
IPMT: 'R.YDELSE',
IRR: 'IA',
ISBINARY: 'ISBINARY',
Expand Down Expand Up @@ -184,11 +193,13 @@ const dictionary: RawTranslationPackage = {
PRODUCT: 'PRODUKT',
POWER: 'POTENS',
PPMT: 'H.YDELSE',
PRICEDISC: 'KURS.DISKONTO',
PROPER: 'STORT.FORBOGSTAV',
PV: 'NV',
RADIANS: 'RADIANER',
RAND: 'SLUMP',
RATE: 'RENTE',
RECEIVED: 'MODTAGET.VED.UDLØB',
REPLACE: 'ERSTAT',
REPT: 'GENTAG',
RIGHT: 'HØJRE',
Expand Down Expand Up @@ -259,6 +270,7 @@ const dictionary: RawTranslationPackage = {
XOR: 'XELLER',
YEAR: 'ÅR',
YEARFRAC: 'ÅR.BRØK',
YIELDDISC: 'AFKAST.DISKONTO',
ROMAN: 'ROMERTAL',
ARABIC: 'ARABISK',
'HF.ADD': 'HF.ADD',
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/languages/deDE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const dictionary: RawTranslationPackage = {
'ARRAY_CONSTRAIN': 'ARRAY_CONSTRAIN',
ARRAYFORMULA: 'ARRAYFORMULA',
ABS: 'ABS',
ACCRINTM: 'AUFGELZINSF',
ACOS: 'ARCCOS',
ACOSH: 'ARCCOSHYP',
ACOT: 'ARCCOTAN',
Expand Down Expand Up @@ -66,6 +67,12 @@ const dictionary: RawTranslationPackage = {
COUNTIF: 'ZÄHLENWENN',
COUNTIFS: 'ZÄHLENWENNS',
COUNTUNIQUE: 'COUNTUNIQUE',
COUPDAYBS: 'ZINSTERMTAGVA',
COUPDAYS: 'ZINSTERMTAGE',
COUPDAYSNC: 'ZINSTERMTAGNZ',
COUPNCD: 'ZINSTERMNZ',
COUPNUM: 'ZINSTERMZAHL',
COUPPCD: 'ZINSTERMVZ',
CSC: 'COSEC',
CSCH: 'COSECHYP',
CUMIPMT: 'KUMZINSZ',
Expand Down Expand Up @@ -96,6 +103,7 @@ const dictionary: RawTranslationPackage = {
DECIMAL: 'DEZIMAL',
DEGREES: 'GRAD',
DELTA: 'DELTA',
DISC: 'DISAGIO',
DOLLARDE: 'NOTIERUNGDEZ',
DOLLARFR: 'NOTIERUNGBRU',
EDATE: 'EDATUM',
Expand Down Expand Up @@ -124,6 +132,7 @@ const dictionary: RawTranslationPackage = {
INDEX: 'INDEX',
INT: 'GANZZAHL',
INTERVAL: 'INTERVAL', //FIXME
INTRATE: 'ZINSSATZ',
IPMT: 'ZINSZ',
IRR: 'IKV',
ISBINARY: 'ISBINARY',
Expand Down Expand Up @@ -184,11 +193,13 @@ const dictionary: RawTranslationPackage = {
PRODUCT: 'PRODUKT',
POWER: 'POTENZ',
PPMT: 'KAPZ',
PRICEDISC: 'KURSDISAGIO',
PROPER: 'GROSS2',
PV: 'BW',
RADIANS: 'BOGENMASS',
RAND: 'ZUFALLSZAHL',
RATE: 'ZINS',
RECEIVED: 'AUSZAHLUNG',
REPLACE: 'ERSETZEN',
REPT: 'WIEDERHOLEN',
RIGHT: 'RECHTS',
Expand Down Expand Up @@ -259,6 +270,7 @@ const dictionary: RawTranslationPackage = {
XOR: 'XODER',
YEAR: 'JAHR',
YEARFRAC: 'BRTEILJAHRE',
YIELDDISC: 'RENDITEDIS',
ROMAN: 'RÖMISCH',
ARABIC: 'ARABISCH',
'HF.ADD': 'HF.ADD',
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/languages/enGB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const dictionary: RawTranslationPackage = {
'ARRAY_CONSTRAIN': 'ARRAY_CONSTRAIN',
ARRAYFORMULA: 'ARRAYFORMULA',
ABS: 'ABS',
ACCRINTM: 'ACCRINTM',
ACOS: 'ACOS',
ACOSH: 'ACOSH',
ACOT: 'ACOT',
Expand Down Expand Up @@ -67,6 +68,12 @@ const dictionary: RawTranslationPackage = {
COUNTIF: 'COUNTIF',
COUNTIFS: 'COUNTIFS',
COUNTUNIQUE: 'COUNTUNIQUE',
COUPDAYBS: 'COUPDAYBS',
COUPDAYS: 'COUPDAYS',
COUPDAYSNC: 'COUPDAYSNC',
COUPNCD: 'COUPNCD',
COUPNUM: 'COUPNUM',
COUPPCD: 'COUPPCD',
CSC: 'CSC',
CSCH: 'CSCH',
CUMIPMT: 'CUMIPMT',
Expand Down Expand Up @@ -97,6 +104,7 @@ const dictionary: RawTranslationPackage = {
DECIMAL: 'DECIMAL',
DEGREES: 'DEGREES',
DELTA: 'DELTA',
DISC: 'DISC',
DOLLARDE: 'DOLLARDE',
DOLLARFR: 'DOLLARFR',
EDATE: 'EDATE',
Expand Down Expand Up @@ -125,6 +133,7 @@ const dictionary: RawTranslationPackage = {
INDEX: 'INDEX',
INT: 'INT',
INTERVAL: 'INTERVAL',
INTRATE: 'INTRATE',
IPMT: 'IPMT',
IRR: 'IRR',
ISBINARY: 'ISBINARY',
Expand Down Expand Up @@ -185,11 +194,13 @@ const dictionary: RawTranslationPackage = {
PRODUCT: 'PRODUCT',
POWER: 'POWER',
PPMT: 'PPMT',
PRICEDISC: 'PRICEDISC',
PROPER: 'PROPER',
PV: 'PV',
RADIANS: 'RADIANS',
RAND: 'RAND',
RATE: 'RATE',
RECEIVED: 'RECEIVED',
REPLACE: 'REPLACE',
REPT: 'REPT',
RIGHT: 'RIGHT',
Expand Down Expand Up @@ -261,6 +272,7 @@ const dictionary: RawTranslationPackage = {
XLOOKUP: 'XLOOKUP',
YEAR: 'YEAR',
YEARFRAC: 'YEARFRAC',
YIELDDISC: 'YIELDDISC',
'HF.ADD': 'HF.ADD',
'HF.CONCAT': 'HF.CONCAT',
'HF.DIVIDE': 'HF.DIVIDE',
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/languages/esES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const dictionary: RawTranslationPackage = {
'ARRAY_CONSTRAIN': 'ARRAY_CONSTRAIN',
ARRAYFORMULA: 'ARRAYFORMULA',
ABS: 'ABS',
ACCRINTM: 'INT.ACUM.V',
ACOS: 'ACOS',
ACOSH: 'ACOSH',
ACOT: 'ACOT',
Expand Down Expand Up @@ -66,6 +67,12 @@ export const dictionary: RawTranslationPackage = {
COUNTIF: 'CONTAR.SI',
COUNTIFS: 'CONTAR.SI.CONJUNTO',
COUNTUNIQUE: 'COUNTUNIQUE',
COUPDAYBS: 'CUPON.DIAS.L1',
COUPDAYS: 'CUPON.DIAS',
COUPDAYSNC: 'CUPON.DIAS.L2',
COUPNCD: 'CUPON.FECHA.L2',
COUPNUM: 'CUPON.NUM',
COUPPCD: 'CUPON.FECHA.L1',
CSC: 'CSC',
CSCH: 'CSCH',
CUMIPMT: 'PAGO.INT.ENTRE',
Expand Down Expand Up @@ -96,6 +103,7 @@ export const dictionary: RawTranslationPackage = {
DECIMAL: 'CONV.DECIMAL',
DEGREES: 'GRADOS',
DELTA: 'DELTA',
DISC: 'TASA.DESC',
DOLLARDE: 'MONEDA.DEC',
DOLLARFR: 'MONEDA.FRAC',
EDATE: 'FECHA.MES',
Expand Down Expand Up @@ -124,6 +132,7 @@ export const dictionary: RawTranslationPackage = {
INDEX: 'INDICE',
INT: 'ENTERO',
INTERVAL: 'INTERVAL', //FIXME
INTRATE: 'TASA.INT',
IPMT: 'PAGOINT',
IRR: 'TIR',
ISBINARY: 'ISBINARY',
Expand Down Expand Up @@ -184,11 +193,13 @@ export const dictionary: RawTranslationPackage = {
PRODUCT: 'PRODUCTO',
POWER: 'POTENCIA',
PPMT: 'PAGOPRIN',
PRICEDISC: 'PRECIO.DESCUENTO',
PROPER: 'NOMPROPIO',
PV: 'VA',
RADIANS: 'RADIANES',
RAND: 'ALEATORIO',
RATE: 'TASA',
RECEIVED: 'CANTIDAD.RECIBIDA',
REPLACE: 'REEMPLAZAR',
REPT: 'REPETIR',
RIGHT: 'DERECHA',
Expand Down Expand Up @@ -259,6 +270,7 @@ export const dictionary: RawTranslationPackage = {
XOR: 'XOR',
YEAR: 'AÑO',
YEARFRAC: 'FRAC.AÑO',
YIELDDISC: 'RENDTO.DESC',
ROMAN: 'NUMERO.ROMANO',
ARABIC: 'ARABIC',
'HF.ADD': 'HF.ADD',
Expand Down
Loading
Loading