@indodev/toolkit 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/datetime/types.ts","../../src/datetime/constants.ts","../../src/datetime/calc.ts","../../src/datetime/parse.ts","../../src/datetime/format.ts","../../src/datetime/relative.ts","../../src/datetime/timezone.ts"],"names":["normalizeDate"],"mappings":";;;AAsBO,IAAM,gBAAA,GAAN,cAA+B,KAAA,CAAM;AAAA,EAI1C,WAAA,CAAY,UAAkB,uBAAA,EAAyB;AACrD,IAAA,KAAA,CAAM,OAAO,CAAA;AAHf;AAAA,IAAA,IAAA,CAAS,IAAA,GAAO,cAAA;AAId,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF;AAiBO,IAAM,qBAAA,GAAN,cAAoC,KAAA,CAAM;AAAA,EAI/C,WAAA,CAAY,UAAkB,mCAAA,EAAqC;AACjE,IAAA,KAAA,CAAM,OAAO,CAAA;AAHf;AAAA,IAAA,IAAA,CAAS,IAAA,GAAO,oBAAA;AAId,IAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AAAA,EACd;AACF;;;AC/CO,IAAM,WAAA,GAAiC;AAAA,EAC5C,EAAA;AAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF;AAGO,IAAM,iBAAA,GAAuC;AAAA,EAClD,EAAA;AAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF;AAGO,IAAM,SAAA,GAA+B;AAAA,EAC1C,QAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF;AAGO,IAAM,eAAA,GAAqC;AAAA,EAChD,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF;AAGO,IAAM,YAAA,GAAiE;AAAA;AAAA,EAE5E,cAAA,EAAgB,KAAA;AAAA,EAChB,gBAAA,EAAkB,KAAA;AAAA;AAAA,EAGlB,eAAA,EAAiB,MAAA;AAAA,EACjB,eAAA,EAAiB,MAAA;AAAA,EACjB,aAAA,EAAe,MAAA;AAAA,EACf,WAAA,EAAa,MAAA;AAAA;AAAA,EAGb,eAAA,EAAiB;AACnB;AAGO,IAAM,iBAAA,GAAuC,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC;;;ACnDrD,SAAS,WAAW,IAAA,EAAuB;AAEhD,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,IAAI,KAAK,CAAC,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA,EAAG;AACrD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAQ,OAAO,CAAA,KAAM,CAAA,IAAK,OAAO,GAAA,KAAQ,CAAA,IAAM,OAAO,GAAA,KAAQ,CAAA;AAChE;AAqBO,SAAS,WAAA,CAAY,OAAe,IAAA,EAAsB;AAE/D,EAAA,IACE,CAAC,OAAO,QAAA,CAAS,KAAK,KACtB,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IACvB,CAAC,OAAO,QAAA,CAAS,IAAI,CAAA,IACrB,CAAC,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA,IACtB,KAAA,GAAQ,CAAA,IACR,KAAA,GAAQ,EAAA,EACR;AACA,IAAA,OAAO,CAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,EAAE,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3C,IAAA,OAAO,EAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,GAAG,CAAA,EAAG,CAAA,EAAG,EAAE,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAG;AACjC,IAAA,OAAO,EAAA;AAAA,EACT;AAGA,EAAA,OAAO,UAAA,CAAW,IAAI,CAAA,GAAI,EAAA,GAAK,EAAA;AACjC;AAsBO,SAAS,YAAY,IAAA,EAA6B;AACvD,EAAA,OAAO,gBAAgB,IAAA,IAAQ,CAAC,OAAO,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AAC7D;AAkBO,SAAS,UAAU,IAAA,EAAqB;AAC7C,EAAA,MAAM,GAAA,GAAM,KAAK,MAAA,EAAO;AACxB,EAAA,OAAO,GAAA,KAAQ,KAAK,GAAA,KAAQ,CAAA;AAC9B;AAmBO,SAAS,aAAa,IAAA,EAAqB;AAChD,EAAA,MAAM,GAAA,GAAM,KAAK,MAAA,EAAO;AACxB,EAAA,OAAO,GAAA,IAAO,KAAK,GAAA,IAAO,CAAA;AAC5B;AASA,SAAS,cAAc,IAAA,EAAoC;AACzD,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,MAAA,GAAS,IAAA;AAAA,EACX,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AACnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AACnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,iBAAiB,wCAAwC,CAAA;AAAA,EACrE;AAEA,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,OAAA,EAAS,CAAA,EAAG;AAClC,IAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,sBAAA,EAAyB,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACpE;AAEA,EAAA,OAAO,MAAA;AACT;AA4BO,SAAS,MAAA,CACd,SAAA,EACA,OAAA,GAAqE,EAAC,EACZ;AAC1D,EAAA,MAAM,KAAA,GAAQ,cAAc,SAAS,CAAA;AACrC,EAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,GAAW,aAAA,CAAc,QAAQ,QAAQ,CAAA,uBAAQ,IAAA,EAAK;AAG3E,EAAA,IAAI,KAAA,CAAM,OAAA,EAAQ,GAAI,IAAA,CAAK,SAAQ,EAAG;AACpC,IAAA,MAAM,IAAI,gBAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,WAAA,EAAY,GAAI,MAAM,WAAA,EAAY;AACnD,EAAA,IAAI,MAAA,GAAS,IAAA,CAAK,QAAA,EAAS,GAAI,MAAM,QAAA,EAAS;AAC9C,EAAA,IAAI,IAAA,GAAO,IAAA,CAAK,OAAA,EAAQ,GAAI,MAAM,OAAA,EAAQ;AAG1C,EAAA,IAAI,OAAO,CAAA,EAAG;AACZ,IAAA,MAAA,EAAA;AAEA,IAAA,MAAM,SAAA,GAAY,KAAK,QAAA,EAAS,KAAM,IAAI,EAAA,GAAK,IAAA,CAAK,UAAS,GAAI,CAAA;AACjE,IAAA,MAAM,aAAA,GACJ,IAAA,CAAK,QAAA,EAAS,KAAM,CAAA,GAAI,KAAK,WAAA,EAAY,GAAI,CAAA,GAAI,IAAA,CAAK,WAAA,EAAY;AACpE,IAAA,IAAA,IAAQ,WAAA,CAAY,SAAA,GAAY,CAAA,EAAG,aAAa,CAAA;AAAA,EAClD;AAGA,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,KAAA,EAAA;AACA,IAAA,MAAA,IAAU,EAAA;AAAA,EACZ;AAEA,EAAA,MAAM,MAAA,GAAS,EAAE,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAK;AAErC,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,OAAO,gBAAgB,MAAM,CAAA;AAAA,EAC/B;AAEA,EAAA,OAAO,MAAA;AACT;AASA,SAAS,gBAAgB,GAAA,EAId;AACT,EAAA,MAAM,QAAkB,EAAC;AAEzB,EAAA,IAAI,GAAA,CAAI,QAAQ,CAAA,EAAG;AACjB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAG,GAAA,CAAI,KAAK,CAAA,MAAA,CAAQ,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,MAAA,CAAQ,CAAA;AAAA,EAClC;AAEA,EAAA,IAAI,GAAA,CAAI,OAAO,CAAA,EAAG;AAChB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAG,GAAA,CAAI,IAAI,CAAA,KAAA,CAAO,CAAA;AAAA,EAC/B;AAGA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,GAAG,CAAA;AACvB;;;AC/OO,SAAS,UAAU,OAAA,EAA8B;AAEtD,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,EAAK;AAG7B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,IAAI,QAAQ,QAAA,CAAS,GAAG,KAAK,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AAClD,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA;AAGnC,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,CAAC,MAAM,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AAG7C,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,KAAM,MAAA,CAAO,MAAM,CAAC,CAAA,IAAK,CAAA,GAAI,CAAC,CAAA,EAAG;AAC9C,IAAA,OAAO,IAAA;AAAA,EACT;AAIA,EAAA,MAAM,CAAC,KAAA,EAAO,MAAA,EAAQ,KAAK,CAAA,GAAI,IAAA;AAG/B,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,IAAA;AAGJ,EAAA,IAAI,KAAA,GAAQ,GAAA,IAAO,KAAA,GAAQ,EAAA,EAAI;AAE7B,IAAA,IAAA,GAAO,KAAA;AACP,IAAA,KAAA,GAAQ,MAAA;AACR,IAAA,GAAA,GAAM,KAAA;AAAA,EACR,CAAA,MAAO;AAGL,IAAA,IAAI,QAAQ,GAAA,EAAM;AAChB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,GAAA,GAAM,KAAA;AACN,IAAA,KAAA,GAAQ,MAAA;AACR,IAAA,IAAA,GAAO,KAAA;AAAA,EACT;AAGA,EAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,GAAQ,EAAA,EAAI;AAC3B,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,IAAI,IAAA,GAAO,GAAA,IAAQ,IAAA,GAAO,IAAA,EAAM;AAC9B,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,KAAA,EAAO,IAAI,CAAA;AACvC,EAAA,IAAI,OAAA,KAAY,CAAA,IAAK,GAAA,GAAM,CAAA,IAAK,MAAM,OAAA,EAAS;AAC7C,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,OAAO,IAAI,IAAA,CAAK,IAAA,EAAM,KAAA,GAAQ,GAAG,GAAG,CAAA;AAI1C,EAAA,IACE,IAAA,CAAK,WAAA,EAAY,KAAM,IAAA,IACvB,IAAA,CAAK,QAAA,EAAS,KAAM,KAAA,GAAQ,CAAA,IAC5B,IAAA,CAAK,OAAA,EAAQ,KAAM,GAAA,EACnB;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA;AACT;;;AC1GA,SAASA,eAAc,IAAA,EAAoC;AACzD,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,MAAA,GAAS,IAAA;AAAA,EACX,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AAEnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AACnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,iBAAiB,wCAAwC,CAAA;AAAA,EACrE;AAGA,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,OAAA,EAAS,CAAA,EAAG;AAClC,IAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,sBAAA,EAAyB,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACpE;AAEA,EAAA,OAAO,MAAA;AACT;AAoBO,SAAS,UAAA,CACd,IAAA,EACA,KAAA,GAAmB,MAAA,EACX;AACR,EAAA,MAAM,CAAA,GAAIA,eAAc,IAAI,CAAA;AAE5B,EAAA,MAAM,GAAA,GAAM,EAAE,OAAA,EAAQ;AACtB,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,QAAA,EAAS,GAAI,CAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,EAAE,WAAA,EAAY;AAC3B,EAAA,MAAM,SAAA,GAAY,EAAE,MAAA,EAAO;AAE3B,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,MAAA;AACH,MAAA,OAAO,CAAA,EAAG,SAAA,CAAU,SAAS,CAAC,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA,EAAI,WAAA,CAAY,KAAK,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAAA,IAEtE,KAAK,MAAA;AACH,MAAA,OAAO,GAAG,GAAG,CAAA,CAAA,EAAI,YAAY,KAAK,CAAC,IAAI,IAAI,CAAA,CAAA;AAAA,IAE7C,KAAK,QAAA;AACH,MAAA,OAAO,GAAG,GAAG,CAAA,CAAA,EAAI,kBAAkB,KAAK,CAAC,IAAI,IAAI,CAAA,CAAA;AAAA,IAEnD,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,KAAK,MAAA,CAAO,GAAG,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACtC,MAAA,MAAM,KAAK,MAAA,CAAO,KAAK,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACxC,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC5B;AAAA,IAEA,KAAK,SAAA;AACH,MAAA,OAAO,UAAU,SAAS,CAAA;AAAA,IAE5B,KAAK,OAAA;AACH,MAAA,OAAO,YAAY,KAAK,CAAA;AAAA,IAE1B;AACE,MAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,sBAAA,EAAyB,KAAK,CAAA,CAAE,CAAA;AAAA;AAEjE;AAyCO,SAAS,eAAA,CACd,KAAA,EACA,GAAA,EACA,KAAA,GAAiD,MAAA,EACzC;AACR,EAAA,MAAM,CAAA,GAAIA,eAAc,KAAK,CAAA;AAC7B,EAAA,MAAM,CAAA,GAAIA,eAAc,GAAG,CAAA;AAG3B,EAAA,IAAI,CAAA,CAAE,OAAA,EAAQ,GAAI,CAAA,CAAE,SAAQ,EAAG;AAC7B,IAAA,MAAM,IAAI,qBAAA,EAAsB;AAAA,EAClC;AAGA,EAAA,IAAI,UAAU,OAAA,EAAS;AACrB,IAAA,OAAO,CAAA,EAAG,WAAW,CAAA,EAAG,OAAO,CAAC,CAAA,GAAA,EAAM,UAAA,CAAW,CAAA,EAAG,OAAO,CAAC,CAAA,CAAA;AAAA,EAC9D;AAGA,EAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,IAAA,OAAO,CAAA,EAAG,WAAW,CAAA,EAAG,MAAM,CAAC,CAAA,GAAA,EAAM,UAAA,CAAW,CAAA,EAAG,MAAM,CAAC,CAAA,CAAA;AAAA,EAC5D;AAGA,EAAA,MAAM,IAAA,GAAO,EAAE,OAAA,EAAQ;AACvB,EAAA,MAAM,IAAA,GAAO,EAAE,OAAA,EAAQ;AACvB,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,QAAA,EAAS,GAAI,CAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,QAAA,EAAS,GAAI,CAAA;AAC9B,EAAA,MAAM,KAAA,GAAQ,EAAE,WAAA,EAAY;AAC5B,EAAA,MAAM,KAAA,GAAQ,EAAE,WAAA,EAAY;AAG5B,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,MAAA,KAAW,MAAA,IAAU,UAAU,KAAA,EAAO;AACzD,IAAA,OAAO,UAAA,CAAW,GAAG,KAAK,CAAA;AAAA,EAC5B;AAGA,EAAA,IAAI,UAAU,KAAA,EAAO;AACnB,IAAA,OAAO,CAAA,EAAG,WAAW,CAAA,EAAG,KAAK,CAAC,CAAA,GAAA,EAAM,UAAA,CAAW,CAAA,EAAG,KAAK,CAAC,CAAA,CAAA;AAAA,EAC1D;AAGA,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,WAAA,CAAY,MAAM,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA,EAAI,WAAA,CAAY,MAAM,CAAC,IAAI,KAAK,CAAA,CAAA;AAAA,IACjF;AAEA,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,iBAAA,CAAkB,MAAM,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA,EAAI,iBAAA,CAAkB,MAAM,CAAC,IAAI,KAAK,CAAA,CAAA;AAAA,EAC7F;AAGA,EAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,GAAA,EAAM,IAAI,IAAI,WAAA,CAAY,MAAM,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,EAC1D;AAEA,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,GAAA,EAAM,IAAI,IAAI,iBAAA,CAAkB,MAAM,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAChE;;;ACjLA,SAASA,eAAc,IAAA,EAAoC;AACzD,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,IAAA,MAAA,GAAS,IAAA;AAAA,EACX,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AACnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAA,IAAW,OAAO,IAAA,KAAS,QAAA,EAAU;AACnC,IAAA,MAAA,GAAS,IAAI,KAAK,IAAI,CAAA;AAAA,EACxB,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,iBAAiB,wCAAwC,CAAA;AAAA,EACrE;AAEA,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,OAAA,EAAS,CAAA,EAAG;AAClC,IAAA,MAAM,IAAI,gBAAA,CAAiB,CAAA,sBAAA,EAAyB,MAAA,CAAO,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACpE;AAEA,EAAA,OAAO,MAAA;AACT;AAuBO,SAAS,cAAA,CACd,IAAA,EACA,QAAA,mBAAiB,IAAI,MAAK,EAClB;AACR,EAAA,MAAM,CAAA,GAAIA,eAAc,IAAI,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAOA,eAAc,QAAQ,CAAA;AAEnC,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,OAAA,EAAQ,GAAI,KAAK,OAAA,EAAQ;AAC1C,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAI,CAAA;AACxC,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,MAAA,IAAU,MAAO,EAAA,CAAG,CAAA;AAC/C,EAAA,MAAM,WAAW,IAAA,CAAK,KAAA,CAAM,MAAA,IAAU,GAAA,GAAO,KAAK,EAAA,CAAG,CAAA;AACrD,EAAA,MAAM,UAAU,IAAA,CAAK,KAAA,CAAM,UAAU,GAAA,GAAO,EAAA,GAAK,KAAK,EAAA,CAAG,CAAA;AAGzD,EAAA,IAAI,WAAW,CAAA,EAAG;AAChB,IAAA,OAAO,UAAA;AAAA,EACT;AAGA,EAAA,IAAI,SAAS,CAAA,EAAG;AAEd,IAAA,IAAI,UAAU,EAAA,EAAI;AAChB,MAAA,OAAO,WAAA;AAAA,IACT;AAGA,IAAA,IAAI,UAAU,EAAA,EAAI;AAChB,MAAA,OAAO,GAAG,OAAO,CAAA,WAAA,CAAA;AAAA,IACnB;AAGA,IAAA,IAAI,WAAW,EAAA,EAAI;AACjB,MAAA,OAAO,GAAG,QAAQ,CAAA,SAAA,CAAA;AAAA,IACpB;AAGA,IAAA,IAAI,WAAW,EAAA,EAAI;AACjB,MAAA,OAAO,OAAA;AAAA,IACT;AAGA,IAAA,IAAI,WAAW,EAAA,EAAI;AACjB,MAAA,OAAO,GAAG,OAAO,CAAA,UAAA,CAAA;AAAA,IACnB;AAGA,IAAA,OAAO,UAAA,CAAW,GAAG,MAAM,CAAA;AAAA,EAC7B;AAGA,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA;AACnC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA;AACnC,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAA;AACrC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA;AAGnC,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,OAAO,WAAA;AAAA,EACT;AAGA,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,OAAO,GAAG,UAAU,CAAA,gBAAA,CAAA;AAAA,EACtB;AAGA,EAAA,IAAI,cAAc,EAAA,EAAI;AACpB,IAAA,OAAO,GAAG,WAAW,CAAA,cAAA,CAAA;AAAA,EACvB;AAGA,EAAA,IAAI,cAAc,EAAA,EAAI;AACpB,IAAA,OAAO,SAAA;AAAA,EACT;AAGA,EAAA,IAAI,cAAc,EAAA,EAAI;AACpB,IAAA,OAAO,GAAG,UAAU,CAAA,eAAA,CAAA;AAAA,EACtB;AAGA,EAAA,OAAO,UAAA,CAAW,GAAG,MAAM,CAAA;AAC7B;;;AClGO,SAAS,sBACd,KAAA,EAC+B;AAE/B,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI,CAAC,OAAO,QAAA,CAAS,KAAK,KAAK,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,EAAG;AACvD,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,QAAQ,KAAA;AAAO,MACb,KAAK,CAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT;AACE,QAAA,OAAO,IAAA;AAAA;AACX,EACF;AAGA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAG3B,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,KAAA,CAAM,0BAA0B,CAAA;AAC5D,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAM,IAAA,GAAO,YAAY,CAAC,CAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,WAAA,CAAY,CAAC,GAAG,EAAE,CAAA;AACzC,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,WAAA,CAAY,CAAC,GAAG,EAAE,CAAA;AAG3C,IAAA,IAAI,SAAS,GAAA,EAAK;AAChB,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,IAAI,YAAY,CAAA,EAAG;AACjB,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,QAAQ,KAAA;AAAO,MACb,KAAK,CAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,CAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT;AACE,QAAA,OAAO,IAAA;AAAA;AACX,EACF;AAGA,EAAA,IAAI,YAAA,CAAa,OAAO,CAAA,EAAG;AACzB,IAAA,OAAO,aAAa,OAAO,CAAA;AAAA,EAC7B;AAGA,EAAA,OAAO,IAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Custom error classes for datetime module\n *\n * @module datetime/types\n * @packageDocumentation\n */\n\n/**\n * Error thrown when an invalid date is provided to a function.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDate('invalid');\n * } catch (error) {\n * if (error instanceof InvalidDateError) {\n * console.log(error.code); // 'INVALID_DATE'\n * }\n * }\n * ```\n */\nexport class InvalidDateError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE' as const;\n\n constructor(message: string = 'Invalid date provided') {\n super(message);\n this.name = 'InvalidDateError';\n }\n}\n\n/**\n * Error thrown when an invalid date range is provided.\n * Extends native Error with a `code` property for programmatic error handling.\n *\n * @example\n * ```typescript\n * try {\n * formatDateRange(new Date('2026-01-05'), new Date('2026-01-01'));\n * } catch (error) {\n * if (error instanceof InvalidDateRangeError) {\n * console.log(error.code); // 'INVALID_DATE_RANGE'\n * }\n * }\n * ```\n */\nexport class InvalidDateRangeError extends Error {\n /** Error code for programmatic identification */\n readonly code = 'INVALID_DATE_RANGE' as const;\n\n constructor(message: string = 'End date must be after start date') {\n super(message);\n this.name = 'InvalidDateRangeError';\n }\n}\n\n/**\n * Date formatting style options\n */\nexport type DateStyle =\n | 'full'\n | 'long'\n | 'medium'\n | 'short'\n | 'weekday'\n | 'month';\n\n/**\n * Options for getAge function\n */\nexport interface AgeOptions {\n /**\n * Reference date to calculate age from.\n * Defaults to current date at function call time.\n * @defaultValue new Date()\n */\n fromDate?: Date | string | number;\n\n /**\n * Return age as formatted string instead of object.\n * @defaultValue false\n */\n asString?: boolean;\n}\n\n/**\n * Age calculation result object\n */\nexport interface AgeResult {\n /** Full years */\n years: number;\n /** Remaining months (0-11) */\n months: number;\n /** Remaining days (0-30) */\n days: number;\n}\n","/**\n * Constants for Indonesian datetime formatting\n *\n * @module datetime/constants\n * @packageDocumentation\n */\n\n/** Full Indonesian month names (1-indexed: index 0 = empty, 1 = Januari) */\nexport const MONTH_NAMES: readonly string[] = [\n '', // Placeholder for 0-index\n 'Januari',\n 'Februari',\n 'Maret',\n 'April',\n 'Mei',\n 'Juni',\n 'Juli',\n 'Agustus',\n 'September',\n 'Oktober',\n 'November',\n 'Desember',\n];\n\n/** Short Indonesian month names (3-letter abbreviation) */\nexport const MONTH_NAMES_SHORT: readonly string[] = [\n '', // Placeholder for 0-index\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'Mei',\n 'Jun',\n 'Jul',\n 'Agu',\n 'Sep',\n 'Okt',\n 'Nov',\n 'Des',\n];\n\n/** Full Indonesian day names */\nexport const DAY_NAMES: readonly string[] = [\n 'Minggu',\n 'Senin',\n 'Selasa',\n 'Rabu',\n 'Kamis',\n 'Jumat',\n 'Sabtu',\n];\n\n/** Short Indonesian day names (3-letter abbreviation) */\nexport const DAY_NAMES_SHORT: readonly string[] = [\n 'Min',\n 'Sen',\n 'Sel',\n 'Rab',\n 'Kam',\n 'Jum',\n 'Sab',\n];\n\n/** Mapping of IANA timezone names to Indonesian abbreviations */\nexport const TIMEZONE_MAP: Readonly<Record<string, 'WIB' | 'WITA' | 'WIT'>> = {\n // UTC+7 - WIB\n 'Asia/Jakarta': 'WIB',\n 'Asia/Pontianak': 'WIB',\n\n // UTC+8 - WITA\n 'Asia/Makassar': 'WITA',\n 'Asia/Denpasar': 'WITA',\n 'Asia/Manado': 'WITA',\n 'Asia/Palu': 'WITA',\n\n // UTC+9 - WIT\n 'Asia/Jayapura': 'WIT',\n};\n\n/** Valid UTC offset hours that map to Indonesian timezones */\nexport const VALID_UTC_OFFSETS: readonly number[] = [7, 8, 9];\n","/**\n * Date calculation utilities\n *\n * @module datetime/calc\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\n\n/**\n * Check if a year is a leap year.\n *\n * A year is a leap year if:\n * - Divisible by 4, but not by 100, OR\n * - Divisible by 400\n *\n * @param year - The year to check\n * @returns `true` if leap year, `false` otherwise (including invalid inputs)\n *\n * @example\n * ```typescript\n * isLeapYear(2024); // true\n * isLeapYear(2023); // false\n * isLeapYear(1900); // false (divisible by 100 but not 400)\n * isLeapYear(2000); // true (divisible by 400)\n * isLeapYear(NaN); // false\n * isLeapYear(3.5); // false (non-integer)\n * ```\n */\nexport function isLeapYear(year: number): boolean {\n // Return false for non-finite, non-integer, or NaN values\n if (!Number.isFinite(year) || !Number.isInteger(year)) {\n return false;\n }\n\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\n/**\n * Get the number of days in a month.\n *\n * Accounts for leap years in February.\n *\n * @param month - Month number (1-12, 1-indexed)\n * @param year - Full year (e.g., 2026)\n * @returns Number of days in the month, or 0 for invalid inputs\n *\n * @example\n * ```typescript\n * daysInMonth(1, 2026); // 31 (January)\n * daysInMonth(2, 2024); // 29 (February, leap year)\n * daysInMonth(2, 2023); // 28 (February, non-leap year)\n * daysInMonth(4, 2026); // 30 (April)\n * daysInMonth(13, 2026); // 0 (invalid month)\n * daysInMonth(2, NaN); // 0 (invalid year)\n * ```\n */\nexport function daysInMonth(month: number, year: number): number {\n // Validate inputs\n if (\n !Number.isFinite(month) ||\n !Number.isInteger(month) ||\n !Number.isFinite(year) ||\n !Number.isInteger(year) ||\n month < 1 ||\n month > 12\n ) {\n return 0;\n }\n\n // Months with 31 days: Jan(1), Mar(3), May(5), Jul(7), Aug(8), Oct(10), Dec(12)\n if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {\n return 31;\n }\n\n // Months with 30 days: Apr(4), Jun(6), Sep(9), Nov(11)\n if ([4, 6, 9, 11].includes(month)) {\n return 30;\n }\n\n // February - check for leap year\n return isLeapYear(year) ? 29 : 28;\n}\n\n/**\n * Type guard to check if a value is a valid Date object.\n *\n * Returns `true` only for Date instances that represent a valid date\n * (i.e., not `Invalid Date`). Returns `false` for null, undefined,\n * invalid dates, and non-Date values.\n *\n * @param date - Value to check\n * @returns `true` if valid Date object, `false` otherwise\n *\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate(new Date('invalid')); // false\n * isValidDate(null); // false\n * isValidDate(undefined); // false\n * isValidDate('2024-01-01'); // false (string, not Date)\n * isValidDate(1704067200000); // false (number, not Date)\n * ```\n */\nexport function isValidDate(date: unknown): date is Date {\n return date instanceof Date && !Number.isNaN(date.getTime());\n}\n\n/**\n * Check if a date falls on a weekend (Saturday or Sunday).\n *\n * Note: This only checks Saturday/Sunday and does not account for\n * industry-specific Saturday work schedules.\n *\n * @param date - Date object to check\n * @returns `true` if Saturday or Sunday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWeekend(new Date('2026-01-03')); // true (Saturday)\n * isWeekend(new Date('2026-01-04')); // true (Sunday)\n * isWeekend(new Date('2026-01-05')); // false (Monday)\n * ```\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6; // Sunday = 0, Saturday = 6\n}\n\n/**\n * Check if a date falls on a working day (Monday-Friday).\n *\n * Note: This only checks Monday-Friday and does not account for\n * national holidays (holiday lists require periodic updates and\n * are not included per project mandates).\n *\n * @param date - Date object to check\n * @returns `true` if Monday-Friday, `false` otherwise\n *\n * @example\n * ```typescript\n * isWorkingDay(new Date('2026-01-05')); // true (Monday)\n * isWorkingDay(new Date('2026-01-03')); // false (Saturday)\n * isWorkingDay(new Date('2026-01-04')); // false (Sunday)\n * ```\n */\nexport function isWorkingDay(date: Date): boolean {\n const day = date.getDay();\n return day >= 1 && day <= 5; // Monday = 1 to Friday = 5\n}\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Calculate age from a birth date.\n *\n * Accounts for leap years and month length variations.\n * Can return as an object { years, months, days } or as a formatted string.\n *\n * @param birthDate - Birth date (Date, string, or number timestamp)\n * @param options - Options for age calculation\n * @returns Age as object or formatted string (based on asString option)\n * @throws {InvalidDateError} If birthDate or fromDate is invalid\n *\n * @example\n * ```typescript\n * // Get age as object\n * getAge('1990-06-15'); // { years: 36, months: 9, days: 21 }\n * getAge(new Date('1990-06-15'), { fromDate: new Date('2024-06-15') });\n * // { years: 34, months: 0, days: 0 }\n *\n * // Get age as string\n * getAge('1990-06-15', { asString: true });\n * // '36 Tahun 9 Bulan 21 Hari'\n *\n * getAge(new Date('2020-01-01'), { fromDate: new Date('2020-01-15'), asString: true });\n * // '15 Hari'\n * ```\n */\nexport function getAge(\n birthDate: Date | string | number,\n options: { fromDate?: Date | string | number; asString?: boolean } = {}\n): { years: number; months: number; days: number } | string {\n const birth = normalizeDate(birthDate);\n const from = options.fromDate ? normalizeDate(options.fromDate) : new Date();\n\n // Validate: birth date cannot be in the future\n if (birth.getTime() > from.getTime()) {\n throw new InvalidDateError(\n 'Birth date cannot be in the future relative to fromDate'\n );\n }\n\n let years = from.getFullYear() - birth.getFullYear();\n let months = from.getMonth() - birth.getMonth();\n let days = from.getDate() - birth.getDate();\n\n // Adjust for negative days\n if (days < 0) {\n months--;\n // Get days in previous month\n const prevMonth = from.getMonth() === 0 ? 11 : from.getMonth() - 1;\n const prevMonthYear =\n from.getMonth() === 0 ? from.getFullYear() - 1 : from.getFullYear();\n days += daysInMonth(prevMonth + 1, prevMonthYear);\n }\n\n // Adjust for negative months\n if (months < 0) {\n years--;\n months += 12;\n }\n\n const result = { years, months, days };\n\n if (options.asString) {\n return formatAgeString(result);\n }\n\n return result;\n}\n\n/**\n * Format age object as Indonesian string.\n * Omits zero components.\n *\n * @param age - Age object with years, months, days\n * @returns Formatted age string\n */\nfunction formatAgeString(age: {\n years: number;\n months: number;\n days: number;\n}): string {\n const parts: string[] = [];\n\n if (age.years > 0) {\n parts.push(`${age.years} Tahun`);\n }\n\n if (age.months > 0) {\n parts.push(`${age.months} Bulan`);\n }\n\n if (age.days > 0) {\n parts.push(`${age.days} Hari`);\n }\n\n // Handle edge case: all zeros (same day)\n if (parts.length === 0) {\n return '0 Hari';\n }\n\n return parts.join(' ');\n}\n","/**\n * Date parsing utilities for Indonesian formats\n *\n * @module datetime/parse\n * @packageDocumentation\n */\n\nimport { daysInMonth } from './calc';\n\n/**\n * Parse a date string in Indonesian format (DD-MM-YYYY) or ISO format (YYYY-MM-DD).\n *\n * Strict parsing rules:\n * - Accepts delimiters: `/`, `-`, `.`\n * - DD-MM-YYYY format: Day first (1-31), 4-digit year required\n * - ISO auto-detection: If first segment is 4 digits AND > 31, treated as YYYY-MM-DD\n * - Leap year validation: Feb 29 is only valid in leap years\n * - 2-digit years NOT supported\n * - Time components NOT supported\n *\n * @param dateStr - Date string to parse\n * @returns Date object if valid, `null` if invalid\n *\n * @example\n * ```typescript\n * // Indonesian format (DD-MM-YYYY)\n * parseDate('02-01-2026'); // Date(2026, 0, 2) - Jan 2, 2026\n * parseDate('02/01/2026'); // Date(2026, 0, 2)\n * parseDate('02.01.2026'); // Date(2026, 0, 2)\n *\n * // ISO format auto-detected (YYYY-MM-DD)\n * parseDate('2026-01-02'); // Date(2026, 0, 2)\n *\n * // Invalid inputs return null\n * parseDate('29-02-2023'); // null (not a leap year)\n * parseDate('02-01-26'); // null (2-digit year)\n * parseDate('02-01-2026 14:30'); // null (time component)\n * parseDate('invalid'); // null\n * ```\n */\nexport function parseDate(dateStr: string): Date | null {\n // Trim whitespace\n const trimmed = dateStr.trim();\n\n // Reject if empty\n if (!trimmed) {\n return null;\n }\n\n // Reject if contains time component (has space or colon)\n if (trimmed.includes(' ') || trimmed.includes(':')) {\n return null;\n }\n\n // Split by supported delimiters: / - .\n const parts = trimmed.split(/[-/.]/);\n\n // Must have exactly 3 parts\n if (parts.length !== 3) {\n return null;\n }\n\n // Parse all segments as integers\n const nums = parts.map((p) => parseInt(p, 10));\n\n // Check for NaN or negative values\n if (nums.some((n) => Number.isNaN(n) || n < 0)) {\n return null;\n }\n\n // Check for 2-digit years (any segment < 100 after the first position)\n // First segment can be < 100 (day) or > 31 (year in ISO format)\n const [first, second, third] = nums;\n\n // Determine format: ISO (YYYY-MM-DD) or Indonesian (DD-MM-YYYY)\n let day: number;\n let month: number;\n let year: number;\n\n // ISO format detection: first segment is 4 digits AND > 31 (must be a year)\n if (first > 999 && first > 31) {\n // ISO format: YYYY-MM-DD\n year = first;\n month = second;\n day = third;\n } else {\n // Indonesian format: DD-MM-YYYY\n // Validate that third segment is 4 digits (year)\n if (third < 1000) {\n return null; // 2-digit year not supported\n }\n\n day = first;\n month = second;\n year = third;\n }\n\n // Validate month range (1-12)\n if (month < 1 || month > 12) {\n return null;\n }\n\n // Validate year is reasonable (positive and 4 digits)\n if (year < 1000 || year > 9999) {\n return null;\n }\n\n // Validate day against month length\n const maxDays = daysInMonth(month, year);\n if (maxDays === 0 || day < 1 || day > maxDays) {\n return null;\n }\n\n // Create date (month is 0-indexed in JS Date)\n const date = new Date(year, month - 1, day);\n\n // Final validation: ensure the date was created correctly\n // (catches edge cases like Feb 30 being converted to Mar 2)\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return null;\n }\n\n return date;\n}\n","/**\n * Date formatting utilities for Indonesian locale\n *\n * @module datetime/format\n * @packageDocumentation\n */\n\nimport {\n InvalidDateError,\n InvalidDateRangeError,\n type DateStyle,\n} from './types';\nimport { MONTH_NAMES, MONTH_NAMES_SHORT, DAY_NAMES } from './constants';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n // Assume milliseconds timestamp\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n // Validate the result\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date with Indonesian locale.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date string\n * @throws {InvalidDateError} If the date is invalid\n *\n * @example\n * ```typescript\n * formatDate(new Date('2026-01-02'), 'full'); // 'Jumat, 2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'long'); // '2 Januari 2026'\n * formatDate(new Date('2026-01-02'), 'medium'); // '2 Jan 2026'\n * formatDate(new Date('2026-01-02'), 'short'); // '02/01/2026'\n * formatDate(new Date('2026-01-02'), 'weekday'); // 'Jumat'\n * formatDate(new Date('2026-01-02'), 'month'); // 'Januari'\n * ```\n */\nexport function formatDate(\n date: Date | string | number,\n style: DateStyle = 'long'\n): string {\n const d = normalizeDate(date);\n\n const day = d.getDate();\n const month = d.getMonth() + 1; // 1-indexed\n const year = d.getFullYear();\n const dayOfWeek = d.getDay(); // 0 = Sunday\n\n switch (style) {\n case 'full':\n return `${DAY_NAMES[dayOfWeek]}, ${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'long':\n return `${day} ${MONTH_NAMES[month]} ${year}`;\n\n case 'medium':\n return `${day} ${MONTH_NAMES_SHORT[month]} ${year}`;\n\n case 'short': {\n const dd = String(day).padStart(2, '0');\n const mm = String(month).padStart(2, '0');\n return `${dd}/${mm}/${year}`;\n }\n\n case 'weekday':\n return DAY_NAMES[dayOfWeek];\n\n case 'month':\n return MONTH_NAMES[month];\n\n default:\n throw new InvalidDateError(`Unknown format style: ${style}`);\n }\n}\n\n/**\n * Format a date range with Indonesian locale and smart redundancy removal.\n *\n * Removes redundant month/year information when dates share them.\n *\n * @param start - Start date\n * @param end - End date\n * @param style - Formatting style (default: 'long')\n * @returns Formatted date range string\n * @throws {InvalidDateError} If either date is invalid\n * @throws {InvalidDateRangeError} If end date is before start date\n *\n * @example\n * ```typescript\n * // Same day\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-02')\n * ); // '2 Januari 2026'\n *\n * // Same month & year\n * formatDateRange(\n * new Date('2026-01-02'),\n * new Date('2026-01-05')\n * ); // '2 - 5 Januari 2026'\n *\n * // Same year\n * formatDateRange(\n * new Date('2026-01-30'),\n * new Date('2026-02-02')\n * ); // '30 Januari - 2 Februari 2026'\n *\n * // Different year\n * formatDateRange(\n * new Date('2025-12-30'),\n * new Date('2026-01-02')\n * ); // '30 Desember 2025 - 2 Januari 2026'\n * ```\n */\nexport function formatDateRange(\n start: Date,\n end: Date,\n style: Exclude<DateStyle, 'weekday' | 'month'> = 'long'\n): string {\n const s = normalizeDate(start);\n const e = normalizeDate(end);\n\n // Validate range\n if (e.getTime() < s.getTime()) {\n throw new InvalidDateRangeError();\n }\n\n // Short style: no redundancy removal, always full format\n if (style === 'short') {\n return `${formatDate(s, 'short')} - ${formatDate(e, 'short')}`;\n }\n\n // Full style: full weekday + date for both\n if (style === 'full') {\n return `${formatDate(s, 'full')} - ${formatDate(e, 'full')}`;\n }\n\n // Extract components\n const sDay = s.getDate();\n const eDay = e.getDate();\n const sMonth = s.getMonth() + 1;\n const eMonth = e.getMonth() + 1;\n const sYear = s.getFullYear();\n const eYear = e.getFullYear();\n\n // Same day: show single date\n if (sDay === eDay && sMonth === eMonth && sYear === eYear) {\n return formatDate(s, style);\n }\n\n // Different year: full format for both\n if (sYear !== eYear) {\n return `${formatDate(s, style)} - ${formatDate(e, style)}`;\n }\n\n // Same year, different month: omit year from start date\n if (sMonth !== eMonth) {\n if (style === 'long') {\n return `${sDay} ${MONTH_NAMES[sMonth]} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} ${MONTH_NAMES_SHORT[sMonth]} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n }\n\n // Same month & year: show range with single month/year\n if (style === 'long') {\n return `${sDay} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;\n }\n // medium style\n return `${sDay} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;\n}\n","/**\n * Relative time formatting for Indonesian locale\n *\n * @module datetime/relative\n * @packageDocumentation\n */\n\nimport { InvalidDateError } from './types';\nimport { formatDate } from './format';\n\n/**\n * Normalize various date input types to a Date object.\n *\n * @param date - Date input (Date, string, or number timestamp)\n * @returns Date object\n * @throws {InvalidDateError} If the input cannot be parsed to a valid date\n */\nfunction normalizeDate(date: Date | string | number): Date {\n let result: Date;\n\n if (date instanceof Date) {\n result = date;\n } else if (typeof date === 'number') {\n result = new Date(date);\n } else if (typeof date === 'string') {\n result = new Date(date);\n } else {\n throw new InvalidDateError('Date must be a Date, string, or number');\n }\n\n if (Number.isNaN(result.getTime())) {\n throw new InvalidDateError(`Unable to parse date: ${String(date)}`);\n }\n\n return result;\n}\n\n/**\n * Format a date as relative time in Indonesian.\n *\n * Returns human-readable relative time like \"Baru saja\", \"X menit yang lalu\",\n * \"Kemarin\", or falls back to formatted date for older dates.\n *\n * @param date - Date to format (Date, string, or number timestamp in milliseconds)\n * @param baseDate - Reference date for comparison (default: current date)\n * @returns Relative time string in Indonesian\n * @throws {InvalidDateError} If either date is invalid\n *\n * @example\n * ```typescript\n * // Assuming today is 2026-01-02 12:00:00\n * toRelativeTime(new Date('2026-01-02 11:59:00')); // 'Baru saja'\n * toRelativeTime(new Date('2026-01-02 11:00:00')); // '1 jam yang lalu'\n * toRelativeTime(new Date('2026-01-01 12:00:00')); // 'Kemarin'\n * toRelativeTime(new Date('2025-12-30 12:00:00')); // '3 hari yang lalu'\n * toRelativeTime(new Date('2025-12-01 12:00:00')); // '1 Desember 2025'\n * ```\n */\nexport function toRelativeTime(\n date: Date | string | number,\n baseDate: Date = new Date()\n): string {\n const d = normalizeDate(date);\n const base = normalizeDate(baseDate);\n\n const diffMs = d.getTime() - base.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffMs / (1000 * 60));\n const diffHour = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDay = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n // Exact match\n if (diffMs === 0) {\n return 'Sekarang';\n }\n\n // Future dates\n if (diffMs > 0) {\n // < 1 minute\n if (diffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (diffMin < 60) {\n return `${diffMin} menit lagi`;\n }\n\n // < 24 hours\n if (diffHour < 24) {\n return `${diffHour} jam lagi`;\n }\n\n // 1 day (24-48 hours)\n if (diffHour < 48) {\n return 'Besok';\n }\n\n // 2-30 days\n if (diffDay <= 30) {\n return `${diffDay} hari lagi`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n }\n\n // Past dates\n const absDiffSec = Math.abs(diffSec);\n const absDiffMin = Math.abs(diffMin);\n const absDiffHour = Math.abs(diffHour);\n const absDiffDay = Math.abs(diffDay);\n\n // < 1 minute\n if (absDiffSec < 60) {\n return 'Baru saja';\n }\n\n // < 60 minutes\n if (absDiffMin < 60) {\n return `${absDiffMin} menit yang lalu`;\n }\n\n // < 24 hours\n if (absDiffHour < 24) {\n return `${absDiffHour} jam yang lalu`;\n }\n\n // 1 day (24-48 hours)\n if (absDiffHour < 48) {\n return 'Kemarin';\n }\n\n // 2-30 days\n if (absDiffDay <= 30) {\n return `${absDiffDay} hari yang lalu`;\n }\n\n // > 30 days: fallback to formatted date\n return formatDate(d, 'long');\n}\n","/**\n * Timezone utilities for Indonesian locale\n *\n * @module datetime/timezone\n * @packageDocumentation\n */\n\nimport { TIMEZONE_MAP } from './constants';\n\n/**\n * Map IANA timezone names or UTC offsets to Indonesian abbreviations (WIB/WITA/WIT).\n *\n * Supported mappings:\n * - UTC+7 / Asia/Jakarta / Asia/Pontianak → \"WIB\"\n * - UTC+8 / Asia/Makassar / Asia/Denpasar → \"WITA\"\n * - UTC+9 / Asia/Jayapura → \"WIT\"\n *\n * @param input - IANA timezone name (case-sensitive), offset in hours, or offset string\n * @returns Indonesian timezone abbreviation or null if not Indonesian\n *\n * @example\n * ```typescript\n * // IANA timezone names\n * getIndonesianTimezone('Asia/Jakarta'); // 'WIB'\n * getIndonesianTimezone('Asia/Makassar'); // 'WITA'\n * getIndonesianTimezone('Asia/Jayapura'); // 'WIT'\n *\n * // Offset as number (hours)\n * getIndonesianTimezone(7); // 'WIB'\n * getIndonesianTimezone(8); // 'WITA'\n * getIndonesianTimezone(9); // 'WIT'\n *\n * // Offset as string\n * getIndonesianTimezone('+07:00'); // 'WIB'\n * getIndonesianTimezone('+0700'); // 'WIB'\n * getIndonesianTimezone('+08:00'); // 'WITA'\n *\n * // Non-Indonesian returns null\n * getIndonesianTimezone('America/New_York'); // null\n * getIndonesianTimezone(-5); // null\n * ```\n */\nexport function getIndonesianTimezone(\n input: string | number\n): 'WIB' | 'WITA' | 'WIT' | null {\n // Handle number input (offset in hours)\n if (typeof input === 'number') {\n if (!Number.isFinite(input) || !Number.isInteger(input)) {\n return null;\n }\n\n switch (input) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Handle string input\n if (typeof input !== 'string') {\n return null;\n }\n\n const trimmed = input.trim();\n\n // Check if it's an offset string (+07:00, +0700, -05:00, etc.)\n const offsetMatch = trimmed.match(/^([+-])(\\d{2}):?(\\d{2})$/);\n if (offsetMatch) {\n const sign = offsetMatch[1];\n const hours = parseInt(offsetMatch[2], 10);\n const minutes = parseInt(offsetMatch[3], 10);\n\n // Indonesian timezones are all positive (UTC+)\n if (sign === '-') {\n return null;\n }\n\n // Validate format (must be exactly on the hour, no minutes)\n if (minutes !== 0) {\n return null;\n }\n\n // Map to Indonesian timezone\n switch (hours) {\n case 7:\n return 'WIB';\n case 8:\n return 'WITA';\n case 9:\n return 'WIT';\n default:\n return null;\n }\n }\n\n // Check if it's an IANA timezone name\n if (TIMEZONE_MAP[trimmed]) {\n return TIMEZONE_MAP[trimmed];\n }\n\n // Unknown timezone\n return null;\n}\n"]}
@@ -0,0 +1,412 @@
1
+ /**
2
+ * Custom error classes for datetime module
3
+ *
4
+ * @module datetime/types
5
+ * @packageDocumentation
6
+ */
7
+ /**
8
+ * Error thrown when an invalid date is provided to a function.
9
+ * Extends native Error with a `code` property for programmatic error handling.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * try {
14
+ * formatDate('invalid');
15
+ * } catch (error) {
16
+ * if (error instanceof InvalidDateError) {
17
+ * console.log(error.code); // 'INVALID_DATE'
18
+ * }
19
+ * }
20
+ * ```
21
+ */
22
+ declare class InvalidDateError extends Error {
23
+ /** Error code for programmatic identification */
24
+ readonly code: "INVALID_DATE";
25
+ constructor(message?: string);
26
+ }
27
+ /**
28
+ * Error thrown when an invalid date range is provided.
29
+ * Extends native Error with a `code` property for programmatic error handling.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * try {
34
+ * formatDateRange(new Date('2026-01-05'), new Date('2026-01-01'));
35
+ * } catch (error) {
36
+ * if (error instanceof InvalidDateRangeError) {
37
+ * console.log(error.code); // 'INVALID_DATE_RANGE'
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ declare class InvalidDateRangeError extends Error {
43
+ /** Error code for programmatic identification */
44
+ readonly code: "INVALID_DATE_RANGE";
45
+ constructor(message?: string);
46
+ }
47
+ /**
48
+ * Date formatting style options
49
+ */
50
+ type DateStyle = 'full' | 'long' | 'medium' | 'short' | 'weekday' | 'month';
51
+ /**
52
+ * Options for getAge function
53
+ */
54
+ interface AgeOptions {
55
+ /**
56
+ * Reference date to calculate age from.
57
+ * Defaults to current date at function call time.
58
+ * @defaultValue new Date()
59
+ */
60
+ fromDate?: Date | string | number;
61
+ /**
62
+ * Return age as formatted string instead of object.
63
+ * @defaultValue false
64
+ */
65
+ asString?: boolean;
66
+ }
67
+ /**
68
+ * Age calculation result object
69
+ */
70
+ interface AgeResult {
71
+ /** Full years */
72
+ years: number;
73
+ /** Remaining months (0-11) */
74
+ months: number;
75
+ /** Remaining days (0-30) */
76
+ days: number;
77
+ }
78
+
79
+ /**
80
+ * Constants for Indonesian datetime formatting
81
+ *
82
+ * @module datetime/constants
83
+ * @packageDocumentation
84
+ */
85
+ /** Full Indonesian month names (1-indexed: index 0 = empty, 1 = Januari) */
86
+ declare const MONTH_NAMES: readonly string[];
87
+ /** Short Indonesian month names (3-letter abbreviation) */
88
+ declare const MONTH_NAMES_SHORT: readonly string[];
89
+ /** Full Indonesian day names */
90
+ declare const DAY_NAMES: readonly string[];
91
+ /** Short Indonesian day names (3-letter abbreviation) */
92
+ declare const DAY_NAMES_SHORT: readonly string[];
93
+ /** Mapping of IANA timezone names to Indonesian abbreviations */
94
+ declare const TIMEZONE_MAP: Readonly<Record<string, 'WIB' | 'WITA' | 'WIT'>>;
95
+ /** Valid UTC offset hours that map to Indonesian timezones */
96
+ declare const VALID_UTC_OFFSETS: readonly number[];
97
+
98
+ /**
99
+ * Date calculation utilities
100
+ *
101
+ * @module datetime/calc
102
+ * @packageDocumentation
103
+ */
104
+ /**
105
+ * Check if a year is a leap year.
106
+ *
107
+ * A year is a leap year if:
108
+ * - Divisible by 4, but not by 100, OR
109
+ * - Divisible by 400
110
+ *
111
+ * @param year - The year to check
112
+ * @returns `true` if leap year, `false` otherwise (including invalid inputs)
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * isLeapYear(2024); // true
117
+ * isLeapYear(2023); // false
118
+ * isLeapYear(1900); // false (divisible by 100 but not 400)
119
+ * isLeapYear(2000); // true (divisible by 400)
120
+ * isLeapYear(NaN); // false
121
+ * isLeapYear(3.5); // false (non-integer)
122
+ * ```
123
+ */
124
+ declare function isLeapYear(year: number): boolean;
125
+ /**
126
+ * Get the number of days in a month.
127
+ *
128
+ * Accounts for leap years in February.
129
+ *
130
+ * @param month - Month number (1-12, 1-indexed)
131
+ * @param year - Full year (e.g., 2026)
132
+ * @returns Number of days in the month, or 0 for invalid inputs
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * daysInMonth(1, 2026); // 31 (January)
137
+ * daysInMonth(2, 2024); // 29 (February, leap year)
138
+ * daysInMonth(2, 2023); // 28 (February, non-leap year)
139
+ * daysInMonth(4, 2026); // 30 (April)
140
+ * daysInMonth(13, 2026); // 0 (invalid month)
141
+ * daysInMonth(2, NaN); // 0 (invalid year)
142
+ * ```
143
+ */
144
+ declare function daysInMonth(month: number, year: number): number;
145
+ /**
146
+ * Type guard to check if a value is a valid Date object.
147
+ *
148
+ * Returns `true` only for Date instances that represent a valid date
149
+ * (i.e., not `Invalid Date`). Returns `false` for null, undefined,
150
+ * invalid dates, and non-Date values.
151
+ *
152
+ * @param date - Value to check
153
+ * @returns `true` if valid Date object, `false` otherwise
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * isValidDate(new Date()); // true
158
+ * isValidDate(new Date('invalid')); // false
159
+ * isValidDate(null); // false
160
+ * isValidDate(undefined); // false
161
+ * isValidDate('2024-01-01'); // false (string, not Date)
162
+ * isValidDate(1704067200000); // false (number, not Date)
163
+ * ```
164
+ */
165
+ declare function isValidDate(date: unknown): date is Date;
166
+ /**
167
+ * Check if a date falls on a weekend (Saturday or Sunday).
168
+ *
169
+ * Note: This only checks Saturday/Sunday and does not account for
170
+ * industry-specific Saturday work schedules.
171
+ *
172
+ * @param date - Date object to check
173
+ * @returns `true` if Saturday or Sunday, `false` otherwise
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * isWeekend(new Date('2026-01-03')); // true (Saturday)
178
+ * isWeekend(new Date('2026-01-04')); // true (Sunday)
179
+ * isWeekend(new Date('2026-01-05')); // false (Monday)
180
+ * ```
181
+ */
182
+ declare function isWeekend(date: Date): boolean;
183
+ /**
184
+ * Check if a date falls on a working day (Monday-Friday).
185
+ *
186
+ * Note: This only checks Monday-Friday and does not account for
187
+ * national holidays (holiday lists require periodic updates and
188
+ * are not included per project mandates).
189
+ *
190
+ * @param date - Date object to check
191
+ * @returns `true` if Monday-Friday, `false` otherwise
192
+ *
193
+ * @example
194
+ * ```typescript
195
+ * isWorkingDay(new Date('2026-01-05')); // true (Monday)
196
+ * isWorkingDay(new Date('2026-01-03')); // false (Saturday)
197
+ * isWorkingDay(new Date('2026-01-04')); // false (Sunday)
198
+ * ```
199
+ */
200
+ declare function isWorkingDay(date: Date): boolean;
201
+ /**
202
+ * Calculate age from a birth date.
203
+ *
204
+ * Accounts for leap years and month length variations.
205
+ * Can return as an object { years, months, days } or as a formatted string.
206
+ *
207
+ * @param birthDate - Birth date (Date, string, or number timestamp)
208
+ * @param options - Options for age calculation
209
+ * @returns Age as object or formatted string (based on asString option)
210
+ * @throws {InvalidDateError} If birthDate or fromDate is invalid
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * // Get age as object
215
+ * getAge('1990-06-15'); // { years: 36, months: 9, days: 21 }
216
+ * getAge(new Date('1990-06-15'), { fromDate: new Date('2024-06-15') });
217
+ * // { years: 34, months: 0, days: 0 }
218
+ *
219
+ * // Get age as string
220
+ * getAge('1990-06-15', { asString: true });
221
+ * // '36 Tahun 9 Bulan 21 Hari'
222
+ *
223
+ * getAge(new Date('2020-01-01'), { fromDate: new Date('2020-01-15'), asString: true });
224
+ * // '15 Hari'
225
+ * ```
226
+ */
227
+ declare function getAge(birthDate: Date | string | number, options?: {
228
+ fromDate?: Date | string | number;
229
+ asString?: boolean;
230
+ }): {
231
+ years: number;
232
+ months: number;
233
+ days: number;
234
+ } | string;
235
+
236
+ /**
237
+ * Date parsing utilities for Indonesian formats
238
+ *
239
+ * @module datetime/parse
240
+ * @packageDocumentation
241
+ */
242
+ /**
243
+ * Parse a date string in Indonesian format (DD-MM-YYYY) or ISO format (YYYY-MM-DD).
244
+ *
245
+ * Strict parsing rules:
246
+ * - Accepts delimiters: `/`, `-`, `.`
247
+ * - DD-MM-YYYY format: Day first (1-31), 4-digit year required
248
+ * - ISO auto-detection: If first segment is 4 digits AND > 31, treated as YYYY-MM-DD
249
+ * - Leap year validation: Feb 29 is only valid in leap years
250
+ * - 2-digit years NOT supported
251
+ * - Time components NOT supported
252
+ *
253
+ * @param dateStr - Date string to parse
254
+ * @returns Date object if valid, `null` if invalid
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Indonesian format (DD-MM-YYYY)
259
+ * parseDate('02-01-2026'); // Date(2026, 0, 2) - Jan 2, 2026
260
+ * parseDate('02/01/2026'); // Date(2026, 0, 2)
261
+ * parseDate('02.01.2026'); // Date(2026, 0, 2)
262
+ *
263
+ * // ISO format auto-detected (YYYY-MM-DD)
264
+ * parseDate('2026-01-02'); // Date(2026, 0, 2)
265
+ *
266
+ * // Invalid inputs return null
267
+ * parseDate('29-02-2023'); // null (not a leap year)
268
+ * parseDate('02-01-26'); // null (2-digit year)
269
+ * parseDate('02-01-2026 14:30'); // null (time component)
270
+ * parseDate('invalid'); // null
271
+ * ```
272
+ */
273
+ declare function parseDate(dateStr: string): Date | null;
274
+
275
+ /**
276
+ * Date formatting utilities for Indonesian locale
277
+ *
278
+ * @module datetime/format
279
+ * @packageDocumentation
280
+ */
281
+
282
+ /**
283
+ * Format a date with Indonesian locale.
284
+ *
285
+ * @param date - Date to format (Date, string, or number timestamp in milliseconds)
286
+ * @param style - Formatting style (default: 'long')
287
+ * @returns Formatted date string
288
+ * @throws {InvalidDateError} If the date is invalid
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * formatDate(new Date('2026-01-02'), 'full'); // 'Jumat, 2 Januari 2026'
293
+ * formatDate(new Date('2026-01-02'), 'long'); // '2 Januari 2026'
294
+ * formatDate(new Date('2026-01-02'), 'medium'); // '2 Jan 2026'
295
+ * formatDate(new Date('2026-01-02'), 'short'); // '02/01/2026'
296
+ * formatDate(new Date('2026-01-02'), 'weekday'); // 'Jumat'
297
+ * formatDate(new Date('2026-01-02'), 'month'); // 'Januari'
298
+ * ```
299
+ */
300
+ declare function formatDate(date: Date | string | number, style?: DateStyle): string;
301
+ /**
302
+ * Format a date range with Indonesian locale and smart redundancy removal.
303
+ *
304
+ * Removes redundant month/year information when dates share them.
305
+ *
306
+ * @param start - Start date
307
+ * @param end - End date
308
+ * @param style - Formatting style (default: 'long')
309
+ * @returns Formatted date range string
310
+ * @throws {InvalidDateError} If either date is invalid
311
+ * @throws {InvalidDateRangeError} If end date is before start date
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * // Same day
316
+ * formatDateRange(
317
+ * new Date('2026-01-02'),
318
+ * new Date('2026-01-02')
319
+ * ); // '2 Januari 2026'
320
+ *
321
+ * // Same month & year
322
+ * formatDateRange(
323
+ * new Date('2026-01-02'),
324
+ * new Date('2026-01-05')
325
+ * ); // '2 - 5 Januari 2026'
326
+ *
327
+ * // Same year
328
+ * formatDateRange(
329
+ * new Date('2026-01-30'),
330
+ * new Date('2026-02-02')
331
+ * ); // '30 Januari - 2 Februari 2026'
332
+ *
333
+ * // Different year
334
+ * formatDateRange(
335
+ * new Date('2025-12-30'),
336
+ * new Date('2026-01-02')
337
+ * ); // '30 Desember 2025 - 2 Januari 2026'
338
+ * ```
339
+ */
340
+ declare function formatDateRange(start: Date, end: Date, style?: Exclude<DateStyle, 'weekday' | 'month'>): string;
341
+
342
+ /**
343
+ * Relative time formatting for Indonesian locale
344
+ *
345
+ * @module datetime/relative
346
+ * @packageDocumentation
347
+ */
348
+ /**
349
+ * Format a date as relative time in Indonesian.
350
+ *
351
+ * Returns human-readable relative time like "Baru saja", "X menit yang lalu",
352
+ * "Kemarin", or falls back to formatted date for older dates.
353
+ *
354
+ * @param date - Date to format (Date, string, or number timestamp in milliseconds)
355
+ * @param baseDate - Reference date for comparison (default: current date)
356
+ * @returns Relative time string in Indonesian
357
+ * @throws {InvalidDateError} If either date is invalid
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * // Assuming today is 2026-01-02 12:00:00
362
+ * toRelativeTime(new Date('2026-01-02 11:59:00')); // 'Baru saja'
363
+ * toRelativeTime(new Date('2026-01-02 11:00:00')); // '1 jam yang lalu'
364
+ * toRelativeTime(new Date('2026-01-01 12:00:00')); // 'Kemarin'
365
+ * toRelativeTime(new Date('2025-12-30 12:00:00')); // '3 hari yang lalu'
366
+ * toRelativeTime(new Date('2025-12-01 12:00:00')); // '1 Desember 2025'
367
+ * ```
368
+ */
369
+ declare function toRelativeTime(date: Date | string | number, baseDate?: Date): string;
370
+
371
+ /**
372
+ * Timezone utilities for Indonesian locale
373
+ *
374
+ * @module datetime/timezone
375
+ * @packageDocumentation
376
+ */
377
+ /**
378
+ * Map IANA timezone names or UTC offsets to Indonesian abbreviations (WIB/WITA/WIT).
379
+ *
380
+ * Supported mappings:
381
+ * - UTC+7 / Asia/Jakarta / Asia/Pontianak → "WIB"
382
+ * - UTC+8 / Asia/Makassar / Asia/Denpasar → "WITA"
383
+ * - UTC+9 / Asia/Jayapura → "WIT"
384
+ *
385
+ * @param input - IANA timezone name (case-sensitive), offset in hours, or offset string
386
+ * @returns Indonesian timezone abbreviation or null if not Indonesian
387
+ *
388
+ * @example
389
+ * ```typescript
390
+ * // IANA timezone names
391
+ * getIndonesianTimezone('Asia/Jakarta'); // 'WIB'
392
+ * getIndonesianTimezone('Asia/Makassar'); // 'WITA'
393
+ * getIndonesianTimezone('Asia/Jayapura'); // 'WIT'
394
+ *
395
+ * // Offset as number (hours)
396
+ * getIndonesianTimezone(7); // 'WIB'
397
+ * getIndonesianTimezone(8); // 'WITA'
398
+ * getIndonesianTimezone(9); // 'WIT'
399
+ *
400
+ * // Offset as string
401
+ * getIndonesianTimezone('+07:00'); // 'WIB'
402
+ * getIndonesianTimezone('+0700'); // 'WIB'
403
+ * getIndonesianTimezone('+08:00'); // 'WITA'
404
+ *
405
+ * // Non-Indonesian returns null
406
+ * getIndonesianTimezone('America/New_York'); // null
407
+ * getIndonesianTimezone(-5); // null
408
+ * ```
409
+ */
410
+ declare function getIndonesianTimezone(input: string | number): 'WIB' | 'WITA' | 'WIT' | null;
411
+
412
+ export { type AgeOptions, type AgeResult, DAY_NAMES, DAY_NAMES_SHORT, type DateStyle, InvalidDateError, InvalidDateRangeError, MONTH_NAMES, MONTH_NAMES_SHORT, TIMEZONE_MAP, VALID_UTC_OFFSETS, daysInMonth, formatDate, formatDateRange, getAge, getIndonesianTimezone, isLeapYear, isValidDate, isWeekend, isWorkingDay, parseDate, toRelativeTime };