@indodev/toolkit 0.3.4 → 0.4.1
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 +56 -164
- 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 +504 -49
- 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 +486 -50
- package/dist/index.js.map +1 -1
- package/dist/parse-BDfy3aQw.d.cts +542 -0
- package/dist/parse-BDfy3aQw.d.ts +542 -0
- package/dist/phone/index.cjs +82 -49
- package/dist/phone/index.cjs.map +1 -1
- package/dist/phone/index.d.cts +38 -485
- package/dist/phone/index.d.ts +38 -485
- package/dist/phone/index.js +80 -50
- package/dist/phone/index.js.map +1 -1
- package/package.json +36 -19
- package/LICENCE +0 -21
package/dist/index.cjs
CHANGED
|
@@ -717,7 +717,7 @@ function isMobileNumber(phone) {
|
|
|
717
717
|
let normalized;
|
|
718
718
|
if (cleaned.startsWith("+62")) {
|
|
719
719
|
normalized = "0" + cleaned.substring(3);
|
|
720
|
-
} else if (cleaned.startsWith("62")) {
|
|
720
|
+
} else if (cleaned.startsWith("62") && !cleaned.startsWith("620")) {
|
|
721
721
|
normalized = "0" + cleaned.substring(2);
|
|
722
722
|
} else {
|
|
723
723
|
normalized = cleaned;
|
|
@@ -731,19 +731,70 @@ function isLandlineNumber(phone) {
|
|
|
731
731
|
return !isMobileNumber(phone);
|
|
732
732
|
}
|
|
733
733
|
|
|
734
|
+
// src/phone/utils.ts
|
|
735
|
+
function normalizePhoneNumber(phone) {
|
|
736
|
+
if (!phone || typeof phone !== "string") {
|
|
737
|
+
return "";
|
|
738
|
+
}
|
|
739
|
+
if (phone.startsWith("+62")) {
|
|
740
|
+
return "0" + phone.substring(3);
|
|
741
|
+
}
|
|
742
|
+
if (phone.startsWith("62") && !phone.startsWith("620")) {
|
|
743
|
+
return "0" + phone.substring(2);
|
|
744
|
+
}
|
|
745
|
+
if (phone.startsWith("0")) {
|
|
746
|
+
return phone;
|
|
747
|
+
}
|
|
748
|
+
return "";
|
|
749
|
+
}
|
|
750
|
+
function normalizeToNational(phone) {
|
|
751
|
+
if (phone.startsWith("+62")) {
|
|
752
|
+
return "0" + phone.substring(3);
|
|
753
|
+
}
|
|
754
|
+
if (phone.startsWith("62") && !phone.startsWith("620")) {
|
|
755
|
+
return "0" + phone.substring(2);
|
|
756
|
+
}
|
|
757
|
+
if (phone.startsWith("0")) {
|
|
758
|
+
return phone;
|
|
759
|
+
}
|
|
760
|
+
return "";
|
|
761
|
+
}
|
|
762
|
+
function getLandlineRegion(phone) {
|
|
763
|
+
if (!phone || typeof phone !== "string") {
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
const cleaned = phone.replace(/[^\d+]/g, "");
|
|
767
|
+
const normalized = normalizeToNational(cleaned);
|
|
768
|
+
if (!normalized || !normalized.startsWith("0")) {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
if (normalized.startsWith("08")) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
const areaCode4 = normalized.substring(0, 4);
|
|
775
|
+
if (AREA_CODES[areaCode4]) {
|
|
776
|
+
return AREA_CODES[areaCode4];
|
|
777
|
+
}
|
|
778
|
+
const areaCode3 = normalized.substring(0, 3);
|
|
779
|
+
if (AREA_CODES[areaCode3]) {
|
|
780
|
+
return AREA_CODES[areaCode3];
|
|
781
|
+
}
|
|
782
|
+
const areaCode2 = normalized.substring(0, 2);
|
|
783
|
+
if (AREA_CODES[areaCode2]) {
|
|
784
|
+
return AREA_CODES[areaCode2];
|
|
785
|
+
}
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
|
|
734
789
|
// src/phone/format.ts
|
|
735
790
|
function formatPhoneNumber(phone, format = "national") {
|
|
736
791
|
if (!validatePhoneNumber(phone)) {
|
|
737
792
|
return phone;
|
|
738
793
|
}
|
|
739
794
|
const cleaned = cleanPhoneNumber(phone);
|
|
740
|
-
|
|
741
|
-
if (
|
|
742
|
-
|
|
743
|
-
} else if (cleaned.startsWith("62") && !cleaned.startsWith("620")) {
|
|
744
|
-
normalized = "0" + cleaned.substring(2);
|
|
745
|
-
} else {
|
|
746
|
-
normalized = cleaned;
|
|
795
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
796
|
+
if (!normalized) {
|
|
797
|
+
return phone;
|
|
747
798
|
}
|
|
748
799
|
switch (format) {
|
|
749
800
|
case "international":
|
|
@@ -762,7 +813,7 @@ function toInternational(phone) {
|
|
|
762
813
|
if (!cleaned) {
|
|
763
814
|
return phone;
|
|
764
815
|
}
|
|
765
|
-
const normalized =
|
|
816
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
766
817
|
if (!normalized) {
|
|
767
818
|
return phone;
|
|
768
819
|
}
|
|
@@ -788,7 +839,7 @@ function toNational(phone) {
|
|
|
788
839
|
if (!cleaned) {
|
|
789
840
|
return phone;
|
|
790
841
|
}
|
|
791
|
-
const normalized =
|
|
842
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
792
843
|
if (!normalized) {
|
|
793
844
|
return phone;
|
|
794
845
|
}
|
|
@@ -813,7 +864,7 @@ function toE164(phone) {
|
|
|
813
864
|
if (!cleaned) {
|
|
814
865
|
return phone;
|
|
815
866
|
}
|
|
816
|
-
const normalized =
|
|
867
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
817
868
|
if (!normalized) {
|
|
818
869
|
return phone;
|
|
819
870
|
}
|
|
@@ -825,16 +876,6 @@ function cleanPhoneNumber(phone) {
|
|
|
825
876
|
}
|
|
826
877
|
return phone.replace(/[^\d+]/g, "");
|
|
827
878
|
}
|
|
828
|
-
function normalizeToNational(phone) {
|
|
829
|
-
if (phone.startsWith("+62")) {
|
|
830
|
-
return "0" + phone.substring(3);
|
|
831
|
-
} else if (phone.startsWith("62") && !phone.startsWith("620")) {
|
|
832
|
-
return "0" + phone.substring(2);
|
|
833
|
-
} else if (phone.startsWith("0")) {
|
|
834
|
-
return phone;
|
|
835
|
-
}
|
|
836
|
-
return "";
|
|
837
|
-
}
|
|
838
879
|
function getAreaCodeLength(normalized) {
|
|
839
880
|
const fourDigitCode = normalized.substring(0, 5);
|
|
840
881
|
if (AREA_CODES[fourDigitCode]) {
|
|
@@ -860,7 +901,7 @@ function maskPhoneNumber(phone, options = {}) {
|
|
|
860
901
|
if (isInternational) {
|
|
861
902
|
toMask = cleaned;
|
|
862
903
|
} else {
|
|
863
|
-
const normalized =
|
|
904
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
864
905
|
toMask = normalized || cleaned;
|
|
865
906
|
}
|
|
866
907
|
if (toMask.length < 4) {
|
|
@@ -929,7 +970,7 @@ function parsePhoneNumber(phone) {
|
|
|
929
970
|
return null;
|
|
930
971
|
}
|
|
931
972
|
const cleaned = cleanPhoneNumber(phone);
|
|
932
|
-
const normalized =
|
|
973
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
933
974
|
if (!normalized) {
|
|
934
975
|
return null;
|
|
935
976
|
}
|
|
@@ -942,7 +983,7 @@ function parsePhoneNumber(phone) {
|
|
|
942
983
|
if (isMobile) {
|
|
943
984
|
operator = getOperator(normalized);
|
|
944
985
|
} else {
|
|
945
|
-
region =
|
|
986
|
+
region = getLandlineRegion(normalized);
|
|
946
987
|
}
|
|
947
988
|
return {
|
|
948
989
|
countryCode,
|
|
@@ -964,7 +1005,7 @@ function getOperator(phone) {
|
|
|
964
1005
|
return null;
|
|
965
1006
|
}
|
|
966
1007
|
const cleaned = cleanPhoneNumber(phone);
|
|
967
|
-
const normalized =
|
|
1008
|
+
const normalized = normalizePhoneNumber(cleaned);
|
|
968
1009
|
if (!normalized || normalized.length < 4) {
|
|
969
1010
|
return null;
|
|
970
1011
|
}
|
|
@@ -978,30 +1019,6 @@ function isProvider(phone, providerName) {
|
|
|
978
1019
|
}
|
|
979
1020
|
return operator.toLowerCase() === providerName.toLowerCase();
|
|
980
1021
|
}
|
|
981
|
-
function getRegion(phone) {
|
|
982
|
-
if (!phone.startsWith("0")) {
|
|
983
|
-
return null;
|
|
984
|
-
}
|
|
985
|
-
const areaCode4 = phone.substring(0, 4);
|
|
986
|
-
if (AREA_CODES[areaCode4]) {
|
|
987
|
-
return AREA_CODES[areaCode4];
|
|
988
|
-
}
|
|
989
|
-
const areaCode3 = phone.substring(0, 3);
|
|
990
|
-
if (AREA_CODES[areaCode3]) {
|
|
991
|
-
return AREA_CODES[areaCode3];
|
|
992
|
-
}
|
|
993
|
-
return null;
|
|
994
|
-
}
|
|
995
|
-
function normalizeToNational2(phone) {
|
|
996
|
-
if (phone.startsWith("+62")) {
|
|
997
|
-
return "0" + phone.substring(3);
|
|
998
|
-
} else if (phone.startsWith("62")) {
|
|
999
|
-
return "0" + phone.substring(2);
|
|
1000
|
-
} else if (phone.startsWith("0")) {
|
|
1001
|
-
return phone;
|
|
1002
|
-
}
|
|
1003
|
-
return "";
|
|
1004
|
-
}
|
|
1005
1022
|
|
|
1006
1023
|
// src/npwp/validate.ts
|
|
1007
1024
|
function validateNPWP(npwp) {
|
|
@@ -3322,17 +3339,447 @@ function similarity(str1, str2) {
|
|
|
3322
3339
|
return 1 - distance / maxLength;
|
|
3323
3340
|
}
|
|
3324
3341
|
|
|
3342
|
+
// src/datetime/types.ts
|
|
3343
|
+
var InvalidDateError = class extends Error {
|
|
3344
|
+
constructor(message = "Invalid date provided") {
|
|
3345
|
+
super(message);
|
|
3346
|
+
/** Error code for programmatic identification */
|
|
3347
|
+
this.code = "INVALID_DATE";
|
|
3348
|
+
this.name = "InvalidDateError";
|
|
3349
|
+
}
|
|
3350
|
+
};
|
|
3351
|
+
var InvalidDateRangeError = class extends Error {
|
|
3352
|
+
constructor(message = "End date must be after start date") {
|
|
3353
|
+
super(message);
|
|
3354
|
+
/** Error code for programmatic identification */
|
|
3355
|
+
this.code = "INVALID_DATE_RANGE";
|
|
3356
|
+
this.name = "InvalidDateRangeError";
|
|
3357
|
+
}
|
|
3358
|
+
};
|
|
3359
|
+
|
|
3360
|
+
// src/datetime/constants.ts
|
|
3361
|
+
var MONTH_NAMES = [
|
|
3362
|
+
"",
|
|
3363
|
+
// Placeholder for 0-index
|
|
3364
|
+
"Januari",
|
|
3365
|
+
"Februari",
|
|
3366
|
+
"Maret",
|
|
3367
|
+
"April",
|
|
3368
|
+
"Mei",
|
|
3369
|
+
"Juni",
|
|
3370
|
+
"Juli",
|
|
3371
|
+
"Agustus",
|
|
3372
|
+
"September",
|
|
3373
|
+
"Oktober",
|
|
3374
|
+
"November",
|
|
3375
|
+
"Desember"
|
|
3376
|
+
];
|
|
3377
|
+
var MONTH_NAMES_SHORT = [
|
|
3378
|
+
"",
|
|
3379
|
+
// Placeholder for 0-index
|
|
3380
|
+
"Jan",
|
|
3381
|
+
"Feb",
|
|
3382
|
+
"Mar",
|
|
3383
|
+
"Apr",
|
|
3384
|
+
"Mei",
|
|
3385
|
+
"Jun",
|
|
3386
|
+
"Jul",
|
|
3387
|
+
"Agu",
|
|
3388
|
+
"Sep",
|
|
3389
|
+
"Okt",
|
|
3390
|
+
"Nov",
|
|
3391
|
+
"Des"
|
|
3392
|
+
];
|
|
3393
|
+
var DAY_NAMES = [
|
|
3394
|
+
"Minggu",
|
|
3395
|
+
"Senin",
|
|
3396
|
+
"Selasa",
|
|
3397
|
+
"Rabu",
|
|
3398
|
+
"Kamis",
|
|
3399
|
+
"Jumat",
|
|
3400
|
+
"Sabtu"
|
|
3401
|
+
];
|
|
3402
|
+
var DAY_NAMES_SHORT = [
|
|
3403
|
+
"Min",
|
|
3404
|
+
"Sen",
|
|
3405
|
+
"Sel",
|
|
3406
|
+
"Rab",
|
|
3407
|
+
"Kam",
|
|
3408
|
+
"Jum",
|
|
3409
|
+
"Sab"
|
|
3410
|
+
];
|
|
3411
|
+
var TIMEZONE_MAP = {
|
|
3412
|
+
// UTC+7 - WIB
|
|
3413
|
+
"Asia/Jakarta": "WIB",
|
|
3414
|
+
"Asia/Pontianak": "WIB",
|
|
3415
|
+
// UTC+8 - WITA
|
|
3416
|
+
"Asia/Makassar": "WITA",
|
|
3417
|
+
"Asia/Denpasar": "WITA",
|
|
3418
|
+
"Asia/Manado": "WITA",
|
|
3419
|
+
"Asia/Palu": "WITA",
|
|
3420
|
+
// UTC+9 - WIT
|
|
3421
|
+
"Asia/Jayapura": "WIT"
|
|
3422
|
+
};
|
|
3423
|
+
var VALID_UTC_OFFSETS = [7, 8, 9];
|
|
3424
|
+
|
|
3425
|
+
// src/datetime/calc.ts
|
|
3426
|
+
function isLeapYear(year) {
|
|
3427
|
+
if (!Number.isFinite(year) || !Number.isInteger(year)) {
|
|
3428
|
+
return false;
|
|
3429
|
+
}
|
|
3430
|
+
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
3431
|
+
}
|
|
3432
|
+
function daysInMonth(month, year) {
|
|
3433
|
+
if (!Number.isFinite(month) || !Number.isInteger(month) || !Number.isFinite(year) || !Number.isInteger(year) || month < 1 || month > 12) {
|
|
3434
|
+
return 0;
|
|
3435
|
+
}
|
|
3436
|
+
if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {
|
|
3437
|
+
return 31;
|
|
3438
|
+
}
|
|
3439
|
+
if ([4, 6, 9, 11].includes(month)) {
|
|
3440
|
+
return 30;
|
|
3441
|
+
}
|
|
3442
|
+
return isLeapYear(year) ? 29 : 28;
|
|
3443
|
+
}
|
|
3444
|
+
function isValidDate(date) {
|
|
3445
|
+
return date instanceof Date && !Number.isNaN(date.getTime());
|
|
3446
|
+
}
|
|
3447
|
+
function isWeekend(date) {
|
|
3448
|
+
const day = date.getDay();
|
|
3449
|
+
return day === 0 || day === 6;
|
|
3450
|
+
}
|
|
3451
|
+
function isWorkingDay(date) {
|
|
3452
|
+
const day = date.getDay();
|
|
3453
|
+
return day >= 1 && day <= 5;
|
|
3454
|
+
}
|
|
3455
|
+
function normalizeDate(date) {
|
|
3456
|
+
let result;
|
|
3457
|
+
if (date instanceof Date) {
|
|
3458
|
+
result = date;
|
|
3459
|
+
} else if (typeof date === "number") {
|
|
3460
|
+
result = new Date(date);
|
|
3461
|
+
} else if (typeof date === "string") {
|
|
3462
|
+
result = new Date(date);
|
|
3463
|
+
} else {
|
|
3464
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3465
|
+
}
|
|
3466
|
+
if (Number.isNaN(result.getTime())) {
|
|
3467
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3468
|
+
}
|
|
3469
|
+
return result;
|
|
3470
|
+
}
|
|
3471
|
+
function getAge2(birthDate, options = {}) {
|
|
3472
|
+
const birth = normalizeDate(birthDate);
|
|
3473
|
+
const from = options.fromDate ? normalizeDate(options.fromDate) : /* @__PURE__ */ new Date();
|
|
3474
|
+
if (birth.getTime() > from.getTime()) {
|
|
3475
|
+
throw new InvalidDateError(
|
|
3476
|
+
"Birth date cannot be in the future relative to fromDate"
|
|
3477
|
+
);
|
|
3478
|
+
}
|
|
3479
|
+
let years = from.getFullYear() - birth.getFullYear();
|
|
3480
|
+
let months = from.getMonth() - birth.getMonth();
|
|
3481
|
+
let days = from.getDate() - birth.getDate();
|
|
3482
|
+
if (days < 0) {
|
|
3483
|
+
months--;
|
|
3484
|
+
const prevMonth = from.getMonth() === 0 ? 11 : from.getMonth() - 1;
|
|
3485
|
+
const prevMonthYear = from.getMonth() === 0 ? from.getFullYear() - 1 : from.getFullYear();
|
|
3486
|
+
days += daysInMonth(prevMonth + 1, prevMonthYear);
|
|
3487
|
+
}
|
|
3488
|
+
if (months < 0) {
|
|
3489
|
+
years--;
|
|
3490
|
+
months += 12;
|
|
3491
|
+
}
|
|
3492
|
+
const result = { years, months, days };
|
|
3493
|
+
if (options.asString) {
|
|
3494
|
+
return formatAgeString(result);
|
|
3495
|
+
}
|
|
3496
|
+
return result;
|
|
3497
|
+
}
|
|
3498
|
+
function formatAgeString(age) {
|
|
3499
|
+
const parts = [];
|
|
3500
|
+
if (age.years > 0) {
|
|
3501
|
+
parts.push(`${age.years} Tahun`);
|
|
3502
|
+
}
|
|
3503
|
+
if (age.months > 0) {
|
|
3504
|
+
parts.push(`${age.months} Bulan`);
|
|
3505
|
+
}
|
|
3506
|
+
if (age.days > 0) {
|
|
3507
|
+
parts.push(`${age.days} Hari`);
|
|
3508
|
+
}
|
|
3509
|
+
if (parts.length === 0) {
|
|
3510
|
+
return "0 Hari";
|
|
3511
|
+
}
|
|
3512
|
+
return parts.join(" ");
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
// src/datetime/parse.ts
|
|
3516
|
+
function parseDate(dateStr) {
|
|
3517
|
+
const trimmed = dateStr.trim();
|
|
3518
|
+
if (!trimmed) {
|
|
3519
|
+
return null;
|
|
3520
|
+
}
|
|
3521
|
+
if (trimmed.includes(" ") || trimmed.includes(":")) {
|
|
3522
|
+
return null;
|
|
3523
|
+
}
|
|
3524
|
+
const parts = trimmed.split(/[-/.]/);
|
|
3525
|
+
if (parts.length !== 3) {
|
|
3526
|
+
return null;
|
|
3527
|
+
}
|
|
3528
|
+
const nums = parts.map((p) => parseInt(p, 10));
|
|
3529
|
+
if (nums.some((n) => Number.isNaN(n) || n < 0)) {
|
|
3530
|
+
return null;
|
|
3531
|
+
}
|
|
3532
|
+
const [first, second, third] = nums;
|
|
3533
|
+
let day;
|
|
3534
|
+
let month;
|
|
3535
|
+
let year;
|
|
3536
|
+
if (first > 999 && first > 31) {
|
|
3537
|
+
year = first;
|
|
3538
|
+
month = second;
|
|
3539
|
+
day = third;
|
|
3540
|
+
} else {
|
|
3541
|
+
if (third < 1e3) {
|
|
3542
|
+
return null;
|
|
3543
|
+
}
|
|
3544
|
+
day = first;
|
|
3545
|
+
month = second;
|
|
3546
|
+
year = third;
|
|
3547
|
+
}
|
|
3548
|
+
if (month < 1 || month > 12) {
|
|
3549
|
+
return null;
|
|
3550
|
+
}
|
|
3551
|
+
if (year < 1e3 || year > 9999) {
|
|
3552
|
+
return null;
|
|
3553
|
+
}
|
|
3554
|
+
const maxDays = daysInMonth(month, year);
|
|
3555
|
+
if (maxDays === 0 || day < 1 || day > maxDays) {
|
|
3556
|
+
return null;
|
|
3557
|
+
}
|
|
3558
|
+
const date = new Date(year, month - 1, day);
|
|
3559
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
3560
|
+
return null;
|
|
3561
|
+
}
|
|
3562
|
+
return date;
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
// src/datetime/format.ts
|
|
3566
|
+
function normalizeDate2(date) {
|
|
3567
|
+
let result;
|
|
3568
|
+
if (date instanceof Date) {
|
|
3569
|
+
result = date;
|
|
3570
|
+
} else if (typeof date === "number") {
|
|
3571
|
+
result = new Date(date);
|
|
3572
|
+
} else if (typeof date === "string") {
|
|
3573
|
+
result = new Date(date);
|
|
3574
|
+
} else {
|
|
3575
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3576
|
+
}
|
|
3577
|
+
if (Number.isNaN(result.getTime())) {
|
|
3578
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3579
|
+
}
|
|
3580
|
+
return result;
|
|
3581
|
+
}
|
|
3582
|
+
function formatDate(date, style = "long") {
|
|
3583
|
+
const d = normalizeDate2(date);
|
|
3584
|
+
const day = d.getDate();
|
|
3585
|
+
const month = d.getMonth() + 1;
|
|
3586
|
+
const year = d.getFullYear();
|
|
3587
|
+
const dayOfWeek = d.getDay();
|
|
3588
|
+
switch (style) {
|
|
3589
|
+
case "full":
|
|
3590
|
+
return `${DAY_NAMES[dayOfWeek]}, ${day} ${MONTH_NAMES[month]} ${year}`;
|
|
3591
|
+
case "long":
|
|
3592
|
+
return `${day} ${MONTH_NAMES[month]} ${year}`;
|
|
3593
|
+
case "medium":
|
|
3594
|
+
return `${day} ${MONTH_NAMES_SHORT[month]} ${year}`;
|
|
3595
|
+
case "short": {
|
|
3596
|
+
const dd = String(day).padStart(2, "0");
|
|
3597
|
+
const mm = String(month).padStart(2, "0");
|
|
3598
|
+
return `${dd}/${mm}/${year}`;
|
|
3599
|
+
}
|
|
3600
|
+
case "weekday":
|
|
3601
|
+
return DAY_NAMES[dayOfWeek];
|
|
3602
|
+
case "month":
|
|
3603
|
+
return MONTH_NAMES[month];
|
|
3604
|
+
default:
|
|
3605
|
+
throw new InvalidDateError(`Unknown format style: ${style}`);
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
function formatDateRange(start, end, style = "long") {
|
|
3609
|
+
const s = normalizeDate2(start);
|
|
3610
|
+
const e = normalizeDate2(end);
|
|
3611
|
+
if (e.getTime() < s.getTime()) {
|
|
3612
|
+
throw new InvalidDateRangeError();
|
|
3613
|
+
}
|
|
3614
|
+
if (style === "short") {
|
|
3615
|
+
return `${formatDate(s, "short")} - ${formatDate(e, "short")}`;
|
|
3616
|
+
}
|
|
3617
|
+
if (style === "full") {
|
|
3618
|
+
return `${formatDate(s, "full")} - ${formatDate(e, "full")}`;
|
|
3619
|
+
}
|
|
3620
|
+
const sDay = s.getDate();
|
|
3621
|
+
const eDay = e.getDate();
|
|
3622
|
+
const sMonth = s.getMonth() + 1;
|
|
3623
|
+
const eMonth = e.getMonth() + 1;
|
|
3624
|
+
const sYear = s.getFullYear();
|
|
3625
|
+
const eYear = e.getFullYear();
|
|
3626
|
+
if (sDay === eDay && sMonth === eMonth && sYear === eYear) {
|
|
3627
|
+
return formatDate(s, style);
|
|
3628
|
+
}
|
|
3629
|
+
if (sYear !== eYear) {
|
|
3630
|
+
return `${formatDate(s, style)} - ${formatDate(e, style)}`;
|
|
3631
|
+
}
|
|
3632
|
+
if (sMonth !== eMonth) {
|
|
3633
|
+
if (style === "long") {
|
|
3634
|
+
return `${sDay} ${MONTH_NAMES[sMonth]} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;
|
|
3635
|
+
}
|
|
3636
|
+
return `${sDay} ${MONTH_NAMES_SHORT[sMonth]} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;
|
|
3637
|
+
}
|
|
3638
|
+
if (style === "long") {
|
|
3639
|
+
return `${sDay} - ${eDay} ${MONTH_NAMES[eMonth]} ${eYear}`;
|
|
3640
|
+
}
|
|
3641
|
+
return `${sDay} - ${eDay} ${MONTH_NAMES_SHORT[eMonth]} ${eYear}`;
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
// src/datetime/relative.ts
|
|
3645
|
+
function normalizeDate3(date) {
|
|
3646
|
+
let result;
|
|
3647
|
+
if (date instanceof Date) {
|
|
3648
|
+
result = date;
|
|
3649
|
+
} else if (typeof date === "number") {
|
|
3650
|
+
result = new Date(date);
|
|
3651
|
+
} else if (typeof date === "string") {
|
|
3652
|
+
result = new Date(date);
|
|
3653
|
+
} else {
|
|
3654
|
+
throw new InvalidDateError("Date must be a Date, string, or number");
|
|
3655
|
+
}
|
|
3656
|
+
if (Number.isNaN(result.getTime())) {
|
|
3657
|
+
throw new InvalidDateError(`Unable to parse date: ${String(date)}`);
|
|
3658
|
+
}
|
|
3659
|
+
return result;
|
|
3660
|
+
}
|
|
3661
|
+
function toRelativeTime(date, baseDate = /* @__PURE__ */ new Date()) {
|
|
3662
|
+
const d = normalizeDate3(date);
|
|
3663
|
+
const base = normalizeDate3(baseDate);
|
|
3664
|
+
const diffMs = d.getTime() - base.getTime();
|
|
3665
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
3666
|
+
const diffMin = Math.floor(diffMs / (1e3 * 60));
|
|
3667
|
+
const diffHour = Math.floor(diffMs / (1e3 * 60 * 60));
|
|
3668
|
+
const diffDay = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
3669
|
+
if (diffMs === 0) {
|
|
3670
|
+
return "Sekarang";
|
|
3671
|
+
}
|
|
3672
|
+
if (diffMs > 0) {
|
|
3673
|
+
if (diffSec < 60) {
|
|
3674
|
+
return "Baru saja";
|
|
3675
|
+
}
|
|
3676
|
+
if (diffMin < 60) {
|
|
3677
|
+
return `${diffMin} menit lagi`;
|
|
3678
|
+
}
|
|
3679
|
+
if (diffHour < 24) {
|
|
3680
|
+
return `${diffHour} jam lagi`;
|
|
3681
|
+
}
|
|
3682
|
+
if (diffHour < 48) {
|
|
3683
|
+
return "Besok";
|
|
3684
|
+
}
|
|
3685
|
+
if (diffDay <= 30) {
|
|
3686
|
+
return `${diffDay} hari lagi`;
|
|
3687
|
+
}
|
|
3688
|
+
return formatDate(d, "long");
|
|
3689
|
+
}
|
|
3690
|
+
const absDiffSec = Math.abs(diffSec);
|
|
3691
|
+
const absDiffMin = Math.abs(diffMin);
|
|
3692
|
+
const absDiffHour = Math.abs(diffHour);
|
|
3693
|
+
const absDiffDay = Math.abs(diffDay);
|
|
3694
|
+
if (absDiffSec < 60) {
|
|
3695
|
+
return "Baru saja";
|
|
3696
|
+
}
|
|
3697
|
+
if (absDiffMin < 60) {
|
|
3698
|
+
return `${absDiffMin} menit yang lalu`;
|
|
3699
|
+
}
|
|
3700
|
+
if (absDiffHour < 24) {
|
|
3701
|
+
return `${absDiffHour} jam yang lalu`;
|
|
3702
|
+
}
|
|
3703
|
+
if (absDiffHour < 48) {
|
|
3704
|
+
return "Kemarin";
|
|
3705
|
+
}
|
|
3706
|
+
if (absDiffDay <= 30) {
|
|
3707
|
+
return `${absDiffDay} hari yang lalu`;
|
|
3708
|
+
}
|
|
3709
|
+
return formatDate(d, "long");
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
// src/datetime/timezone.ts
|
|
3713
|
+
function getIndonesianTimezone(input) {
|
|
3714
|
+
if (typeof input === "number") {
|
|
3715
|
+
if (!Number.isFinite(input) || !Number.isInteger(input)) {
|
|
3716
|
+
return null;
|
|
3717
|
+
}
|
|
3718
|
+
switch (input) {
|
|
3719
|
+
case 7:
|
|
3720
|
+
return "WIB";
|
|
3721
|
+
case 8:
|
|
3722
|
+
return "WITA";
|
|
3723
|
+
case 9:
|
|
3724
|
+
return "WIT";
|
|
3725
|
+
default:
|
|
3726
|
+
return null;
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
if (typeof input !== "string") {
|
|
3730
|
+
return null;
|
|
3731
|
+
}
|
|
3732
|
+
const trimmed = input.trim();
|
|
3733
|
+
const offsetMatch = trimmed.match(/^([+-])(\d{2}):?(\d{2})$/);
|
|
3734
|
+
if (offsetMatch) {
|
|
3735
|
+
const sign = offsetMatch[1];
|
|
3736
|
+
const hours = parseInt(offsetMatch[2], 10);
|
|
3737
|
+
const minutes = parseInt(offsetMatch[3], 10);
|
|
3738
|
+
if (sign === "-") {
|
|
3739
|
+
return null;
|
|
3740
|
+
}
|
|
3741
|
+
if (minutes !== 0) {
|
|
3742
|
+
return null;
|
|
3743
|
+
}
|
|
3744
|
+
switch (hours) {
|
|
3745
|
+
case 7:
|
|
3746
|
+
return "WIB";
|
|
3747
|
+
case 8:
|
|
3748
|
+
return "WITA";
|
|
3749
|
+
case 9:
|
|
3750
|
+
return "WIT";
|
|
3751
|
+
default:
|
|
3752
|
+
return null;
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
if (TIMEZONE_MAP[trimmed]) {
|
|
3756
|
+
return TIMEZONE_MAP[trimmed];
|
|
3757
|
+
}
|
|
3758
|
+
return null;
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
exports.DAY_NAMES = DAY_NAMES;
|
|
3762
|
+
exports.DAY_NAMES_SHORT = DAY_NAMES_SHORT;
|
|
3763
|
+
exports.InvalidDateError = InvalidDateError;
|
|
3764
|
+
exports.InvalidDateRangeError = InvalidDateRangeError;
|
|
3765
|
+
exports.MONTH_NAMES = MONTH_NAMES;
|
|
3766
|
+
exports.MONTH_NAMES_SHORT = MONTH_NAMES_SHORT;
|
|
3767
|
+
exports.TIMEZONE_MAP = TIMEZONE_MAP;
|
|
3768
|
+
exports.VALID_UTC_OFFSETS = VALID_UTC_OFFSETS;
|
|
3325
3769
|
exports.addRupiahSymbol = addRupiahSymbol;
|
|
3326
3770
|
exports.calculateTax = calculateTax;
|
|
3327
3771
|
exports.capitalize = capitalize2;
|
|
3328
3772
|
exports.cleanPhoneNumber = cleanPhoneNumber;
|
|
3329
3773
|
exports.compareStrings = compareStrings;
|
|
3330
3774
|
exports.contractAbbreviation = contractAbbreviation;
|
|
3775
|
+
exports.daysInMonth = daysInMonth;
|
|
3331
3776
|
exports.expandAbbreviation = expandAbbreviation;
|
|
3332
3777
|
exports.extractWords = extractWords;
|
|
3333
3778
|
exports.formatAccounting = formatAccounting;
|
|
3334
3779
|
exports.formatBirthDate = formatBirthDate;
|
|
3335
3780
|
exports.formatCompact = formatCompact;
|
|
3781
|
+
exports.formatDate = formatDate;
|
|
3782
|
+
exports.formatDateRange = formatDateRange;
|
|
3336
3783
|
exports.formatNIK = formatNIK;
|
|
3337
3784
|
exports.formatNPWP = formatNPWP;
|
|
3338
3785
|
exports.formatPhoneNumber = formatPhoneNumber;
|
|
@@ -3342,21 +3789,28 @@ exports.generateSmsLink = generateSmsLink;
|
|
|
3342
3789
|
exports.generateTelLink = generateTelLink;
|
|
3343
3790
|
exports.generateWALink = generateWALink;
|
|
3344
3791
|
exports.getAge = getAge;
|
|
3792
|
+
exports.getAgeFromDate = getAge2;
|
|
3345
3793
|
exports.getEmailInfo = getEmailInfo;
|
|
3794
|
+
exports.getIndonesianTimezone = getIndonesianTimezone;
|
|
3346
3795
|
exports.getOperator = getOperator;
|
|
3347
3796
|
exports.getRegionFromPlate = getRegionFromPlate;
|
|
3348
3797
|
exports.isAlay = isAlay;
|
|
3349
3798
|
exports.isLandlineNumber = isLandlineNumber;
|
|
3799
|
+
exports.isLeapYear = isLeapYear;
|
|
3350
3800
|
exports.isMobileNumber = isMobileNumber;
|
|
3351
3801
|
exports.isProvider = isProvider;
|
|
3802
|
+
exports.isValidDate = isValidDate;
|
|
3352
3803
|
exports.isValidForBirthDate = isValidForBirthDate;
|
|
3353
3804
|
exports.isValidForGender = isValidForGender;
|
|
3805
|
+
exports.isWeekend = isWeekend;
|
|
3806
|
+
exports.isWorkingDay = isWorkingDay;
|
|
3354
3807
|
exports.maskEmail = maskEmail;
|
|
3355
3808
|
exports.maskNIK = maskNIK;
|
|
3356
3809
|
exports.maskNPWP = maskNPWP;
|
|
3357
3810
|
exports.maskPhoneNumber = maskPhoneNumber;
|
|
3358
3811
|
exports.normalizeEmail = normalizeEmail;
|
|
3359
3812
|
exports.normalizeWhitespace = normalizeWhitespace;
|
|
3813
|
+
exports.parseDate = parseDate;
|
|
3360
3814
|
exports.parseNIK = parseNIK;
|
|
3361
3815
|
exports.parseNPWP = parseNPWP;
|
|
3362
3816
|
exports.parsePhoneNumber = parsePhoneNumber;
|
|
@@ -3372,6 +3826,7 @@ exports.toE164 = toE164;
|
|
|
3372
3826
|
exports.toFormal = toFormal;
|
|
3373
3827
|
exports.toInternational = toInternational;
|
|
3374
3828
|
exports.toNational = toNational;
|
|
3829
|
+
exports.toRelativeTime = toRelativeTime;
|
|
3375
3830
|
exports.toSentenceCase = toSentenceCase;
|
|
3376
3831
|
exports.toTitleCase = toTitleCase;
|
|
3377
3832
|
exports.toWords = toWords;
|