Skip to content

Commit

Permalink
feat: adding the option to handle polar night and midnight sun cases
Browse files Browse the repository at this point in the history
  • Loading branch information
b-stud committed Dec 16, 2020
1 parent 5a38898 commit 98a3c09
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
coverage/
coverage/
.idea
7 changes: 6 additions & 1 deletion Adhan.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class PrayerTimes {
}

export class CalculationParameters {
constructor(fajrAngle: number, ishaAngle: number, ishaInterval: number, methodName?: string)
constructor(methodName: string|undefined|null, fajrAngle: number, ishaAngle: number, ishaInterval: number, maghribAngle: number)

readonly method: string;
fajrAngle: number;
Expand Down Expand Up @@ -84,3 +84,8 @@ export enum HighLatitudeRule {
TwilightAngle
}

export enum PolarCircleResolution {
aqrabBalad,
aqrabYaum,
unresolved
}
119 changes: 117 additions & 2 deletions Adhan.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Adhan.js.map

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions src/Adhan.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import { Madhab } from './Madhab';
import HighLatitudeRule from './HighLatitudeRule';
import CalculationMethod from './CalculationMethod';
import CalculationParameters from './CalculationParameters';
import qibla from './Qibla';
import Qibla from './Qibla';
import SunnahTimes from './SunnahTimes';
import { PolarCircleResolution } from './PolarCircleResolution';

const adhan = {
Prayer: Prayer,
Madhab: Madhab,
HighLatitudeRule: HighLatitudeRule,
Coordinates: Coordinates,
CalculationParameters: CalculationParameters,
CalculationMethod: CalculationMethod,
PrayerTimes: PrayerTimes,
SunnahTimes: SunnahTimes,
Qibla: qibla
Prayer,
Madhab,
HighLatitudeRule,
Coordinates,
CalculationParameters,
CalculationMethod,
PrayerTimes,
SunnahTimes,
Qibla,
PolarCircleResolution,
};

export default adhan;
2 changes: 2 additions & 0 deletions src/CalculationParameters.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Madhab } from './Madhab';
import HighLatitudeRule from './HighLatitudeRule';
import { PolarCircleResolution } from './PolarCircleResolution';

export default class CalculationParameters {
constructor(methodName, fajrAngle, ishaAngle, ishaInterval, maghribAngle) {
Expand All @@ -12,6 +13,7 @@ export default class CalculationParameters {
this.highLatitudeRule = HighLatitudeRule.MiddleOfTheNight;
this.adjustments = { fajr: 0, sunrise: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0 };
this.methodAdjustments = { fajr: 0, sunrise: 0, dhuhr: 0, asr: 0, maghrib: 0, isha: 0 };
this.polarCircleResolution = PolarCircleResolution.unresolved;
}

nightPortions() {
Expand Down
4 changes: 4 additions & 0 deletions src/DateUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ export function dayOfYear(date) {

return returnedDayOfYear;
}

export function isValidDate(date) {
return date instanceof Date && !isNaN(date.valueOf());
}
78 changes: 78 additions & 0 deletions src/PolarCircleResolution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import SolarTime from './SolarTime';
import { dateByAddingDays } from './DateUtils';

export const PolarCircleResolution = {
aqrabBalad: 'aqrab-balad',
aqrabYaum: 'aqrab-yaum',
unresolved: 'unresolved'
};

const LATITUDE_VARIATION_STEP = 0.5; // Degrees to add/remove at each resolution step
const UNSAFE_LATITUDE = 65; // Based on https://en.wikipedia.org/wiki/Midnight_sun

const isValidSolarTime = (solarTime) => solarTime && !isNaN(solarTime.sunrise) && !isNaN(solarTime.sunset);

const aqrabYaumResolver = (coordinates, date, daysAdded = 1, direction = 1) => {
if (daysAdded > Math.ceil(365 / 2)) {
return null;
}
const testDate = new Date(date.getTime());
testDate.setDate(testDate.getDate() + (direction * daysAdded));
const tomorrow = dateByAddingDays(testDate, 1);
const solarTime = new SolarTime(testDate, coordinates);
const tomorrowSolarTime = new SolarTime(tomorrow, coordinates);

if (!isValidSolarTime(solarTime) || !isValidSolarTime(tomorrowSolarTime)) {
return aqrabYaumResolver(coordinates, date, daysAdded + (direction > 0 ? 0 : 1), -direction);
}

return {
date,
tomorrow,
coordinates,
solarTime,
tomorrowSolarTime,
};
}

const aqrabBaladResolver = (coordinates, date, latitude) => {
const solarTime = new SolarTime(date, { ...coordinates, latitude });
const tomorrow = dateByAddingDays(date, 1);
const tomorrowSolarTime = new SolarTime(tomorrow, { ...coordinates, latitude });
if (!isValidSolarTime(solarTime) || !isValidSolarTime(tomorrowSolarTime)) {
return (Math.abs(latitude) >= UNSAFE_LATITUDE) ?
aqrabBaladResolver(coordinates, date, latitude - Math.sign(latitude) * LATITUDE_VARIATION_STEP)
: null;
}

return {
date,
tomorrow,
coordinates: { latitude, longitude: coordinates.longitude },
solarTime,
tomorrowSolarTime,
};
};

export const polarCircleResolvedValues = (resolver, date, coordinates) => {
const defaultReturn = {
date,
tomorrow: dateByAddingDays(date, 1),
coordinates,
solarTime: new SolarTime(date, coordinates),
tomorrowSolarTime: new SolarTime(dateByAddingDays(date, 1), coordinates),
};

switch (resolver) {
case PolarCircleResolution.aqrabYaum: {
return aqrabYaumResolver(coordinates, date) || defaultReturn;
}
case PolarCircleResolution.aqrabBalad: {
const { latitude } = coordinates;
return aqrabBaladResolver(coordinates, date, latitude - (Math.sign(latitude) * LATITUDE_VARIATION_STEP)) || defaultReturn;
}
default: {
return defaultReturn;
}
}
};
Loading

0 comments on commit 98a3c09

Please sign in to comment.