@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.
- package/README.md +46 -170
- package/dist/currency/index.cjs +158 -25
- package/dist/currency/index.cjs.map +1 -1
- package/dist/currency/index.d.cts +50 -354
- package/dist/currency/index.d.ts +50 -354
- package/dist/currency/index.js +154 -26
- package/dist/currency/index.js.map +1 -1
- package/dist/datetime/index.cjs +442 -0
- package/dist/datetime/index.cjs.map +1 -0
- package/dist/datetime/index.d.cts +412 -0
- package/dist/datetime/index.d.ts +412 -0
- package/dist/datetime/index.js +422 -0
- package/dist/datetime/index.js.map +1 -0
- package/dist/index.cjs +503 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +485 -26
- package/dist/index.js.map +1 -1
- package/dist/utils-OG1yMaAa.d.cts +485 -0
- package/dist/utils-OG1yMaAa.d.ts +485 -0
- package/package.json +19 -2
package/dist/index.cjs
CHANGED
|
@@ -1334,7 +1334,7 @@ function formatRupiah(amount, options) {
|
|
|
1334
1334
|
spaceAfterSymbol = true
|
|
1335
1335
|
} = options || {};
|
|
1336
1336
|
const precision = options?.precision !== void 0 ? options.precision : decimal ? 2 : 0;
|
|
1337
|
-
const isNegative = amount < 0;
|
|
1337
|
+
const isNegative = amount < 0 && amount !== 0;
|
|
1338
1338
|
const absAmount = Math.abs(amount);
|
|
1339
1339
|
let result;
|
|
1340
1340
|
if (decimal) {
|
|
@@ -1352,17 +1352,21 @@ function formatRupiah(amount, options) {
|
|
|
1352
1352
|
const intAmount = Math.floor(absAmount);
|
|
1353
1353
|
result = intAmount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator);
|
|
1354
1354
|
}
|
|
1355
|
-
if (isNegative) {
|
|
1356
|
-
result = `-${result}`;
|
|
1357
|
-
}
|
|
1358
1355
|
if (symbol) {
|
|
1359
1356
|
const space = spaceAfterSymbol ? " " : "";
|
|
1360
|
-
|
|
1357
|
+
if (isNegative) {
|
|
1358
|
+
result = `-Rp${space}${result}`;
|
|
1359
|
+
} else {
|
|
1360
|
+
result = `Rp${space}${result}`;
|
|
1361
|
+
}
|
|
1362
|
+
} else if (isNegative) {
|
|
1363
|
+
result = `-${result}`;
|
|
1361
1364
|
}
|
|
1362
1365
|
return result;
|
|
1363
1366
|
}
|
|
1364
|
-
function formatCompact(amount) {
|
|
1365
|
-
const
|
|
1367
|
+
function formatCompact(amount, options) {
|
|
1368
|
+
const { symbol = true, spaceAfterSymbol = true } = options || {};
|
|
1369
|
+
const isNegative = amount < 0 && amount !== 0;
|
|
1366
1370
|
const abs = Math.abs(amount);
|
|
1367
1371
|
let result;
|
|
1368
1372
|
if (abs >= 1e12) {
|
|
@@ -1378,10 +1382,17 @@ function formatCompact(amount) {
|
|
|
1378
1382
|
} else {
|
|
1379
1383
|
result = abs.toString();
|
|
1380
1384
|
}
|
|
1381
|
-
if (
|
|
1385
|
+
if (symbol) {
|
|
1386
|
+
const space = spaceAfterSymbol ? " " : "";
|
|
1387
|
+
if (isNegative) {
|
|
1388
|
+
result = `-Rp${space}${result}`;
|
|
1389
|
+
} else {
|
|
1390
|
+
result = `Rp${space}${result}`;
|
|
1391
|
+
}
|
|
1392
|
+
} else if (isNegative) {
|
|
1382
1393
|
result = `-${result}`;
|
|
1383
1394
|
}
|
|
1384
|
-
return
|
|
1395
|
+
return result;
|
|
1385
1396
|
}
|
|
1386
1397
|
function formatCompactValue(value, unit) {
|
|
1387
1398
|
const rounded = Math.round(value * 10) / 10;
|
|
@@ -1478,20 +1489,42 @@ var TENS = [
|
|
|
1478
1489
|
"sembilan puluh"
|
|
1479
1490
|
];
|
|
1480
1491
|
function toWords(amount, options) {
|
|
1481
|
-
const {
|
|
1492
|
+
const {
|
|
1493
|
+
uppercase = false,
|
|
1494
|
+
withCurrency = true,
|
|
1495
|
+
withDecimals = false
|
|
1496
|
+
} = options || {};
|
|
1482
1497
|
if (amount === 0) {
|
|
1483
1498
|
let result = "nol";
|
|
1484
1499
|
if (withCurrency) result += " rupiah";
|
|
1485
1500
|
return uppercase ? capitalize(result) : result;
|
|
1486
1501
|
}
|
|
1487
1502
|
const isNegative = amount < 0;
|
|
1488
|
-
const absAmount = Math.
|
|
1503
|
+
const absAmount = Math.abs(amount);
|
|
1504
|
+
const intPart = Math.floor(absAmount);
|
|
1505
|
+
let words = convertInteger(intPart);
|
|
1506
|
+
if (isNegative) {
|
|
1507
|
+
words = "minus " + words;
|
|
1508
|
+
}
|
|
1509
|
+
if (withCurrency) {
|
|
1510
|
+
words += " rupiah";
|
|
1511
|
+
}
|
|
1512
|
+
if (withDecimals) {
|
|
1513
|
+
const decimalPart = Math.round((absAmount - intPart) * 100);
|
|
1514
|
+
if (decimalPart > 0) {
|
|
1515
|
+
words += " koma " + convertDecimal(decimalPart);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
return uppercase ? capitalize(words) : words;
|
|
1519
|
+
}
|
|
1520
|
+
function convertInteger(num) {
|
|
1521
|
+
if (num === 0) return "nol";
|
|
1489
1522
|
let words = "";
|
|
1490
|
-
const triliun = Math.floor(
|
|
1491
|
-
const miliar = Math.floor(
|
|
1492
|
-
const juta = Math.floor(
|
|
1493
|
-
const ribu = Math.floor(
|
|
1494
|
-
const sisa =
|
|
1523
|
+
const triliun = Math.floor(num / 1e12);
|
|
1524
|
+
const miliar = Math.floor(num % 1e12 / 1e9);
|
|
1525
|
+
const juta = Math.floor(num % 1e9 / 1e6);
|
|
1526
|
+
const ribu = Math.floor(num % 1e6 / 1e3);
|
|
1527
|
+
const sisa = num % 1e3;
|
|
1495
1528
|
if (triliun > 0) {
|
|
1496
1529
|
words += convertGroup(triliun) + " triliun";
|
|
1497
1530
|
}
|
|
@@ -1511,13 +1544,19 @@ function toWords(amount, options) {
|
|
|
1511
1544
|
if (words) words += " ";
|
|
1512
1545
|
words += convertGroup(sisa);
|
|
1513
1546
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
if (
|
|
1518
|
-
|
|
1547
|
+
return words;
|
|
1548
|
+
}
|
|
1549
|
+
function convertDecimal(num) {
|
|
1550
|
+
if (num === 0) return "";
|
|
1551
|
+
if (num < 10) return BASIC_NUMBERS[num];
|
|
1552
|
+
if (num < 20) return TEENS[num - 10];
|
|
1553
|
+
const tens = Math.floor(num / 10);
|
|
1554
|
+
const ones = num % 10;
|
|
1555
|
+
let result = TENS[tens];
|
|
1556
|
+
if (ones > 0) {
|
|
1557
|
+
result += " " + BASIC_NUMBERS[ones];
|
|
1519
1558
|
}
|
|
1520
|
-
return
|
|
1559
|
+
return result;
|
|
1521
1560
|
}
|
|
1522
1561
|
function convertGroup(num) {
|
|
1523
1562
|
if (num === 0) return "";
|
|
@@ -1567,15 +1606,16 @@ function formatAccounting(amount, options) {
|
|
|
1567
1606
|
}
|
|
1568
1607
|
return formatted;
|
|
1569
1608
|
}
|
|
1570
|
-
function calculateTax(amount, rate
|
|
1609
|
+
function calculateTax(amount, rate) {
|
|
1571
1610
|
return amount * rate;
|
|
1572
1611
|
}
|
|
1573
1612
|
function addRupiahSymbol(amount) {
|
|
1574
1613
|
if (typeof amount === "number") {
|
|
1575
|
-
|
|
1614
|
+
const formatted = amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
1615
|
+
return `Rp ${formatted}`;
|
|
1576
1616
|
}
|
|
1577
1617
|
if (amount.trim().startsWith("Rp")) {
|
|
1578
|
-
return amount;
|
|
1618
|
+
return amount.trim();
|
|
1579
1619
|
}
|
|
1580
1620
|
return `Rp ${amount.trim()}`;
|
|
1581
1621
|
}
|
|
@@ -3282,17 +3322,447 @@ function similarity(str1, str2) {
|
|
|
3282
3322
|
return 1 - distance / maxLength;
|
|
3283
3323
|
}
|
|
3284
3324
|
|
|
3325
|
+
// src/datetime/types.ts
|
|
3326
|
+
var InvalidDateError = class extends Error {
|
|
3327
|
+
constructor(message = "Invalid date provided") {
|
|
3328
|
+
super(message);
|
|
3329
|
+
/** Error code for programmatic identification */
|
|
3330
|
+
this.code = "INVALID_DATE";
|
|
3331
|
+
this.name = "InvalidDateError";
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
var InvalidDateRangeError = class extends Error {
|
|
3335
|
+
constructor(message = "End date must be after start date") {
|
|
3336
|
+
super(message);
|
|
3337
|
+
/** Error code for programmatic identification */
|
|
3338
|
+
this.code = "INVALID_DATE_RANGE";
|
|
3339
|
+
this.name = "InvalidDateRangeError";
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
|
|
3343
|
+
// src/datetime/constants.ts
|
|
3344
|
+
var MONTH_NAMES = [
|
|
3345
|
+
"",
|
|
3346
|
+
// Placeholder for 0-index
|
|
3347
|
+
"Januari",
|
|
3348
|
+
"Februari",
|
|
3349
|
+
"Maret",
|
|
3350
|
+
"April",
|
|
3351
|
+
"Mei",
|
|
3352
|
+
"Juni",
|
|
3353
|
+
"Juli",
|
|
3354
|
+
"Agustus",
|
|
3355
|
+
"September",
|
|
3356
|
+
"Oktober",
|
|
3357
|
+
"November",
|
|
3358
|
+
"Desember"
|
|
3359
|
+
];
|
|
3360
|
+
var MONTH_NAMES_SHORT = [
|
|
3361
|
+
"",
|
|
3362
|
+
// Placeholder for 0-index
|
|
3363
|
+
"Jan",
|
|
3364
|
+
"Feb",
|
|
3365
|
+
"Mar",
|
|
3366
|
+
"Apr",
|
|
3367
|
+
"Mei",
|
|
3368
|
+
"Jun",
|
|
3369
|
+
"Jul",
|
|
3370
|
+
"Agu",
|
|
3371
|
+
"Sep",
|
|
3372
|
+
"Okt",
|
|
3373
|
+
"Nov",
|
|
3374
|
+
"Des"
|
|
3375
|
+
];
|
|
3376
|
+
var DAY_NAMES = [
|
|
3377
|
+
"Minggu",
|
|
3378
|
+
"Senin",
|
|
3379
|
+
"Selasa",
|
|
3380
|
+
"Rabu",
|
|
3381
|
+
"Kamis",
|
|
3382
|
+
"Jumat",
|
|
3383
|
+
"Sabtu"
|
|
3384
|
+
];
|
|
3385
|
+
var DAY_NAMES_SHORT = [
|
|
3386
|
+
"Min",
|
|
3387
|
+
"Sen",
|
|
3388
|
+
"Sel",
|
|
3389
|
+
"Rab",
|
|
3390
|
+
"Kam",
|
|
3391
|
+
"Jum",
|
|
3392
|
+
"Sab"
|
|
3393
|
+
];
|
|
3394
|
+
var TIMEZONE_MAP = {
|
|
3395
|
+
// UTC+7 - WIB
|
|
3396
|
+
"Asia/Jakarta": "WIB",
|
|
3397
|
+
"Asia/Pontianak": "WIB",
|
|
3398
|
+
// UTC+8 - WITA
|
|
3399
|
+
"Asia/Makassar": "WITA",
|
|
3400
|
+
"Asia/Denpasar": "WITA",
|
|
3401
|
+
"Asia/Manado": "WITA",
|
|
3402
|
+
"Asia/Palu": "WITA",
|
|
3403
|
+
// UTC+9 - WIT
|
|
3404
|
+
"Asia/Jayapura": "WIT"
|
|
3405
|
+
};
|
|
3406
|
+
var VALID_UTC_OFFSETS = [7, 8, 9];
|
|
3407
|
+
|
|
3408
|
+
// src/datetime/calc.ts
|
|
3409
|
+
function isLeapYear(year) {
|
|
3410
|
+
if (!Number.isFinite(year) || !Number.isInteger(year)) {
|
|
3411
|
+
return false;
|
|
3412
|
+
}
|
|
3413
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
3414
|
+
}
|
|
3415
|
+
function daysInMonth(month, year) {
|
|
3416
|
+
if (!Number.isFinite(month) || !Number.isInteger(month) || !Number.isFinite(year) || !Number.isInteger(year) || month < 1 || month > 12) {
|
|
3417
|
+
return 0;
|
|
3418
|
+
}
|
|
3419
|
+
if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {
|
|
3420
|
+
return 31;
|
|
3421
|
+
}
|
|
3422
|
+
if ([4, 6, 9, 11].includes(month)) {
|
|
3423
|
+
return 30;
|
|
3424
|
+
}
|
|
3425
|
+
return isLeapYear(year) ? 29 : 28;
|
|
3426
|
+
}
|
|
3427
|
+
function isValidDate(date) {
|
|
3428
|
+
return date instanceof Date && !Number.isNaN(date.getTime());
|
|
3429
|
+
}
|
|
3430
|
+
function isWeekend(date) {
|
|
3431
|
+
const day = date.getDay();
|
|
3432
|
+
return day === 0 || day === 6;
|
|
3433
|
+
}
|
|
3434
|
+
function isWorkingDay(date) {
|
|
3435
|
+
const day = date.getDay();
|
|
3436
|
+
return day >= 1 && day <= 5;
|
|
3437
|
+
}
|
|
3438
|
+
function normalizeDate(date) {
|
|
3439
|
+
let result;
|
|
3440
|
+
if (date instanceof Date) {
|
|
3441
|
+
result = date;
|
|
3442
|
+
} else if (typeof date === "number") {
|
|
3443
|
+
result = new Date(date);
|
|
3444
|
+
} else if (typeof date === "string") {
|
|
3445
|
+
result = new Date(date);
|
|
3446
|
+
} else {
|
|
3447
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3448
|
+
}
|
|
3449
|
+
if (Number.isNaN(result.getTime())) {
|
|
3450
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3451
|
+
}
|
|
3452
|
+
return result;
|
|
3453
|
+
}
|
|
3454
|
+
function getAge2(birthDate, options = {}) {
|
|
3455
|
+
const birth = normalizeDate(birthDate);
|
|
3456
|
+
const from = options.fromDate ? normalizeDate(options.fromDate) : /* @__PURE__ */ new Date();
|
|
3457
|
+
if (birth.getTime() > from.getTime()) {
|
|
3458
|
+
throw new InvalidDateError(
|
|
3459
|
+
"Birth date cannot be in the future relative to fromDate"
|
|
3460
|
+
);
|
|
3461
|
+
}
|
|
3462
|
+
let years = from.getFullYear() - birth.getFullYear();
|
|
3463
|
+
let months = from.getMonth() - birth.getMonth();
|
|
3464
|
+
let days = from.getDate() - birth.getDate();
|
|
3465
|
+
if (days < 0) {
|
|
3466
|
+
months--;
|
|
3467
|
+
const prevMonth = from.getMonth() === 0 ? 11 : from.getMonth() - 1;
|
|
3468
|
+
const prevMonthYear = from.getMonth() === 0 ? from.getFullYear() - 1 : from.getFullYear();
|
|
3469
|
+
days += daysInMonth(prevMonth + 1, prevMonthYear);
|
|
3470
|
+
}
|
|
3471
|
+
if (months < 0) {
|
|
3472
|
+
years--;
|
|
3473
|
+
months += 12;
|
|
3474
|
+
}
|
|
3475
|
+
const result = { years, months, days };
|
|
3476
|
+
if (options.asString) {
|
|
3477
|
+
return formatAgeString(result);
|
|
3478
|
+
}
|
|
3479
|
+
return result;
|
|
3480
|
+
}
|
|
3481
|
+
function formatAgeString(age) {
|
|
3482
|
+
const parts = [];
|
|
3483
|
+
if (age.years > 0) {
|
|
3484
|
+
parts.push(`${age.years} Tahun`);
|
|
3485
|
+
}
|
|
3486
|
+
if (age.months > 0) {
|
|
3487
|
+
parts.push(`${age.months} Bulan`);
|
|
3488
|
+
}
|
|
3489
|
+
if (age.days > 0) {
|
|
3490
|
+
parts.push(`${age.days} Hari`);
|
|
3491
|
+
}
|
|
3492
|
+
if (parts.length === 0) {
|
|
3493
|
+
return "0 Hari";
|
|
3494
|
+
}
|
|
3495
|
+
return parts.join(" ");
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// src/datetime/parse.ts
|
|
3499
|
+
function parseDate(dateStr) {
|
|
3500
|
+
const trimmed = dateStr.trim();
|
|
3501
|
+
if (!trimmed) {
|
|
3502
|
+
return null;
|
|
3503
|
+
}
|
|
3504
|
+
if (trimmed.includes(" ") || trimmed.includes(":")) {
|
|
3505
|
+
return null;
|
|
3506
|
+
}
|
|
3507
|
+
const parts = trimmed.split(/[-/.]/);
|
|
3508
|
+
if (parts.length !== 3) {
|
|
3509
|
+
return null;
|
|
3510
|
+
}
|
|
3511
|
+
const nums = parts.map((p) => parseInt(p, 10));
|
|
3512
|
+
if (nums.some((n) => Number.isNaN(n) || n < 0)) {
|
|
3513
|
+
return null;
|
|
3514
|
+
}
|
|
3515
|
+
const [first, second, third] = nums;
|
|
3516
|
+
let day;
|
|
3517
|
+
let month;
|
|
3518
|
+
let year;
|
|
3519
|
+
if (first > 999 && first > 31) {
|
|
3520
|
+
year = first;
|
|
3521
|
+
month = second;
|
|
3522
|
+
day = third;
|
|
3523
|
+
} else {
|
|
3524
|
+
if (third < 1e3) {
|
|
3525
|
+
return null;
|
|
3526
|
+
}
|
|
3527
|
+
day = first;
|
|
3528
|
+
month = second;
|
|
3529
|
+
year = third;
|
|
3530
|
+
}
|
|
3531
|
+
if (month < 1 || month > 12) {
|
|
3532
|
+
return null;
|
|
3533
|
+
}
|
|
3534
|
+
if (year < 1e3 || year > 9999) {
|
|
3535
|
+
return null;
|
|
3536
|
+
}
|
|
3537
|
+
const maxDays = daysInMonth(month, year);
|
|
3538
|
+
if (maxDays === 0 || day < 1 || day > maxDays) {
|
|
3539
|
+
return null;
|
|
3540
|
+
}
|
|
3541
|
+
const date = new Date(year, month - 1, day);
|
|
3542
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
3543
|
+
return null;
|
|
3544
|
+
}
|
|
3545
|
+
return date;
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
// src/datetime/format.ts
|
|
3549
|
+
function normalizeDate2(date) {
|
|
3550
|
+
let result;
|
|
3551
|
+
if (date instanceof Date) {
|
|
3552
|
+
result = date;
|
|
3553
|
+
} else if (typeof date === "number") {
|
|
3554
|
+
result = new Date(date);
|
|
3555
|
+
} else if (typeof date === "string") {
|
|
3556
|
+
result = new Date(date);
|
|
3557
|
+
} else {
|
|
3558
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3559
|
+
}
|
|
3560
|
+
if (Number.isNaN(result.getTime())) {
|
|
3561
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3562
|
+
}
|
|
3563
|
+
return result;
|
|
3564
|
+
}
|
|
3565
|
+
function formatDate(date, style = "long") {
|
|
3566
|
+
const d = normalizeDate2(date);
|
|
3567
|
+
const day = d.getDate();
|
|
3568
|
+
const month = d.getMonth() + 1;
|
|
3569
|
+
const year = d.getFullYear();
|
|
3570
|
+
const dayOfWeek = d.getDay();
|
|
3571
|
+
switch (style) {
|
|
3572
|
+
case "full":
|
|
3573
|
+
return `${DAY_NAMES[dayOfWeek]}, ${day} ${MONTH_NAMES[month]} ${year}`;
|
|
3574
|
+
case "long":
|
|
3575
|
+
return `${day} ${MONTH_NAMES[month]} ${year}`;
|
|
3576
|
+
case "medium":
|
|
3577
|
+
return `${day} ${MONTH_NAMES_SHORT[month]} ${year}`;
|
|
3578
|
+
case "short": {
|
|
3579
|
+
const dd = String(day).padStart(2, "0");
|
|
3580
|
+
const mm = String(month).padStart(2, "0");
|
|
3581
|
+
return `${dd}/${mm}/${year}`;
|
|
3582
|
+
}
|
|
3583
|
+
case "weekday":
|
|
3584
|
+
return DAY_NAMES[dayOfWeek];
|
|
3585
|
+
case "month":
|
|
3586
|
+
return MONTH_NAMES[month];
|
|
3587
|
+
default:
|
|
3588
|
+
throw new InvalidDateError(`Unknown format style: ${style}`);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
function formatDateRange(start, end, style = "long") {
|
|
3592
|
+
const s = normalizeDate2(start);
|
|
3593
|
+
const e = normalizeDate2(end);
|
|
3594
|
+
if (e.getTime() < s.getTime()) {
|
|
3595
|
+
throw new InvalidDateRangeError();
|
|
3596
|
+
}
|
|
3597
|
+
if (style === "short") {
|
|
3598
|
+
return `${formatDate(s, "short")} - ${formatDate(e, "short")}`;
|
|
3599
|
+
}
|
|
3600
|
+
if (style === "full") {
|
|
3601
|
+
return `${formatDate(s, "full")} - ${formatDate(e, "full")}`;
|
|
3602
|
+
}
|
|
3603
|
+
const sDay = s.getDate();
|
|
3604
|
+
const eDay = e.getDate();
|
|
3605
|
+
const sMonth = s.getMonth() + 1;
|
|
3606
|
+
const eMonth = e.getMonth() + 1;
|
|
3607
|
+
const sYear = s.getFullYear();
|
|
3608
|
+
const eYear = e.getFullYear();
|
|
3609
|
+
if (sDay === eDay && sMonth === eMonth && sYear === eYear) {
|
|
3610
|
+
return formatDate(s, style);
|
|
3611
|
+
}
|
|
3612
|
+
if (sYear !== eYear) {
|
|
3613
|
+
return `${formatDate(s, style)} - ${formatDate(e, style)}`;
|
|
3614
|
+
}
|
|
3615
|
+
if (sMonth !== eMonth) {
|
|
3616
|
+
if (style === "long") {
|
|
3617
|
+
return `${sDay} ${MONTH_NAMES[sMonth]} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;
|
|
3618
|
+
}
|
|
3619
|
+
return `${sDay} ${MONTH_NAMES_SHORT[sMonth]} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;
|
|
3620
|
+
}
|
|
3621
|
+
if (style === "long") {
|
|
3622
|
+
return `${sDay} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;
|
|
3623
|
+
}
|
|
3624
|
+
return `${sDay} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
// src/datetime/relative.ts
|
|
3628
|
+
function normalizeDate3(date) {
|
|
3629
|
+
let result;
|
|
3630
|
+
if (date instanceof Date) {
|
|
3631
|
+
result = date;
|
|
3632
|
+
} else if (typeof date === "number") {
|
|
3633
|
+
result = new Date(date);
|
|
3634
|
+
} else if (typeof date === "string") {
|
|
3635
|
+
result = new Date(date);
|
|
3636
|
+
} else {
|
|
3637
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3638
|
+
}
|
|
3639
|
+
if (Number.isNaN(result.getTime())) {
|
|
3640
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3641
|
+
}
|
|
3642
|
+
return result;
|
|
3643
|
+
}
|
|
3644
|
+
function toRelativeTime(date, baseDate = /* @__PURE__ */ new Date()) {
|
|
3645
|
+
const d = normalizeDate3(date);
|
|
3646
|
+
const base = normalizeDate3(baseDate);
|
|
3647
|
+
const diffMs = d.getTime() - base.getTime();
|
|
3648
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
3649
|
+
const diffMin = Math.floor(diffMs / (1e3 * 60));
|
|
3650
|
+
const diffHour = Math.floor(diffMs / (1e3 * 60 * 60));
|
|
3651
|
+
const diffDay = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
3652
|
+
if (diffMs === 0) {
|
|
3653
|
+
return "Sekarang";
|
|
3654
|
+
}
|
|
3655
|
+
if (diffMs > 0) {
|
|
3656
|
+
if (diffSec < 60) {
|
|
3657
|
+
return "Baru saja";
|
|
3658
|
+
}
|
|
3659
|
+
if (diffMin < 60) {
|
|
3660
|
+
return `${diffMin} menit lagi`;
|
|
3661
|
+
}
|
|
3662
|
+
if (diffHour < 24) {
|
|
3663
|
+
return `${diffHour} jam lagi`;
|
|
3664
|
+
}
|
|
3665
|
+
if (diffHour < 48) {
|
|
3666
|
+
return "Besok";
|
|
3667
|
+
}
|
|
3668
|
+
if (diffDay <= 30) {
|
|
3669
|
+
return `${diffDay} hari lagi`;
|
|
3670
|
+
}
|
|
3671
|
+
return formatDate(d, "long");
|
|
3672
|
+
}
|
|
3673
|
+
const absDiffSec = Math.abs(diffSec);
|
|
3674
|
+
const absDiffMin = Math.abs(diffMin);
|
|
3675
|
+
const absDiffHour = Math.abs(diffHour);
|
|
3676
|
+
const absDiffDay = Math.abs(diffDay);
|
|
3677
|
+
if (absDiffSec < 60) {
|
|
3678
|
+
return "Baru saja";
|
|
3679
|
+
}
|
|
3680
|
+
if (absDiffMin < 60) {
|
|
3681
|
+
return `${absDiffMin} menit yang lalu`;
|
|
3682
|
+
}
|
|
3683
|
+
if (absDiffHour < 24) {
|
|
3684
|
+
return `${absDiffHour} jam yang lalu`;
|
|
3685
|
+
}
|
|
3686
|
+
if (absDiffHour < 48) {
|
|
3687
|
+
return "Kemarin";
|
|
3688
|
+
}
|
|
3689
|
+
if (absDiffDay <= 30) {
|
|
3690
|
+
return `${absDiffDay} hari yang lalu`;
|
|
3691
|
+
}
|
|
3692
|
+
return formatDate(d, "long");
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
// src/datetime/timezone.ts
|
|
3696
|
+
function getIndonesianTimezone(input) {
|
|
3697
|
+
if (typeof input === "number") {
|
|
3698
|
+
if (!Number.isFinite(input) || !Number.isInteger(input)) {
|
|
3699
|
+
return null;
|
|
3700
|
+
}
|
|
3701
|
+
switch (input) {
|
|
3702
|
+
case 7:
|
|
3703
|
+
return "WIB";
|
|
3704
|
+
case 8:
|
|
3705
|
+
return "WITA";
|
|
3706
|
+
case 9:
|
|
3707
|
+
return "WIT";
|
|
3708
|
+
default:
|
|
3709
|
+
return null;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
if (typeof input !== "string") {
|
|
3713
|
+
return null;
|
|
3714
|
+
}
|
|
3715
|
+
const trimmed = input.trim();
|
|
3716
|
+
const offsetMatch = trimmed.match(/^([+-])(\d{2}):?(\d{2})$/);
|
|
3717
|
+
if (offsetMatch) {
|
|
3718
|
+
const sign = offsetMatch[1];
|
|
3719
|
+
const hours = parseInt(offsetMatch[2], 10);
|
|
3720
|
+
const minutes = parseInt(offsetMatch[3], 10);
|
|
3721
|
+
if (sign === "-") {
|
|
3722
|
+
return null;
|
|
3723
|
+
}
|
|
3724
|
+
if (minutes !== 0) {
|
|
3725
|
+
return null;
|
|
3726
|
+
}
|
|
3727
|
+
switch (hours) {
|
|
3728
|
+
case 7:
|
|
3729
|
+
return "WIB";
|
|
3730
|
+
case 8:
|
|
3731
|
+
return "WITA";
|
|
3732
|
+
case 9:
|
|
3733
|
+
return "WIT";
|
|
3734
|
+
default:
|
|
3735
|
+
return null;
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
if (TIMEZONE_MAP[trimmed]) {
|
|
3739
|
+
return TIMEZONE_MAP[trimmed];
|
|
3740
|
+
}
|
|
3741
|
+
return null;
|
|
3742
|
+
}
|
|
3743
|
+
|
|
3744
|
+
exports.DAY_NAMES = DAY_NAMES;
|
|
3745
|
+
exports.DAY_NAMES_SHORT = DAY_NAMES_SHORT;
|
|
3746
|
+
exports.InvalidDateError = InvalidDateError;
|
|
3747
|
+
exports.InvalidDateRangeError = InvalidDateRangeError;
|
|
3748
|
+
exports.MONTH_NAMES = MONTH_NAMES;
|
|
3749
|
+
exports.MONTH_NAMES_SHORT = MONTH_NAMES_SHORT;
|
|
3750
|
+
exports.TIMEZONE_MAP = TIMEZONE_MAP;
|
|
3751
|
+
exports.VALID_UTC_OFFSETS = VALID_UTC_OFFSETS;
|
|
3285
3752
|
exports.addRupiahSymbol = addRupiahSymbol;
|
|
3286
3753
|
exports.calculateTax = calculateTax;
|
|
3287
3754
|
exports.capitalize = capitalize2;
|
|
3288
3755
|
exports.cleanPhoneNumber = cleanPhoneNumber;
|
|
3289
3756
|
exports.compareStrings = compareStrings;
|
|
3290
3757
|
exports.contractAbbreviation = contractAbbreviation;
|
|
3758
|
+
exports.daysInMonth = daysInMonth;
|
|
3291
3759
|
exports.expandAbbreviation = expandAbbreviation;
|
|
3292
3760
|
exports.extractWords = extractWords;
|
|
3293
3761
|
exports.formatAccounting = formatAccounting;
|
|
3294
3762
|
exports.formatBirthDate = formatBirthDate;
|
|
3295
3763
|
exports.formatCompact = formatCompact;
|
|
3764
|
+
exports.formatDate = formatDate;
|
|
3765
|
+
exports.formatDateRange = formatDateRange;
|
|
3296
3766
|
exports.formatNIK = formatNIK;
|
|
3297
3767
|
exports.formatNPWP = formatNPWP;
|
|
3298
3768
|
exports.formatPhoneNumber = formatPhoneNumber;
|
|
@@ -3302,21 +3772,28 @@ exports.generateSmsLink = generateSmsLink;
|
|
|
3302
3772
|
exports.generateTelLink = generateTelLink;
|
|
3303
3773
|
exports.generateWALink = generateWALink;
|
|
3304
3774
|
exports.getAge = getAge;
|
|
3775
|
+
exports.getAgeFromDate = getAge2;
|
|
3305
3776
|
exports.getEmailInfo = getEmailInfo;
|
|
3777
|
+
exports.getIndonesianTimezone = getIndonesianTimezone;
|
|
3306
3778
|
exports.getOperator = getOperator;
|
|
3307
3779
|
exports.getRegionFromPlate = getRegionFromPlate;
|
|
3308
3780
|
exports.isAlay = isAlay;
|
|
3309
3781
|
exports.isLandlineNumber = isLandlineNumber;
|
|
3782
|
+
exports.isLeapYear = isLeapYear;
|
|
3310
3783
|
exports.isMobileNumber = isMobileNumber;
|
|
3311
3784
|
exports.isProvider = isProvider;
|
|
3785
|
+
exports.isValidDate = isValidDate;
|
|
3312
3786
|
exports.isValidForBirthDate = isValidForBirthDate;
|
|
3313
3787
|
exports.isValidForGender = isValidForGender;
|
|
3788
|
+
exports.isWeekend = isWeekend;
|
|
3789
|
+
exports.isWorkingDay = isWorkingDay;
|
|
3314
3790
|
exports.maskEmail = maskEmail;
|
|
3315
3791
|
exports.maskNIK = maskNIK;
|
|
3316
3792
|
exports.maskNPWP = maskNPWP;
|
|
3317
3793
|
exports.maskPhoneNumber = maskPhoneNumber;
|
|
3318
3794
|
exports.normalizeEmail = normalizeEmail;
|
|
3319
3795
|
exports.normalizeWhitespace = normalizeWhitespace;
|
|
3796
|
+
exports.parseDate = parseDate;
|
|
3320
3797
|
exports.parseNIK = parseNIK;
|
|
3321
3798
|
exports.parseNPWP = parseNPWP;
|
|
3322
3799
|
exports.parsePhoneNumber = parsePhoneNumber;
|
|
@@ -3332,6 +3809,7 @@ exports.toE164 = toE164;
|
|
|
3332
3809
|
exports.toFormal = toFormal;
|
|
3333
3810
|
exports.toInternational = toInternational;
|
|
3334
3811
|
exports.toNational = toNational;
|
|
3812
|
+
exports.toRelativeTime = toRelativeTime;
|
|
3335
3813
|
exports.toSentenceCase = toSentenceCase;
|
|
3336
3814
|
exports.toTitleCase = toTitleCase;
|
|
3337
3815
|
exports.toWords = toWords;
|