diff --git a/src/__tests__/getDate.test.ts b/src/__tests__/getDate.test.ts index c7161f5..ca53f08 100644 --- a/src/__tests__/getDate.test.ts +++ b/src/__tests__/getDate.test.ts @@ -36,4 +36,27 @@ describe('getDate', () => { ); }); }); + + const december162022 = new Date('2023-12-16'); + describe(`Date: ${december162022}`, () => { + it(`(BD) should return 'শনিবার, ১ পৌষ, ১৪৩০'`, () => { + expect(getDate(december162022)).toEqual('শনিবার, ১ পৌষ, ১৪৩০'); + }); + it(`(IN) should return 'শনিবার, ২৯ অগ্রহায়ণ, ১৪৩০'`, () => { + expect(getDate(december162022, { calculationMethod: 'IN' })).toEqual( + 'শনিবার, ২৯ অগ্রহায়ণ, ১৪৩০' + ); + }); + }); + const june192023 = new Date('2023-06-19'); + describe(`Date: ${june192023}`, () => { + it(`(BD) should return 'সোমবার, ৫ আষাঢ়, ১৪৩০'`, () => { + expect(getDate(june192023)).toEqual('সোমবার, ৫ আষাঢ়, ১৪৩০'); + }); + it(`(IN) should return 'সোমবার, ৩ আষাঢ়, ১৪৩০'`, () => { + expect(getDate(june192023, { calculationMethod: 'IN' })).toEqual( + 'সোমবার, ৩ আষাঢ়, ১৪৩০' + ); + }); + }); }); diff --git a/src/__tests__/getDay.test.ts b/src/__tests__/getDay.test.ts index 81497ad..4216092 100644 --- a/src/__tests__/getDay.test.ts +++ b/src/__tests__/getDay.test.ts @@ -179,7 +179,8 @@ describe('getDay', () => { expect(getDay(august17, { calculationMethod: 'IN' })).toBe('৩১'); }); }); - const august18 = new Date('August 18 2022 06:22:03'); + + const august18 = new Date('2022-08-18'); describe(`Date: ${august18}`, () => { it(`(BD) should convert to '৩'`, () => { expect(getDay(august18)).toBe('৩'); diff --git a/src/__tests__/getMonth.test.ts b/src/__tests__/getMonth.test.ts index 69fd3c9..18dee41 100644 --- a/src/__tests__/getMonth.test.ts +++ b/src/__tests__/getMonth.test.ts @@ -1,17 +1,5 @@ import { getMonth } from '../getMonth'; -// const may14 = new Date('May 14 2021 06:22:03'); -// const may15 = new Date('May 15 2021 06:22:03'); -// const may16 = new Date('May 16 2021 06:22:03'); - -// const june14 = new Date('June 14 2021 06:22:03'); -// const june15 = new Date('June 15 2021 06:22:03'); -// const june16 = new Date('June 16 2021 06:22:03'); - -// const july15 = new Date('July 15 2021 06:22:03'); -// const july16 = new Date('July 16 2021 06:22:03'); -// const july18 = new Date('July 18 2021 06:22:03'); - describe('getMonth', () => { const april13 = new Date('April 13 2021 06:22:03'); describe(`Date: ${april13}`, () => { @@ -49,109 +37,23 @@ describe('getMonth', () => { const invalidDate = new Date('sdfasf'); describe(`Date: ${invalidDate}`, () => { it(`(BD) should convert to 'Invalid Date'`, () => { - expect(getMonth(invalidDate)).toBe('Invalid Date'); + let error: Error | undefined; + try { + getMonth(invalidDate); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); }); it(`(IN) should convert to 'Invalid Date'`, () => { - expect(getMonth(invalidDate, { calculationMethod: 'IN' })).toBe( - 'Invalid Date' - ); + let error: Error | undefined; + try { + getMonth(invalidDate, { calculationMethod: 'IN' }); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); }); }); }); - -// test(`converts ${may14} to 'বৈশাখ'`, () => { -// expect(getMonth(may14)).toBe('বৈশাখ'); -// }); - -// test(`converts ${may14} to 'বৈশাখ'`, () => { -// expect(getMonth(may14, { calculationMethod: 'IN' })).toBe('বৈশাখ'); -// }); - -// test(`converts ${may15} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may15)).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${may15} to 'বৈশাখ'`, () => { -// expect(getMonth(may15, { calculationMethod: 'IN' })).toBe('বৈশাখ'); -// }); - -// test(`converts ${may16} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may16)).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${may16} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may16, { calculationMethod: 'IN' })).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${may14} to 'বৈশাখ'`, () => { -// expect(getMonth(may14)).toBe('বৈশাখ'); -// }); - -// test(`converts ${may14} to 'বৈশাখ'`, () => { -// expect(getMonth(may14, { calculationMethod: 'IN' })).toBe('বৈশাখ'); -// }); - -// test(`converts ${may15} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may15)).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${may15} to 'বৈশাখ'`, () => { -// expect(getMonth(may15, { calculationMethod: 'IN' })).toBe('বৈশাখ'); -// }); - -// test(`converts ${may16} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may16)).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${may16} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(may16, { calculationMethod: 'IN' })).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${june14} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(june14)).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${june14} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(june14, { calculationMethod: 'IN' })).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${june15} to 'আষাঢ়'`, () => { -// expect(getMonth(june15)).toBe('আষাঢ়'); -// }); - -// test(`converts ${june15} to 'জ্যৈষ্ঠ'`, () => { -// expect(getMonth(june15, { calculationMethod: 'IN' })).toBe('জ্যৈষ্ঠ'); -// }); - -// test(`converts ${june16} to 'আষাঢ়'`, () => { -// expect(getMonth(june16)).toBe('আষাঢ়'); -// }); - -// test(`converts ${june16} to 'আষাঢ়'`, () => { -// expect(getMonth(june16, { calculationMethod: 'IN' })).toBe('আষাঢ়'); -// }); - -// test(`converts ${july15} to 'আষাঢ়'`, () => { -// expect(getMonth(july15)).toBe('আষাঢ়'); -// }); - -// test(`converts ${july15} to 'আষাঢ়'`, () => { -// expect(getMonth(july15, { calculationMethod: 'IN' })).toBe('আষাঢ়'); -// }); - -// test(`converts ${july16} to 'শ্রাবণ'`, () => { -// expect(getMonth(july16)).toBe('শ্রাবণ'); -// }); - -// test(`converts ${july16} to 'আষাঢ়'`, () => { -// expect(getMonth(july16, { calculationMethod: 'IN' })).toBe('আষাঢ়'); -// }); - -// test(`converts ${july18} to 'শ্রাবণ'`, () => { -// expect(getMonth(july18)).toBe('শ্রাবণ'); -// }); - -// test(`converts ${july18} to 'শ্রাবণ'`, () => { -// expect(getMonth(july18, { calculationMethod: 'IN' })).toBe('শ্রাবণ'); -// }); diff --git a/src/__tests__/getYear.test.ts b/src/__tests__/getYear.test.ts index 5f195dc..d1b53c0 100644 --- a/src/__tests__/getYear.test.ts +++ b/src/__tests__/getYear.test.ts @@ -48,13 +48,49 @@ describe('getYear', () => { const invalidDate = new Date('xyzdate'); describe(`Date: ${invalidDate}`, () => { it(`(BD) should convert to 'Invalid Date'`, () => { - expect(getYear(invalidDate, { format: 'YY' })).toBe('Invalid Date'); + let error: Error | undefined; + try { + getYear(invalidDate, { format: 'YY' }); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); }); it(`(IN) should convert to 'Invalid Date'`, () => { - expect( - getYear(invalidDate, { format: 'YY', calculationMethod: 'IN' }) - ).toBe('Invalid Date'); + let error: Error | undefined; + try { + getYear(invalidDate, { format: 'YY', calculationMethod: 'IN' }); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); + }); + }); + + const beforeBanglaDate = new Date('593-04-13'); + describe(`Date: ${beforeBanglaDate}`, () => { + it(`(BD) should convert to 'Invalid Date'`, () => { + let error: Error | undefined; + try { + getYear(beforeBanglaDate, { format: 'YY' }); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); + }); + + it(`(IN) should convert to 'Invalid Date'`, () => { + let error: Error | undefined; + try { + getYear(beforeBanglaDate, { + format: 'YY', + calculationMethod: 'IN', + }); + } catch (err) { + error = err; + } + expect(error).toEqual(new Error('Invalid Date')); }); }); }); diff --git a/src/getDate.ts b/src/getDate.ts index db674cf..80e3767 100644 --- a/src/getDate.ts +++ b/src/getDate.ts @@ -12,9 +12,14 @@ export function getDate( calculationMethod: 'BD', } ) { - if (!isValidDate(date)) return errorMessage; + if (!isValidDate(date)) { + throw new Error(errorMessage); + } const inputDate = new Date(date); + inputDate.setTime( + inputDate.getTime() + (inputDate.getTimezoneOffset() + 360) * 60 * 1000 + ); const { format = 'eeee, D MMMM, YYYY', calculationMethod = 'BD' } = options; let formattedDate = format.replace(/eeee|eee/gi, (fmt) => { diff --git a/src/getDay.ts b/src/getDay.ts index 555ae80..c01529f 100644 --- a/src/getDay.ts +++ b/src/getDay.ts @@ -1,5 +1,14 @@ import { DayOptions } from './types'; -import { errorMessage, formatDay, isLeapYear, isValidDate } from './utils'; +import { + errorMessage, + formatDay, + getJulianDate, + isLeapYear, + isValidDate, + monthLengthIN, + startJulianDate, + yearLength, +} from './utils'; function getDayBD(day: number, month: number, year: number): number { let banglaDay: number; @@ -49,56 +58,26 @@ function getDayBD(day: number, month: number, year: number): number { } function getDayIN(day: number, month: number, year: number): number { + const julianDate = getJulianDate(year, month + 1, day); + + if (julianDate < startJulianDate) { + throw new Error(errorMessage); + } + + const banglaYear = Math.floor((julianDate - startJulianDate) / yearLength); + const calculatedJulianDate = startJulianDate + banglaYear * yearLength; + let ps: number; + let ns: number; let banglaDay: number; - switch (month) { - case 0: - banglaDay = day < 16 ? day + 15 : day - 15; - break; - case 1: - banglaDay = day < 14 ? day + 16 : day - 13; - break; - case 2: - if (isLeapYear(year)) { - banglaDay = day < 15 ? day + 16 : day - 14; - } else { - banglaDay = day < 16 ? day + 15 : day - 15; - } - break; - case 3: - if (isLeapYear(year)) { - banglaDay = day < 14 ? day + 17 : day - 13; - } else { - banglaDay = day < 15 ? day + 16 : day - 14; - } - break; - case 4: - banglaDay = day < 16 ? day + 16 : day - 15; - break; - case 5: - banglaDay = day < 16 ? day + 16 : day - 15; - break; - case 6: - banglaDay = day < 18 ? day + 15 : day - 17; - break; - case 7: - banglaDay = day < 18 ? day + 14 : day - 17; - break; - case 8: - banglaDay = day < 18 ? day + 14 : day - 17; - break; - case 9: - banglaDay = day < 19 ? day + 13 : day - 18; - break; - case 10: - banglaDay = day < 18 ? day + 13 : day - 17; - break; - case 11: - banglaDay = day < 17 ? day + 13 : day - 16; - break; - default: - banglaDay = day < 15 ? day + 16 : day - 14; - break; + for (let i = 0; i < 12; i += 1) { + ps = calculatedJulianDate + monthLengthIN[i]; + ns = calculatedJulianDate + monthLengthIN[i + 1]; + + if (julianDate >= ps && julianDate <= Math.floor(ns) + 1.75) { + banglaDay = Math.floor(julianDate - ps) + 1; + } } + return banglaDay; } @@ -106,14 +85,20 @@ export function getDay( date: Date = new Date(), options: DayOptions = { format: 'D', calculationMethod: 'BD' } ): string { - if (!isValidDate(date)) return errorMessage; + if (!isValidDate(date)) { + throw new Error(errorMessage); + } const inputDate = new Date(date); + inputDate.setTime( + inputDate.getTime() + (inputDate.getTimezoneOffset() + 360) * 60 * 1000 + ); const day = inputDate.getUTCDate(); const month = inputDate.getMonth(); const year = inputDate.getFullYear(); const { format, calculationMethod = 'BD' } = options; + const banglaDay = calculationMethod === 'BD' ? getDayBD(day, month, year) diff --git a/src/getMonth.ts b/src/getMonth.ts index 2fc3113..f1a7cc1 100644 --- a/src/getMonth.ts +++ b/src/getMonth.ts @@ -1,5 +1,37 @@ import { MonthOptions } from './types'; -import { errorMessage, formatMonth, isValidDate } from './utils'; +import { + errorMessage, + formatMonth, + getJulianDate, + isValidDate, + monthLengthIN, + startJulianDate, + yearLength, +} from './utils'; + +const getMonthIN = (year: number, month: number, day: number) => { + const julianDate = getJulianDate(year, month + 1, day); + + if (julianDate < startJulianDate) { + throw new Error(errorMessage); + } + + const banglaYear = Math.floor((julianDate - startJulianDate) / yearLength); + const calculatedJulianDate = startJulianDate + banglaYear * yearLength; + let ps: number; + let ns: number; + let banglaMonth: number; + for (let i = 0; i < 12; i += 1) { + ps = calculatedJulianDate + monthLengthIN[i]; + ns = calculatedJulianDate + monthLengthIN[i + 1]; + + if (julianDate >= ps && julianDate <= Math.floor(ns) + 1.75) { + banglaMonth = i + 1; + } + } + + return banglaMonth - 1; +}; function getMonthBD(day: number, month: number): number { let result: number; @@ -46,66 +78,24 @@ function getMonthBD(day: number, month: number): number { return result; } -function getMonthIN(day: number, month: number): number { - let result: number; - - switch (true) { - case (month === 4 && day > 15) || (month === 5 && day < 16): - result = 1; - break; - case (month === 5 && day > 15) || (month === 6 && day < 18): - result = 2; - break; - case (month === 6 && day > 17) || (month === 7 && day < 18): - result = 3; - break; - case (month === 7 && day > 17) || (month === 8 && day < 18): - result = 4; - break; - case (month === 8 && day > 17) || (month === 9 && day < 19): - result = 5; - break; - case (month === 9 && day > 18) || (month === 10 && day < 18): - result = 6; - break; - case (month === 10 && day > 17) || (month === 11 && day < 17): - result = 7; - break; - case (month === 11 && day > 16) || (month === 0 && day < 16): - result = 8; - break; - case (month === 0 && day > 15) || (month === 1 && day < 14): - result = 9; - break; - case (month === 1 && day > 13) || (month === 2 && day < 16): - result = 10; - break; - case (month === 2 && day > 15) || (month === 3 && day < 15): - result = 11; - break; - default: - result = 0; - break; - } - - return result; -} - export function getMonth( date: Date = new Date(), options: MonthOptions = { format: 'MMMM', calculationMethod: 'BD' } ): string { - if (!isValidDate(date)) return errorMessage; + if (!isValidDate(date)) { + throw new Error(errorMessage); + } const inputDate = new Date(date); const day = inputDate.getUTCDate(); const month = inputDate.getMonth(); + const year = inputDate.getFullYear(); const { format, calculationMethod = 'BD' } = options; const banglaMonth = calculationMethod === 'BD' ? getMonthBD(day, month) - : getMonthIN(day, month); + : getMonthIN(year, month, day); const result = formatMonth(banglaMonth, format); return result; diff --git a/src/getYear.ts b/src/getYear.ts index c314480..e3a6cf4 100644 --- a/src/getYear.ts +++ b/src/getYear.ts @@ -1,11 +1,30 @@ import { YearOptions } from './types'; -import { errorMessage, formatYear, isLeapYear, isValidDate } from './utils'; +import { + errorMessage, + formatYear, + getJulianDate, + isValidDate, + startJulianDate, + yearLength, +} from './utils'; + +const getYearIN = (year: number, month: number, day: number) => { + const julianDate = getJulianDate(year, month + 1, day); + + if (julianDate < startJulianDate) { + throw new Error(errorMessage); + } + + return Math.floor((julianDate - startJulianDate) / yearLength) + 1; +}; export function getYear( date: Date = new Date(), options: YearOptions = { format: 'YYYY', calculationMethod: 'BD' } ): string { - if (!isValidDate(date)) return errorMessage; + if (!isValidDate(date)) { + throw new Error(errorMessage); + } const inputDate = new Date(date); @@ -14,25 +33,19 @@ export function getYear( const year = inputDate.getFullYear(); const { format, calculationMethod = 'BD' } = options; - let result = formatYear(year - 593, format); + if (calculationMethod === 'IN') { + return formatYear(getYearIN(year, month, day), format); + } + + let banglaYear = year - 593; - if ( - isLeapYear(year) && - (month < 3 || - (calculationMethod === 'BD' && month === 3 && day < 14) || - (calculationMethod === 'IN' && month === 3 && day < 14)) - ) { - result = formatYear(year - 594, format); + if (month < 3 || (month === 3 && day < 14)) { + banglaYear = year - 594; } - if ( - !isLeapYear(year) && - (month < 3 || - (calculationMethod === 'BD' && month === 3 && day < 14) || - (calculationMethod === 'IN' && month === 3 && day < 15)) - ) { - result = formatYear(year - 594, format); + if (banglaYear < 1) { + throw new Error(errorMessage); } - return result; + return formatYear(banglaYear, format); } diff --git a/src/utils.ts b/src/utils.ts index 21cd947..354b43d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,6 @@ import { DayFormat, MonthFormat, WeekDayFormat, YearFormat } from './types'; -export const convertNumbers = (data): string => { +export const convertNumbers = (data: any) => { const numbers = { 0: '০', 1: '১', @@ -130,4 +130,32 @@ export const formatYear = ( } }; +export const getJulianDate = (year: number, month: number, day: number) => { + let y = year; + let m = month; + if (month <= 2) { + y -= 1; + m += 12; + } + const A = Math.floor(y / 100); + const B = 2 - A + Math.floor(A / 4); + + const JD = + Math.floor(365.25 * (y + 4716)) + + Math.floor(30.6001 * (m + 1)) + + day + + B - + 1524.5; + + return JD; +}; + +export const monthLengthIN = [ + 0, 30.93081, 62.35364, 93.9999999999999, 125.47636, 156.48933, 186.92405, + 216.3179999, 246.3153999, 275.14288, 305.09428, 334.91145, 365.258756, +]; + +export const startJulianDate = 1938094.4629; +export const yearLength = 365.258756; + export const errorMessage = 'Invalid Date'; diff --git a/tsconfig.json b/tsconfig.json index dd78a66..51218f2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "lib": "es2015", "compilerOptions": { "emitDeclarationOnly": true, "esModuleInterop": true,