rynn-k / gists
nik-parser.js javascript
const axios = require('axios');

async function nikparser(nik) {
    try {
        const provincesRes = await axios.get('https://emsifa.github.io/api-wilayah-indonesia/api/provinces.json');
        const provinces = Object.fromEntries(provincesRes.data.map(p => [p.id, p.name.toUpperCase()]));
        
        nik = nik.toString();
        if (nik.length !== 16 || !provinces[nik.slice(0, 2)]) throw new Error('NIK tidak valid: panjang atau kode provinsi salah.');
        
        const provinceId = nik.slice(0, 2);
        const regenciesRes = await axios.get(`https://emsifa.github.io/api-wilayah-indonesia/api/regencies/${provinceId}.json`);
        const regencies = Object.fromEntries(regenciesRes.data.map(r => [r.id, r.name.toUpperCase()]));
        
        if (!regencies[nik.slice(0, 4)]) throw new Error('NIK tidak valid: kode kabupaten/kota salah.');
        
        const regencyId = nik.slice(0, 4);
        const districtsRes = await axios.get(`https://emsifa.github.io/api-wilayah-indonesia/api/districts/${regencyId}.json`);
        const districts = Object.fromEntries(districtsRes.data.map(d => [d.id.slice(0, -1), `${d.name.toUpperCase()}`]));
        
        if (!districts[nik.slice(0, 6)]) throw new Error('NIK tidak valid: kode kecamatan salah.');
        
        const province = provinces[provinceId];
        const city = regencies[regencyId];
        const subdistrict = districts[nik.slice(0, 6)];
        const day = parseInt(nik.slice(6, 8));
        const month = parseInt(nik.slice(8, 10));
        const yearCode = nik.slice(10, 12);
        const uniqCode = nik.slice(12, 16);
        
        const gender = day > 40 ? 'PEREMPUAN' : 'LAKI-LAKI';
        const birthDay = day > 40 ? (day - 40).toString().padStart(2, '0') : day.toString().padStart(2, '0');
        const birthYear = yearCode < new Date().getFullYear().toString().slice(-2) ? `20${yearCode}` : `19${yearCode}`;
        const birthDate = `${birthDay}/${month.toString().padStart(2, '0')}/${birthYear}`;
        const birth = new Date(birthYear, month - 1, birthDay);
        
        if (isNaN(birth.getTime())) throw new Error('Tanggal lahir tidak valid.');
        
        const today = new Date();
        let years = today.getFullYear() - birth.getFullYear();
        let months = today.getMonth() - birth.getMonth();
        let remainingDays = today.getDate() - birth.getDate();
        if (remainingDays < 0) {
            remainingDays += new Date(today.getFullYear(), today.getMonth(), 0).getDate();
            months--;
        }
        if (months < 0) {
            months += 12;
            years--;
        }
        const age = `${years} Tahun ${months} Bulan ${remainingDays} Hari`;
        
        let ageCategory = '';
        if (years < 12) ageCategory = 'Anak-anak';
        else if (years < 18) ageCategory = 'Remaja';
        else if (years < 60) ageCategory = 'Dewasa';
        else ageCategory = 'Lansia';
        
        const nextBirthday = new Date(today.getMonth() < month - 1 ? today.getFullYear() : today.getFullYear() + 1, month - 1, birthDay);
        const timeDiff = nextBirthday - today;
        const monthsLeft = Math.floor(timeDiff / (1000 * 60 * 60 * 24 * 30));
        const daysLeft = Math.floor((timeDiff % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24));
        const birthdayCountdown = `${monthsLeft} Bulan ${daysLeft} Hari`;
        
        const baseDate = new Date(1970, 0, 2);
        const diffDays = Math.floor((birth - baseDate + 86400000) / (1000 * 60 * 60 * 24));
        const pasaranIndex = Math.round((diffDays % 5) * 2) / 2;
        const pasaranNames = ['Wage', 'Kliwon', 'Legi', 'Pahing', 'Pon'];
        const dayNames = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu'];
        const monthNames = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'];
        const birthDateFull = `${birthDay} ${monthNames[month - 1]} ${birthYear}`;
        const pasaran = `${dayNames[birth.getDay()]} ${pasaranNames[pasaranIndex] || ''}, ${birthDay} ${monthNames[month - 1]} ${birthYear}`;
        
        let zodiac = '';
        if ((month === 1 && day >= 20) || (month === 2 && day < 19)) zodiac = 'Aquarius';
        else if ((month === 2 && day >= 19) || (month === 3 && day < 21)) zodiac = 'Pisces';
        else if ((month === 3 && day >= 21) || (month === 4 && day < 20)) zodiac = 'Aries';
        else if ((month === 4 && day >= 20) || (month === 5 && day < 21)) zodiac = 'Taurus';
        else if ((month === 5 && day >= 21) || (month === 6 && day < 22)) zodiac = 'Gemini';
        else if ((month === 6 && day >= 21) || (month === 7 && day < 23)) zodiac = 'Cancer';
        else if ((month === 7 && day >= 23) || (month === 8 && day < 23)) zodiac = 'Leo';
        else if ((month === 8 && day >= 23) || (month === 9 && day < 23)) zodiac = 'Virgo';
        else if ((month === 9 && day >= 23) || (month === 10 && day < 24)) zodiac = 'Libra';
        else if ((month === 10 && day >= 24) || (month === 11 && day < 23)) zodiac = 'Scorpio';
        else if ((month === 11 && day >= 23) || (month === 12 && day < 22)) zodiac = 'Sagitarius';
        else if ((month === 12 && day >= 22) || (month === 1 && day < 20)) zodiac = 'Capricorn';
        
        const regencyType = city.includes('KOTA') ? 'Kota' : 'Kabupaten';
        const areaCode = `${provinceId}.${regencyId.slice(2)}.${nik.slice(4, 6)}`;
        
        return {
            nik,
            kelamin: gender,
            lahir: birthDate,
            lahir_lengkap: birthDateFull,
            provinsi: {
                kode: provinceId,
                nama: province
            },
            kotakab: {
                kode: regencyId,
                nama: city,
                jenis: regencyType
            },
            kecamatan: {
                kode: nik.slice(0, 6),
                nama: subdistrict
            },
            kode_wilayah: areaCode,
            nomor_urut: uniqCode,
            tambahan: {
                pasaran,
                usia: age,
                kategori_usia: ageCategory,
                ultah: `${birthdayCountdown} Lagi`,
                zodiak: zodiac
            }
        };
    } catch (error) {
        throw new Error(error.message);
    }
}

// Usage:
nikparser('XXXXXXXXXXXXXXXX').then(console.log);
6386 bytes ยท Updated Mar 6, 2026