updated for timezone handling and asr calc

This commit is contained in:
Ali Camarata 2023-11-13 08:51:34 +07:00
parent 13a477abee
commit b867162ace
12 changed files with 191 additions and 39 deletions

16
CHANGELOG.md Normal file
View file

@ -0,0 +1,16 @@
# Changelog
All notable changes to this project will be documented in this file.
## [1.0.0] - 2023-11-11
- Initial release
## [1.1.0] - 2023-11-12
- Updated calculation behavior to be more accurate (major)
## [1.2.2] - 2023-11-12
- Moved timezone to main args and changed default behavior (major)
- Updated test cases and readme to reflect new usage (minor)

View file

@ -14,15 +14,37 @@ npm install praycalc
Example of using praycalc to get prayer times: Example of using praycalc to get prayer times:
```js ```js
const { calcTimes } = require('./calcTimes'); const { getTimes, calcTimesAll } = require('praycalc');
const date = new Date(); // Current date const date = new Date();
const latitude = 40.7128; // Latitude for New York City
const longitude = -74.006; // Longitude for New York City
const elevation = 10; // Elevation for New York City
const prayerTimes = calcTimes(date, latitude, longitude, elevation); /* NYC - minimum params
console.log(prayerTimes); const city = "New York"
const lat = 40.7128;
const lng = -74.006;
const tz = null
const elevation = null
const temperature = null
const pressure = null
*/
// Jakarta - all params
const city = "Jakarta"
const lat = -6.2088
const lng = 106.8456
const tz = 7
const elevation = 18
const temperature = 26.56
const pressure = 1017
// Get results
const get = getTimes(date, lat, lng); // minimal args
const calc = calcTimesAll(date, lat, lng, tz, elevation, temperature, pressure);
// Print results
console.log(`\nTest: ${city} with current Date():\n`)
console.log("getTimes =", get, "\n");
console.log("calcTimesAll =", calc, "\n");
``` ```
Exported functions include getTimes, calcTimes, getTimesAll, calcTimesAll where the "get" functions return fractal or decimal times directly from the source nrel-spa calculator and the "calc" functions return formatted times in HH:MM:SS.sss format. The functions will give results including our custom angle but the "All" functions will include a methods key with all traditional static angle methods (Muslim World League, Egyptian General Authority of Survey, ISNA, etc.) included as well for their Fajr and Isha times. Exported functions include getTimes, calcTimes, getTimesAll, calcTimesAll where the "get" functions return fractal or decimal times directly from the source nrel-spa calculator and the "calc" functions return formatted times in HH:MM:SS.sss format. The functions will give results including our custom angle but the "All" functions will include a methods key with all traditional static angle methods (Muslim World League, Egyptian General Authority of Survey, ISNA, etc.) included as well for their Fajr and Isha times.

View file

@ -12,8 +12,8 @@ const { getTimes } = require('./getTimes');
* @param {number} [pressure=1013.25] - Atmospheric pressure in millibars (default 1013.25). * @param {number} [pressure=1013.25] - Atmospheric pressure in millibars (default 1013.25).
* @returns {Object} - Object containing prayer times. * @returns {Object} - Object containing prayer times.
*/ */
function calcTimes(date, lat, lng, elevation = 50, temperature = 15, pressure = 1013.25) { function calcTimes(date, lat, lng, tz, elevation = 50, temperature = 15, pressure = 1013.25) {
let result = getTimes(date, lat, lng, elevation, temperature, pressure); let result = getTimes(date, lat, lng, tz, elevation, temperature, pressure);
// Sort the result object by their values, excluding "Angle" // Sort the result object by their values, excluding "Angle"
let sortedEntries = Object.entries(result) let sortedEntries = Object.entries(result)

View file

@ -1,8 +1,8 @@
const { fractalTime } = require('nrel-spa'); const { fractalTime } = require('nrel-spa');
const { getTimesAll } = require('./getTimesAll'); const { getTimesAll } = require('./getTimesAll');
function calcTimesAll(date, lat, lng, elevation = 10, temperature = 15, pressure = 1013.25) { function calcTimesAll(date, lat, lng, tz, elevation = 10, temperature = 15, pressure = 1013.25) {
let result = getTimesAll(date, lat, lng, elevation, temperature, pressure); let result = getTimesAll(date, lat, lng, tz, elevation, temperature, pressure);
// Sort the methods by Fajr time // Sort the methods by Fajr time
let sortedMethods = Object.entries(result.Methods) let sortedMethods = Object.entries(result.Methods)

View file

@ -1,7 +1,7 @@
const { getSpa, fractalTime } = require('nrel-spa'); const { getSpa, fractalTime } = require('nrel-spa');
function getAsr(solarNoonDate, latitude, longitude, standard = true) { function getAsr(solarNoonDate, latitude, longitude, tz, standard = true) {
const solarNoonAltitude = getSpa(solarNoonDate, latitude, longitude).zenith; const solarNoonAltitude = getSpa(solarNoonDate, latitude, longitude, tz).zenith;
const shadowLengthAtNoon = 1 / Math.tan((90 - solarNoonAltitude) * Math.PI / 180); const shadowLengthAtNoon = 1 / Math.tan((90 - solarNoonAltitude) * Math.PI / 180);
// For standard method: Shadow length = object height + shadow length at noon // For standard method: Shadow length = object height + shadow length at noon
@ -12,9 +12,8 @@ function getAsr(solarNoonDate, latitude, longitude, standard = true) {
let asrTime; let asrTime;
for (let i = 0; i < 720; i++) { // Check next 12 hours for (let i = 0; i < 720; i++) { // Check next 12 hours
const testTime = new Date(solarNoonDate.getTime() + i * 60000); // Increment by one minute const testTime = new Date(solarNoonDate.getTime() + i * 60000); // Increment by one minute
const currentAltitude = getSpa(testTime, latitude, longitude).zenith; const currentAltitude = getSpa(testTime, latitude, longitude, tz).zenith;
const currentShadowLength = 1 / Math.tan((90 - currentAltitude) * Math.PI / 180); const currentShadowLength = 1 / Math.tan((90 - currentAltitude) * Math.PI / 180);
if (currentShadowLength >= targetShadowLength) { if (currentShadowLength >= targetShadowLength) {
asrTime = testTime; asrTime = testTime;
break; break;

View file

@ -3,13 +3,13 @@ const { getAngles } = require('./getAngles');
const { getAsr } = require('./getAsr'); const { getAsr } = require('./getAsr');
const { getQiyam } = require('./getQiyam'); const { getQiyam } = require('./getQiyam');
function getTimes(date, lat, lng, elevation = 50, temperature = 15, pressure = 1013.25, standard = true) { function getTimes(date, lat, lng, tz, elevation = 50, temperature = 15, pressure = 1013.25, standard = true) {
// Step 1: Get the custom angles // Step 1: Get the custom angles
const { fajrAngle, ishaAngle } = getAngles(elevation, pressure, temperature); const { fajrAngle, ishaAngle } = getAngles(elevation, pressure, temperature);
// Step 2: Get SPA data with custom angle for Fajr/Isha // Step 2: Get SPA data with custom angle for Fajr/Isha
const spaParams = { elevation, temperature, pressure }; const spaParams = { elevation, temperature, pressure };
const spaData = getSpa(date, lat, lng, spaParams, [fajrAngle+90, ishaAngle+90]); const spaData = getSpa(date, lat, lng, tz, spaParams, [fajrAngle+90, ishaAngle+90]);
// Organize prayer times // Organize prayer times
const fajrTime = spaData.angles[0].sunrise; // Lower time from custom angle const fajrTime = spaData.angles[0].sunrise; // Lower time from custom angle
@ -25,7 +25,7 @@ function getTimes(date, lat, lng, elevation = 50, temperature = 15, pressure = 1
const solarNoonSeconds = Math.floor((spaData.solarNoon * 3600) - (solarNoonHours * 3600) - (solarNoonMinutes * 60)); const solarNoonSeconds = Math.floor((spaData.solarNoon * 3600) - (solarNoonHours * 3600) - (solarNoonMinutes * 60));
const solarNoonDate = new Date(date); const solarNoonDate = new Date(date);
solarNoonDate.setHours(solarNoonHours, solarNoonMinutes, solarNoonSeconds); solarNoonDate.setHours(solarNoonHours, solarNoonMinutes, solarNoonSeconds);
const asrPrayerTime = getAsr(solarNoonDate, lat, lng, standard); const asrPrayerTime = getAsr(solarNoonDate, lat, lng, tz, standard);
// Step 4: Calculate Qiyam time // Step 4: Calculate Qiyam time
const qiyamTime = getQiyam(fajrTime, ishaTime); const qiyamTime = getQiyam(fajrTime, ishaTime);

View file

@ -16,14 +16,14 @@ const methods = [
{n:'MUIS', f:20, i:18, r:'SG'}, {n:'MUIS', f:20, i:18, r:'SG'},
]; ];
function getTimesAll(date, lat, lng, elevation = 50, temperature = 15, pressure = 1013.25, standard = true) { function getTimesAll(date, lat, lng, tz, elevation = 50, temperature = 15, pressure = 1013.25, standard = true) {
// Step 1: Get the custom angles // Step 1: Get the custom angles
const { fajrAngle, ishaAngle } = getAngles(elevation, pressure, temperature); const { fajrAngle, ishaAngle } = getAngles(elevation, pressure, temperature);
const methodAngles = methods.map(m => [m.f + 90, m.i + 90]); const methodAngles = methods.map(m => [m.f + 90, m.i + 90]);
// Step 2: Get SPA data with custom angle for Fajr/Isha and other methods // Step 2: Get SPA data with custom angle for Fajr/Isha and other methods
const spaParams = { elevation, temperature, pressure }; const spaParams = { elevation, temperature, pressure };
const spaData = getSpa(date, lat, lng, spaParams, [fajrAngle + 90, ishaAngle + 90, ...methodAngles.flat()]); const spaData = getSpa(date, lat, lng, tz, spaParams, [fajrAngle + 90, ishaAngle + 90, ...methodAngles.flat()]);
// Organize prayer times // Organize prayer times
const fajrTime = spaData.angles[0].sunrise; const fajrTime = spaData.angles[0].sunrise;
@ -39,7 +39,7 @@ function getTimesAll(date, lat, lng, elevation = 50, temperature = 15, pressure
const solarNoonSeconds = Math.floor((spaData.solarNoon * 3600) - (solarNoonHours * 3600) - (solarNoonMinutes * 60)); const solarNoonSeconds = Math.floor((spaData.solarNoon * 3600) - (solarNoonHours * 3600) - (solarNoonMinutes * 60));
const solarNoonDate = new Date(date); const solarNoonDate = new Date(date);
solarNoonDate.setHours(solarNoonHours, solarNoonMinutes, solarNoonSeconds); solarNoonDate.setHours(solarNoonHours, solarNoonMinutes, solarNoonSeconds);
const asrPrayerTime = getAsr(solarNoonDate, lat, lng, standard); const asrPrayerTime = getAsr(solarNoonDate, lat, lng, tz, standard);
// Step 4: Calculate Qiyam time // Step 4: Calculate Qiyam time
const qiyamTime = getQiyam(fajrTime, ishaTime); const qiyamTime = getQiyam(fajrTime, ishaTime);

63
index.d.ts vendored Normal file
View file

@ -0,0 +1,63 @@
declare module 'praycalc' {
export function getMoon(date: Date): MoonReturnType;
export function getTimes(date: Date, lat: number, lng: number, elevation?: number, temperature?: number, pressure?: number): TimesReturnType;
export function calcTimes(date: Date, lat: number, lng: number, elevation?: number, temperature?: number, pressure?: number): CalcTimesReturnType;
export function getTimesAll(date: Date, lat: number, lng: number, elevation?: number, temperature?: number, pressure?: number): TimesAllReturnType;
export function calcTimesAll(date: Date, lat: number, lng: number, elevation?: number, temperature?: number, pressure?: number): CalcTimesAllReturnType;
interface MoonReturnType {
fraction: number;
phase: number;
angle: number;
}
interface TimesReturnType {
Qiyam: number;
Fajr: number;
Sunrise: number;
Noon: number;
Dhuhr: number;
Asr: number;
Maghrib: number;
Isha: number;
Angles: number[];
}
interface CalcTimesReturnType {
Qiyam: string;
Fajr: string;
Sunrise: string;
Noon: string;
Dhuhr: string;
Asr: string;
Maghrib: string;
Isha: string;
Angles: number[];
}
interface TimesAllReturnType {
Qiyam: number;
Fajr: number;
Sunrise: number;
Noon: number;
Dhuhr: number;
Asr: number;
Maghrib: number;
Isha: number;
Methods: Record<string, string[]>;
Angles: number[];
}
interface CalcTimesAllReturnType {
Qiyam: string;
Fajr: string;
Sunrise: string;
Noon: string;
Dhuhr: string;
Asr: string;
Maghrib: string;
Isha: string;
Methods: Record<string, string[]>;
Angles: number[];
}
}

12
package-lock.json generated
View file

@ -1,21 +1,21 @@
{ {
"name": "praycalc", "name": "praycalc",
"version": "1.0.0", "version": "1.2.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "praycalc", "name": "praycalc",
"version": "1.0.0", "version": "1.2.2",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nrel-spa": "^1.1.0" "nrel-spa": "^1.2.2"
} }
}, },
"node_modules/nrel-spa": { "node_modules/nrel-spa": {
"version": "1.1.0", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/nrel-spa/-/nrel-spa-1.1.0.tgz", "resolved": "https://registry.npmjs.org/nrel-spa/-/nrel-spa-1.2.2.tgz",
"integrity": "sha512-uoVKBDIj5vvAMEzRr2LSKXo/r9IcadE46CeBSepU47ssByoDZ6QFUsmzTUvg9DAggGbVTTCCEvM29bGUI4YYzA==" "integrity": "sha512-2mycHd7PP0l+pPjPvrT6vr+PRHufCFOxsPcpaIOQ9GwhhfzgyTvSsLKPsqC6ZENNU65yq4PetT5XlWj3CoLjiQ=="
} }
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "praycalc", "name": "praycalc",
"version": "1.0.0", "version": "1.2.2",
"description": "Prayer times calculator using nrel-spa and custom formula for Fajr and Isha angles (as well as traditional static angle methods in the All function)", "description": "Prayer times calculator using nrel-spa and custom formula for Fajr and Isha angles (as well as traditional static angle methods in the All function)",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -13,6 +13,6 @@
"author": "USF", "author": "USF",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nrel-spa": "^1.1.0" "nrel-spa": "^1.2.2"
} }
} }

34
test-spa.js Normal file
View file

@ -0,0 +1,34 @@
const { getSpa, calcSpa } = require('nrel-spa');
const date = new Date();
console.log(date)
/* NYC - minimum params
const city = "New York"
const lat = 40.7128;
const lng = -74.006;
const tz = -5;
const params = null
const angles = []
*/
// Jakarta - all params
const city = "Jakarta"
const lat = -6.2088
const lng = 106.8456
const tz = 7
const elevation = 18
const temperature = 26.56
const pressure = 1017
const params = {elevation, temperature, pressure}
const angles = [63.435]
// Get results
const get = getSpa(date, lat, lng); // minimal args
const calc = calcSpa(date, lat, lng, tz, params, angles);
// Print results
console.log(`\nTest: ${city} with current Date():\n`)
console.log("getSpa =", get, "\n");
console.log("calcSpa =", calc, "\n");

38
test.js
View file

@ -1,13 +1,31 @@
const { calcTimesAll } = require('./index'); const { getTimes, calcTimesAll } = require('./index');
const lat = 40.7128; // Latitude for New York City
const lng = -74.0060; // Longitude for New York City
const elevation = 10; // Average elevation for NYC in meters
const temperature = 15; // Average temperature for NYC in Celsius
const pressure = 1013.25; // Average atmospheric pressure in millibars
const date = new Date(); const date = new Date();
const prayerTimes = calcTimesAll(date, lat, lng, elevation, temperature, pressure);
console.log(`NYC Prayer Times for Today:\n\n`); /* NYC - minimum params
console.log(prayerTimes); const city = "New York"
const lat = 40.7128;
const lng = -74.006;
const tz = null
const elevation = null
const temperature = null
const pressure = null
*/
// Jakarta - all params
const city = "Jakarta"
const lat = -6.2088
const lng = 106.8456
const tz = 7
const elevation = 18
const temperature = 26.56
const pressure = 1017
// Get results
const get = getTimes(date, lat, lng); // minimal args
const calc = calcTimesAll(date, lat, lng, tz, elevation, temperature, pressure);
// Print results
console.log(`\nTest: ${city} with current Date():\n`)
console.log("getTimes =", get, "\n");
console.log("calcTimesAll =", calc, "\n");