ISO 8601 継続時間表記を正規表現で抜き出す

ISO 8601 日時の期間文字列から W, Y, M, D, h, m, s を抜き出す。

書式は、P[n]Y[n]M[n]DT[n]H[n]M[n]S
または、P[n]W

/^P(?=(?:\d+(?:\.\d+)?W|(?:\d+(?:\.\d+)?[YMD]){1,3}(?:T(?:\d+(?:\.\d+)?[HMS]){1,3})?|T(?:\d+(?:\.\d+)?[HMS]){1,3})$)(?:(.+)W|(?:(.+)Y)?(?:([\d\.]+)M)?(?:(.+)D)?)(?:T(?:(.+)H)?(?:(.+)M)?(?:(.+)S)?)?$/

Date オブジェクトと継続時間表記の文字列の加算

 function addDateDuration (date = new this, iso8601_duration_string, scale = 1) {
    const    //週の値は整数に制限[0-53], Y,M,D,h,m,s 共に少数を許容する
      REG_ISO8601_DURATION = /^P(?=(?:\d+(?:\.\d+)?W|(?:\d+(?:\.\d+)?[YMD]){1,3}(?:T(?:\d+(?:\.\d+)?[HMS]){1,3})?|T(?:\d+(?:\.\d+)?[HMS]){1,3})$)(?:(.+)W|(?:(.+)Y)?(?:([\d\.]+)M)?(?:(.+)D)?)(?:T(?:(.+)H)?(?:(.+)M)?(?:(.+)S)?)?$/,
      SECONDS = [ 86400, 3600, 60, 1 ],
      ONE_DAY = 365.2422 / 12,
      { floor: INT, ceil: CEIL } = Math;

    let parm = REG_ISO8601_DURATION.exec (iso8601_duration_string);
    if (parm) {
      let
        [, W, Y, M, D, h, m, s] = parm.map (n=> parseFloat (n) || 0),
        YM = Y * 12 + M,//Y,M の端数はDに加算して切り捨てる (時分秒に影響しない)
        ms = [D + W * 7 + INT ((YM % 1) * ONE_DAY), h, m, s].reduce ((a, b, i)=> a + b * SECONDS[i], 0) * 1000;
      date.setMonth (date.getMonth () + INT (YM * scale));
      date.setTime (date.getTime () + INT (ms * scale));
      return date;
    }
    else
      throw new Error ('Error!!: 解析できない文字列です。/:' + iso8601_duration_string);

  }