mirror of https://github.com/espruino/BangleApps
feat: use customizer to more accurately generate calendar data file
feat: brand new UI to display upcoming/current calendar events feat: add holidays, shabbat torah readings, and time display to clockpull/1731/head
parent
b7b64c2cfe
commit
34f02fd1da
|
@ -2,3 +2,5 @@
|
|||
0.02: using TS and rollup to bundle
|
||||
0.03: bug fixes and support bangle 1
|
||||
0.04: removing TS
|
||||
0.05: major overhaul; now you customize your calendar based on your location for candle lighting times
|
||||
0.06: bug fixes and improvements
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
|
@ -1,19 +1,22 @@
|
|||
# Hebrew Calendar
|
||||
|
||||
Displays the current hebrew calendar date
|
||||
Add screen shots (if possible) to the app folder and link then into this file with 
|
||||
Displays the current hebrew calendar date and upcoming holidays alongside a clock
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
Open the app, and it shows a menu with the date components
|
||||
Set it up as your clock in the settings
|
||||
|
||||
## Features
|
||||
|
||||
Shows the hebrew date, month, and year; alongside the gregorian date
|
||||
- Shows the hebrew date, month, and year; alongside the gregorian date
|
||||
- Shows when upcoming holidays start
|
||||
- Shows the gregorian day of week, date, and current time
|
||||
|
||||
## Controls
|
||||
|
||||
Name the buttons and what they are used for
|
||||
N/A
|
||||
|
||||
## Requests
|
||||
|
||||
|
@ -22,5 +25,5 @@ Michael Salaverry (github.com/barakplasma)
|
|||
## Creator
|
||||
|
||||
Michael Salaverry
|
||||
with help from https://github.com/IonicaBizau/hebrew-date (MIT license)
|
||||
with help from https://github.com/hebcal/hebcal-es6 (MIT license) which is used to calculate the calendar
|
||||
<div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">[www.flaticon.com](https://www.flaticon.com/premium-icon/calendar_3130060?term=jewish&page=1&position=10&page=1&position=10&related_id=3130060&origin=tag)</a></div>
|
|
@ -1,26 +1,181 @@
|
|||
g.clear();
|
||||
const dayInMS = 86400000;
|
||||
|
||||
let now = new Date();
|
||||
const DateProvider = { now: () => Date.now() };
|
||||
|
||||
let today = require('hebrewDate').hebrewDate(now);
|
||||
const Layout = require("Layout");
|
||||
const Locale = require("locale");
|
||||
|
||||
var mainmenu = {
|
||||
"": {
|
||||
"title": "Hebrew Date"
|
||||
},
|
||||
greg: {
|
||||
// @ts-ignore
|
||||
value: require('locale').date(now, 1),
|
||||
},
|
||||
date: {
|
||||
value: today.date,
|
||||
},
|
||||
month: {
|
||||
value: today.month_name,
|
||||
},
|
||||
year: {
|
||||
value: today.year,
|
||||
let nextEndingEvent;
|
||||
|
||||
function getCurrentEvents() {
|
||||
const now = DateProvider.now();
|
||||
|
||||
const current = hebrewCalendar.filter(
|
||||
(x) => x.startEvent <= now && x.endEvent >= now
|
||||
);
|
||||
|
||||
nextEndingEvent = current.reduce((acc, ev) => {
|
||||
return Math.min(acc, ev.endEvent);
|
||||
}, Infinity);
|
||||
|
||||
return current.map((event, i) => {
|
||||
return {
|
||||
type: "txt",
|
||||
font: "12x20",
|
||||
id: "currentEvents" + i,
|
||||
label: event.desc,
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getUpcomingEvents() {
|
||||
const now = DateProvider.now();
|
||||
|
||||
const futureEvents = hebrewCalendar.filter(
|
||||
(x) => x.startEvent >= now && x.startEvent <= now + dayInMS
|
||||
);
|
||||
|
||||
let warning;
|
||||
let eventsLeft = hebrewCalendar.filter(
|
||||
(x) => x.startEvent >= now && x.startEvent <= now + dayInMS * 14
|
||||
).length;
|
||||
|
||||
if (eventsLeft < 14) {
|
||||
warning = {
|
||||
startEvent: 0,
|
||||
type: "txt",
|
||||
font: "4x6",
|
||||
id: "warning",
|
||||
label: "only " + eventsLeft + " events left in calendar; update soon",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
}
|
||||
};
|
||||
// @ts-ignore
|
||||
E.showMenu(mainmenu);
|
||||
|
||||
return futureEvents
|
||||
.slice(0, 2)
|
||||
.map((event, i) => {
|
||||
return {
|
||||
startEvent: event.startEvent,
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "upcomingEvents" + 1,
|
||||
label: event.desc + " at " + Locale.time(new Date(event.startEvent), 1),
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
})
|
||||
.concat(warning)
|
||||
.sort(function (a, b) {
|
||||
return a.startEvent - b.startEvent;
|
||||
});
|
||||
}
|
||||
|
||||
function dateTime() {
|
||||
return (
|
||||
Locale.dow(new Date(), 1) +
|
||||
" " +
|
||||
Locale.date(new Date(), 1) +
|
||||
" " +
|
||||
Locale.time(new Date(), 1)
|
||||
);
|
||||
}
|
||||
|
||||
function makeLayout() {
|
||||
return new Layout(
|
||||
{
|
||||
type: "v",
|
||||
c: [
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "title",
|
||||
label: "-- Hebrew Calendar Events --",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg2,
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "currently",
|
||||
label: "Currently",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bgH,
|
||||
},
|
||||
]
|
||||
.concat(getCurrentEvents())
|
||||
.concat([
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
label: "Upcoming",
|
||||
id: "upcoming",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bgH,
|
||||
},
|
||||
])
|
||||
.concat(getUpcomingEvents())
|
||||
.concat([
|
||||
{
|
||||
type: "txt",
|
||||
font: "Vector14",
|
||||
id: "time",
|
||||
label: dateTime(),
|
||||
pad: 2,
|
||||
bgCol: undefined,
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ lazy: true }
|
||||
);
|
||||
}
|
||||
let layout = makeLayout();
|
||||
// see also https://www.espruino.com/Bangle.js+Layout#updating-the-screen
|
||||
|
||||
// timeout used to update every minute
|
||||
let drawTimeout;
|
||||
|
||||
function draw() {
|
||||
layout.time.label = dateTime();
|
||||
layout.render();
|
||||
|
||||
// schedule a draw for the next minute
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function () {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (DateProvider.now() % 60000));
|
||||
console.log("updated time");
|
||||
}
|
||||
|
||||
// update time and draw
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
draw();
|
||||
|
||||
function findNextEvent() {
|
||||
return hebrewCalendar.find((ev) => {
|
||||
return ev.startEvent > DateProvider.now();
|
||||
});
|
||||
}
|
||||
|
||||
function updateCalendar() {
|
||||
layout.clear();
|
||||
layout = makeLayout();
|
||||
layout.forgetLazyState();
|
||||
layout.render();
|
||||
|
||||
let nextChange = Math.min(
|
||||
findNextEvent().startEvent - DateProvider.now() + 5000,
|
||||
nextEndingEvent - DateProvider.now() + 5000
|
||||
);
|
||||
setTimeout(updateCalendar, nextChange);
|
||||
console.log("updated events");
|
||||
}
|
||||
|
||||
updateCalendar();
|
||||
|
||||
Bangle.setUI("clock");
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hebrew Calendar Customizer</title>
|
||||
<link rel="stylesheet" href="https://banglejs.com/apps/css/spectre.min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container grid-sm">
|
||||
<div class="panel center">
|
||||
<div class="panel-header">
|
||||
<div class="panel-title text-center h5 mt-10">Hebrew Calendar Loader</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="h4">Your location</div>
|
||||
<form method="GET">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="lat">Latitude</label>
|
||||
<input class="form-input" type="number" id="lat" name="lat" required min="-90" max="90" step="0.0000001" value="31.776580" placeholder="31.776580">
|
||||
<label class="form-label" for="lon">Longitude</label>
|
||||
<input class="form-input" type="number" id="lon" name="lon" required min="-180" max="180" step="0.0000001" value="35.233706" placeholder="35.233706">
|
||||
<div>get your latitude and longitude from <a href="https://plus.codes/map">plus.codes</a> or:</div>
|
||||
<button class="btn btn-secondary input-group-btn" id="geoloc">Get Latitude and Longitude automatically (using location permission)</button>
|
||||
<label class="form-switch">
|
||||
<input type="checkbox" id="inIL" name="inIL" checked>
|
||||
<i class="form-icon"></i> In Israel?
|
||||
</label>
|
||||
<button class="btn btn-primary input-group-btn" type="submit">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="text-center h6"><a href="https://github.com/hebcal/hebcal-es6">With help from @hebcal/core</a></div>
|
||||
<div class="text-center" id="hDate"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://banglejs.com/apps/core/lib/customize.js"></script>
|
||||
<script type="module" src="customizer.mjs"></script>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,329 @@
|
|||
import {
|
||||
HebrewCalendar,
|
||||
HDate,
|
||||
Location,
|
||||
Zmanim,
|
||||
} from "https://cdn.skypack.dev/@hebcal/core@^3?min";
|
||||
|
||||
function onload(event) {
|
||||
event.preventDefault();
|
||||
const latLon = getLatLonFromForm();
|
||||
const events = generateHebCal(latLon);
|
||||
const calendar = serializeEvents(events);
|
||||
console.debug(calendar);
|
||||
globalThis["cal"] = calendar;
|
||||
loadWatch(calendar);
|
||||
}
|
||||
|
||||
function loadWatch(json) {
|
||||
sendCustomizedApp({
|
||||
id: "hebrew_calendar",
|
||||
|
||||
storage: [
|
||||
{
|
||||
name: "hebrew_calendar.app.js",
|
||||
url: "app.js",
|
||||
// content below is same as app.js except for the first line which customizes the hebrewCalendar object used
|
||||
content: `
|
||||
let hebrewCalendar = ${json};
|
||||
|
||||
const dayInMS = 86400000;
|
||||
|
||||
const DateProvider = { now: () => Date.now() };
|
||||
|
||||
const Layout = require("Layout");
|
||||
const Locale = require("locale");
|
||||
|
||||
let nextEndingEvent;
|
||||
|
||||
function getCurrentEvents() {
|
||||
const now = DateProvider.now();
|
||||
|
||||
const current = hebrewCalendar.filter(
|
||||
(x) => x.startEvent <= now && x.endEvent >= now
|
||||
);
|
||||
|
||||
nextEndingEvent = current.reduce((acc, ev) => {
|
||||
return Math.min(acc, ev.endEvent);
|
||||
}, Infinity);
|
||||
|
||||
return current.map((event, i) => {
|
||||
return {
|
||||
type: "txt",
|
||||
font: "12x20",
|
||||
id: "currentEvents" + i,
|
||||
label: event.desc,
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getUpcomingEvents() {
|
||||
const now = DateProvider.now();
|
||||
|
||||
const futureEvents = hebrewCalendar.filter(
|
||||
(x) => x.startEvent >= now && x.startEvent <= now + dayInMS
|
||||
);
|
||||
|
||||
let warning;
|
||||
let eventsLeft = hebrewCalendar.filter(
|
||||
(x) => x.startEvent >= now && x.startEvent <= now + dayInMS * 14
|
||||
).length;
|
||||
|
||||
if (eventsLeft < 14) {
|
||||
warning = {
|
||||
startEvent: 0,
|
||||
type: "txt",
|
||||
font: "4x6",
|
||||
id: "warning",
|
||||
label: "only " + eventsLeft + " events left in calendar; update soon",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
}
|
||||
|
||||
return futureEvents
|
||||
.slice(0, 2)
|
||||
.map((event, i) => {
|
||||
return {
|
||||
startEvent: event.startEvent,
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "upcomingEvents" + 1,
|
||||
label: event.desc + " at " + Locale.time(new Date(event.startEvent), 1),
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg,
|
||||
};
|
||||
})
|
||||
.concat(warning)
|
||||
.sort(function (a, b) {
|
||||
return a.startEvent - b.startEvent;
|
||||
});
|
||||
}
|
||||
|
||||
function dateTime() {
|
||||
return (
|
||||
Locale.dow(new Date(), 1) +
|
||||
" " +
|
||||
Locale.date(new Date(), 1) +
|
||||
" " +
|
||||
Locale.time(new Date(), 1)
|
||||
);
|
||||
}
|
||||
|
||||
function makeLayout() {
|
||||
return new Layout(
|
||||
{
|
||||
type: "v",
|
||||
c: [
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "title",
|
||||
label: "-- Hebrew Calendar Events --",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bg2,
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
id: "currently",
|
||||
label: "Currently",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bgH,
|
||||
},
|
||||
]
|
||||
.concat(getCurrentEvents())
|
||||
.concat([
|
||||
{
|
||||
type: "txt",
|
||||
font: "6x8",
|
||||
label: "Upcoming",
|
||||
id: "upcoming",
|
||||
pad: 2,
|
||||
bgCol: g.theme.bgH,
|
||||
},
|
||||
])
|
||||
.concat(getUpcomingEvents())
|
||||
.concat([
|
||||
{
|
||||
type: "txt",
|
||||
font: "Vector14",
|
||||
id: "time",
|
||||
label: dateTime(),
|
||||
pad: 2,
|
||||
bgCol: undefined,
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ lazy: true }
|
||||
);
|
||||
}
|
||||
let layout = makeLayout();
|
||||
// see also https://www.espruino.com/Bangle.js+Layout#updating-the-screen
|
||||
|
||||
// timeout used to update every minute
|
||||
let drawTimeout;
|
||||
|
||||
function draw() {
|
||||
layout.time.label = dateTime();
|
||||
layout.render();
|
||||
|
||||
// schedule a draw for the next minute
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = setTimeout(function () {
|
||||
drawTimeout = undefined;
|
||||
draw();
|
||||
}, 60000 - (DateProvider.now() % 60000));
|
||||
console.log("updated time");
|
||||
}
|
||||
|
||||
// update time and draw
|
||||
g.clear();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
draw();
|
||||
|
||||
function findNextEvent() {
|
||||
return hebrewCalendar.find((ev) => {
|
||||
return ev.startEvent > DateProvider.now();
|
||||
});
|
||||
}
|
||||
|
||||
function updateCalendar() {
|
||||
layout.clear();
|
||||
layout = makeLayout();
|
||||
layout.forgetLazyState();
|
||||
layout.render();
|
||||
|
||||
let nextChange = Math.min(
|
||||
findNextEvent().startEvent - DateProvider.now() + 5000,
|
||||
nextEndingEvent - DateProvider.now() + 5000
|
||||
);
|
||||
setTimeout(updateCalendar, nextChange);
|
||||
console.log("updated events");
|
||||
}
|
||||
|
||||
updateCalendar();
|
||||
|
||||
Bangle.setUI("clock");
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector("button[type=submit]")
|
||||
.addEventListener("click", onload, false);
|
||||
|
||||
document.querySelector("#geoloc")?.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => {
|
||||
const {
|
||||
coords: { latitude, longitude },
|
||||
} = pos;
|
||||
locationElements[0].value = latitude;
|
||||
locationElements[1].value = longitude;
|
||||
console.debug(pos);
|
||||
},
|
||||
(err) => {
|
||||
if (err.PERMISSION_DENIED) {
|
||||
alert("permission required to use geolocation api; enter manually");
|
||||
}
|
||||
if (err.POSITION_UNAVAILABLE) {
|
||||
alert("position unavailable; enter manually");
|
||||
}
|
||||
},
|
||||
{ enableHighAccuracy: false }
|
||||
);
|
||||
});
|
||||
|
||||
document.querySelector(
|
||||
"#hDate"
|
||||
).innerText = `Today is ${new Date().toLocaleDateString()} & ${new HDate().toString()}`;
|
||||
|
||||
const locationElements = [
|
||||
document.querySelector("#lat"),
|
||||
document.querySelector("#lon"),
|
||||
];
|
||||
|
||||
function getLatLonFromForm() {
|
||||
const latLon = locationElements.map((el) => el.value);
|
||||
if (locationElements.every((x) => x.checkValidity())) {
|
||||
return latLon;
|
||||
} else {
|
||||
console.debug("lat lon invalid error");
|
||||
return [0, 0];
|
||||
}
|
||||
}
|
||||
|
||||
function groupBy(arr, fn) {
|
||||
return arr
|
||||
.map(typeof fn === "function" ? fn : (val) => val[fn])
|
||||
.reduce((acc, val, i) => {
|
||||
acc[val] = (acc[val] || []).concat(arr[i]);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function generateHebCal(latLon) {
|
||||
const location = new Location(
|
||||
...latLon,
|
||||
document.querySelector("#inIL").checked
|
||||
);
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const options = {
|
||||
year: now.getFullYear(),
|
||||
isHebrewYear: false,
|
||||
candlelighting: true,
|
||||
location,
|
||||
addHebrewDates: true,
|
||||
addHebrewDatesForEvents: true,
|
||||
sedrot: true,
|
||||
start: now,
|
||||
end: new Date(now.getFullYear(), now.getMonth() + 3),
|
||||
};
|
||||
|
||||
const events = HebrewCalendar.calendar(options).map((ev) => {
|
||||
const { desc, eventTime, startEvent, endEvent } = ev;
|
||||
|
||||
const zman = new Zmanim(ev.date, ...latLon.map(Number));
|
||||
|
||||
let output = {
|
||||
desc,
|
||||
startEvent: startEvent?.eventTime?.getTime() || zman.gregEve().getTime(),
|
||||
endEvent: endEvent?.eventTime?.getTime() || zman.shkiah().getTime(),
|
||||
};
|
||||
|
||||
if (eventTime) {
|
||||
delete output.startEvent;
|
||||
delete output.endEvent;
|
||||
output.startEvent = eventTime.getTime();
|
||||
output.endEvent = eventTime.getTime() + 60000 * 15;
|
||||
}
|
||||
|
||||
return output;
|
||||
});
|
||||
|
||||
// console.table(events)
|
||||
|
||||
return events.sort((a, b) => {
|
||||
return a.startEvent - b.startEvent;
|
||||
});
|
||||
}
|
||||
|
||||
function enc(data) {
|
||||
return btoa(heatshrink.compress(new TextEncoder().encode(data)));
|
||||
}
|
||||
|
||||
function serializeEvents(events) {
|
||||
// const splitByGregorianMonth = groupBy(events, (evt) => {
|
||||
// return new Date(evt.startEvent).getMonth();
|
||||
// });
|
||||
return JSON.stringify(events);
|
||||
}
|
|
@ -1,311 +0,0 @@
|
|||
/*!
|
||||
* This script was taked from this page http://www.shamash.org/help/javadate.shtml and ported to Node.js by Ionică Bizău in https://github.com/IonicaBizau/hebrew-date
|
||||
*
|
||||
* This script was adapted from C sources written by
|
||||
* Scott E. Lee, which contain the following copyright notice:
|
||||
*
|
||||
* Copyright 1993-1995, Scott E. Lee, all rights reserved.
|
||||
* Permission granted to use, copy, modify, distribute and sell so long as
|
||||
* the above copyright and this permission statement are retained in all
|
||||
* copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
|
||||
*
|
||||
* Bill Hastings
|
||||
* RBI Software Systems
|
||||
* bhastings@rbi.com
|
||||
*/
|
||||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
||||
var GREG_SDN_OFFSET = 32045, DAYS_PER_5_MONTHS = 153, DAYS_PER_4_YEARS = 1461, DAYS_PER_400_YEARS = 146097;
|
||||
var HALAKIM_PER_HOUR = 1080, HALAKIM_PER_DAY = 25920, HALAKIM_PER_LUNAR_CYCLE = 29 * HALAKIM_PER_DAY + 13753, HALAKIM_PER_METONIC_CYCLE = HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7);
|
||||
var HEB_SDN_OFFSET = 347997, NEW_MOON_OF_CREATION = 31524, NOON = 18 * HALAKIM_PER_HOUR, AM3_11_20 = 9 * HALAKIM_PER_HOUR + 204, AM9_32_43 = 15 * HALAKIM_PER_HOUR + 589;
|
||||
var SUN = 0, MON = 1, TUES = 2, WED = 3, THUR = 4, FRI = 5, SAT = 6;
|
||||
function weekdayarr(d0, d1, d2, d3, d4, d5, d6) {
|
||||
this[0] = d0;
|
||||
this[1] = d1;
|
||||
this[2] = d2;
|
||||
this[3] = d3;
|
||||
this[4] = d4;
|
||||
this[5] = d5;
|
||||
this[6] = d6;
|
||||
}
|
||||
function gregmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11) {
|
||||
this[0] = m0;
|
||||
this[1] = m1;
|
||||
this[2] = m2;
|
||||
this[3] = m3;
|
||||
this[4] = m4;
|
||||
this[5] = m5;
|
||||
this[6] = m6;
|
||||
this[7] = m7;
|
||||
this[8] = m8;
|
||||
this[9] = m9;
|
||||
this[10] = m10;
|
||||
this[11] = m11;
|
||||
}
|
||||
function hebrewmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13) {
|
||||
this[0] = m0;
|
||||
this[1] = m1;
|
||||
this[2] = m2;
|
||||
this[3] = m3;
|
||||
this[4] = m4;
|
||||
this[5] = m5;
|
||||
this[6] = m6;
|
||||
this[7] = m7;
|
||||
this[8] = m8;
|
||||
this[9] = m9;
|
||||
this[10] = m10;
|
||||
this[11] = m11;
|
||||
this[12] = m12;
|
||||
this[13] = m13;
|
||||
}
|
||||
function monthsperyeararr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18) {
|
||||
this[0] = m0;
|
||||
this[1] = m1;
|
||||
this[2] = m2;
|
||||
this[3] = m3;
|
||||
this[4] = m4;
|
||||
this[5] = m5;
|
||||
this[6] = m6;
|
||||
this[7] = m7;
|
||||
this[8] = m8;
|
||||
this[9] = m9;
|
||||
this[10] = m10;
|
||||
this[11] = m11;
|
||||
this[12] = m12;
|
||||
this[13] = m13;
|
||||
this[14] = m14;
|
||||
this[15] = m15;
|
||||
this[16] = m16;
|
||||
this[17] = m17;
|
||||
this[18] = m18;
|
||||
}
|
||||
var gWeekday = new weekdayarr("Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"), gMonth = new gregmontharr("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), hMonth = new hebrewmontharr("Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "AdarI", "AdarII", "Nisan", "Iyyar", "Sivan", "Tammuz", "Av", "Elul"), mpy = new monthsperyeararr(12, 12, 13, 12, 12, 13, 12, 13, 12, 12, 13, 12, 12, 13, 12, 12, 13, 12, 13);
|
||||
/**
|
||||
* hebrewDate
|
||||
* Convert the Gregorian dates into Hebrew calendar dates.
|
||||
*
|
||||
* @name hebrewDate
|
||||
* @function
|
||||
* @param {Date|Number} inputDate The date object (representing the Gregorian date) or the year.
|
||||
* @return {Object} An object containing:
|
||||
*
|
||||
* - `year`: The Hebrew year.
|
||||
* - `month`: The Hebrew month.
|
||||
* - `month_name`: The Hebrew month name.
|
||||
* - `date`: The Hebrew date.
|
||||
*/
|
||||
function hebrewDate(inputDateOrYear) {
|
||||
var inputMonth, inputDate;
|
||||
var hebrewMonth = 0, hebrewDate = 0, hebrewYear = 0, metonicCycle = 0, metonicYear = 0, moladDay = 0, moladHalakim = 0;
|
||||
function GregorianToSdn(inputYear, inputMonth, inputDay) {
|
||||
var year = 0, month = 0, sdn = void 0;
|
||||
// Make year a positive number
|
||||
if (inputYear < 0) {
|
||||
year = inputYear + 4801;
|
||||
}
|
||||
else {
|
||||
year = inputYear + 4800;
|
||||
}
|
||||
// Adjust the start of the year
|
||||
if (inputMonth > 2) {
|
||||
month = inputMonth - 3;
|
||||
}
|
||||
else {
|
||||
month = inputMonth + 9;
|
||||
year--;
|
||||
}
|
||||
sdn = Math.floor(Math.floor(year / 100) * DAYS_PER_400_YEARS / 4);
|
||||
sdn += Math.floor(year % 100 * DAYS_PER_4_YEARS / 4);
|
||||
sdn += Math.floor((month * DAYS_PER_5_MONTHS + 2) / 5);
|
||||
sdn += inputDay - GREG_SDN_OFFSET;
|
||||
return sdn;
|
||||
}
|
||||
function SdnToHebrew(sdn) {
|
||||
var tishri1 = 0, tishri1After = 0, yearLength = 0, inputDay = sdn - HEB_SDN_OFFSET;
|
||||
FindTishriMolad(inputDay);
|
||||
tishri1 = Tishri1(metonicYear, moladDay, moladHalakim);
|
||||
if (inputDay >= tishri1) {
|
||||
// It found Tishri 1 at the start of the year.
|
||||
hebrewYear = metonicCycle * 19 + metonicYear + 1;
|
||||
if (inputDay < tishri1 + 59) {
|
||||
if (inputDay < tishri1 + 30) {
|
||||
hebrewMonth = 1;
|
||||
hebrewDate = inputDay - tishri1 + 1;
|
||||
}
|
||||
else {
|
||||
hebrewMonth = 2;
|
||||
hebrewDate = inputDay - tishri1 - 29;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// We need the length of the year to figure this out,so find Tishri 1 of the next year.
|
||||
moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear];
|
||||
moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
|
||||
moladHalakim = moladHalakim % HALAKIM_PER_DAY;
|
||||
tishri1After = Tishri1((metonicYear + 1) % 19, moladDay, moladHalakim);
|
||||
}
|
||||
else {
|
||||
// It found Tishri 1 at the end of the year.
|
||||
hebrewYear = metonicCycle * 19 + metonicYear;
|
||||
if (inputDay >= tishri1 - 177) {
|
||||
// It is one of the last 6 months of the year.
|
||||
if (inputDay > tishri1 - 30) {
|
||||
hebrewMonth = 13;
|
||||
hebrewDate = inputDay - tishri1 + 30;
|
||||
}
|
||||
else if (inputDay > tishri1 - 60) {
|
||||
hebrewMonth = 12;
|
||||
hebrewDate = inputDay - tishri1 + 60;
|
||||
}
|
||||
else if (inputDay > tishri1 - 89) {
|
||||
hebrewMonth = 11;
|
||||
hebrewDate = inputDay - tishri1 + 89;
|
||||
}
|
||||
else if (inputDay > tishri1 - 119) {
|
||||
hebrewMonth = 10;
|
||||
hebrewDate = inputDay - tishri1 + 119;
|
||||
}
|
||||
else if (inputDay > tishri1 - 148) {
|
||||
hebrewMonth = 9;
|
||||
hebrewDate = inputDay - tishri1 + 148;
|
||||
}
|
||||
else {
|
||||
hebrewMonth = 8;
|
||||
hebrewDate = inputDay - tishri1 + 178;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (mpy[(hebrewYear - 1) % 19] == 13) {
|
||||
hebrewMonth = 7;
|
||||
hebrewDate = inputDay - tishri1 + 207;
|
||||
if (hebrewDate > 0)
|
||||
return;
|
||||
hebrewMonth--;
|
||||
hebrewDate += 30;
|
||||
if (hebrewDate > 0)
|
||||
return;
|
||||
hebrewMonth--;
|
||||
hebrewDate += 30;
|
||||
}
|
||||
else {
|
||||
hebrewMonth = 6;
|
||||
hebrewDate = inputDay - tishri1 + 207;
|
||||
if (hebrewDate > 0)
|
||||
return;
|
||||
hebrewMonth--;
|
||||
hebrewDate += 30;
|
||||
}
|
||||
if (hebrewDate > 0)
|
||||
return;
|
||||
hebrewMonth--;
|
||||
hebrewDate += 29;
|
||||
if (hebrewDate > 0)
|
||||
return;
|
||||
// We need the length of the year to figure this out,so find Tishri 1 of this year.
|
||||
tishri1After = tishri1;
|
||||
FindTishriMolad(moladDay - 365);
|
||||
tishri1 = Tishri1(metonicYear, moladDay, moladHalakim);
|
||||
}
|
||||
}
|
||||
yearLength = tishri1After - tishri1;
|
||||
moladDay = inputDay - tishri1 - 29;
|
||||
if (yearLength == 355 || yearLength == 385) {
|
||||
// Heshvan has 30 days
|
||||
if (moladDay <= 30) {
|
||||
hebrewMonth = 2;
|
||||
hebrewDate = moladDay;
|
||||
return;
|
||||
}
|
||||
moladDay -= 30;
|
||||
}
|
||||
else {
|
||||
// Heshvan has 29 days
|
||||
if (moladDay <= 29) {
|
||||
hebrewMonth = 2;
|
||||
hebrewDate = moladDay;
|
||||
return;
|
||||
}
|
||||
moladDay -= 29;
|
||||
}
|
||||
// It has to be Kislev.
|
||||
hebrewMonth = 3;
|
||||
hebrewDate = moladDay;
|
||||
}
|
||||
function FindTishriMolad(inputDay) {
|
||||
// Estimate the metonic cycle number. Note that this may be an under
|
||||
// estimate because there are 6939.6896 days in a metonic cycle not
|
||||
// 6940,but it will never be an over estimate. The loop below will
|
||||
// correct for any error in this estimate.
|
||||
metonicCycle = Math.floor((inputDay + 310) / 6940);
|
||||
// Calculate the time of the starting molad for this metonic cycle.
|
||||
MoladOfMetonicCycle();
|
||||
// If the above was an under estimate,increment the cycle number until
|
||||
// the correct one is found. For modern dates this loop is about 98.6%
|
||||
// likely to not execute,even once,because the above estimate is
|
||||
// really quite close.
|
||||
while (moladDay < inputDay - 6940 + 310) {
|
||||
metonicCycle++;
|
||||
moladHalakim += HALAKIM_PER_METONIC_CYCLE;
|
||||
moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
|
||||
moladHalakim = moladHalakim % HALAKIM_PER_DAY;
|
||||
}
|
||||
// Find the molad of Tishri closest to this date.
|
||||
for (metonicYear = 0; metonicYear < 18; metonicYear++) {
|
||||
if (moladDay > inputDay - 74)
|
||||
break;
|
||||
moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear];
|
||||
moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
|
||||
moladHalakim = moladHalakim % HALAKIM_PER_DAY;
|
||||
}
|
||||
}
|
||||
function MoladOfMetonicCycle() {
|
||||
var r1 = void 0, r2 = void 0, d1 = void 0, d2 = void 0;
|
||||
// Start with the time of the first molad after creation.
|
||||
r1 = NEW_MOON_OF_CREATION;
|
||||
// Calculate gMetonicCycle * HALAKIM_PER_METONIC_CYCLE. The upper 32
|
||||
// bits of the result will be in r2 and the lower 16 bits will be in r1.
|
||||
r1 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE & 0xFFFF);
|
||||
r2 = r1 >> 16;
|
||||
r2 += metonicCycle * (HALAKIM_PER_METONIC_CYCLE >> 16 & 0xFFFF);
|
||||
// Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1,the
|
||||
// upper 16 bits of the quotient will be in d2 and the lower 16 bits
|
||||
// will be in d1.
|
||||
d2 = Math.floor(r2 / HALAKIM_PER_DAY);
|
||||
r2 -= d2 * HALAKIM_PER_DAY;
|
||||
r1 = r2 << 16 | r1 & 0xFFFF;
|
||||
d1 = Math.floor(r1 / HALAKIM_PER_DAY);
|
||||
r1 -= d1 * HALAKIM_PER_DAY;
|
||||
moladDay = d2 << 16 | d1;
|
||||
moladHalakim = r1;
|
||||
}
|
||||
function Tishri1(metonicYear, moladDay, moladHalakim) {
|
||||
var tishri1 = moladDay, dow = tishri1 % 7, leapYear = metonicYear == 2 || metonicYear == 5 || metonicYear == 7 || metonicYear == 10 || metonicYear == 13 || metonicYear == 16 || metonicYear == 18, lastWasLeapYear = metonicYear == 3 || metonicYear == 6 || metonicYear == 8 || metonicYear == 11 || metonicYear == 14 || metonicYear == 17 || metonicYear == 0;
|
||||
// Apply rules 2,3 and 4
|
||||
if (moladHalakim >= NOON || !leapYear && dow == TUES && moladHalakim >= AM3_11_20 || lastWasLeapYear && dow == MON && moladHalakim >= AM9_32_43) {
|
||||
tishri1++;
|
||||
dow++;
|
||||
if (dow == 7)
|
||||
dow = 0;
|
||||
}
|
||||
// Apply rule 1 after the others because it can cause an additional delay of one day.
|
||||
if (dow == WED || dow == FRI || dow == SUN) {
|
||||
tishri1++;
|
||||
}
|
||||
return tishri1;
|
||||
}
|
||||
var inputYear = inputDateOrYear;
|
||||
if ((typeof inputYear === "undefined" ? "undefined" : _typeof(inputYear)) === "object") {
|
||||
inputMonth = inputDateOrYear.getMonth() + 1;
|
||||
inputDate = inputDateOrYear.getDate();
|
||||
inputYear = inputDateOrYear.getFullYear();
|
||||
}
|
||||
SdnToHebrew(GregorianToSdn(inputYear, inputMonth, inputDate));
|
||||
return {
|
||||
year: hebrewYear,
|
||||
month: hebrewMonth,
|
||||
date: hebrewDate,
|
||||
month_name: hMonth[hebrewMonth - 1]
|
||||
};
|
||||
}
|
||||
|
||||
exports.hebrewDate = hebrewDate;
|
|
@ -2,25 +2,19 @@
|
|||
"id": "hebrew_calendar",
|
||||
"name": "Hebrew Calendar",
|
||||
"shortName": "HebCal",
|
||||
"version": "0.04",
|
||||
"description": "lists the date according to the hebrew calendar",
|
||||
"version": "0.06",
|
||||
"description": "lists the date & holidays according to the hebrew calendar",
|
||||
"icon": "app.png",
|
||||
"allow_emulator": false,
|
||||
"tags": "tool,locale",
|
||||
"tags": "clocks,tools",
|
||||
"custom": "customizer.html",
|
||||
"supports": [
|
||||
"BANGLEJS",
|
||||
"BANGLEJS2"
|
||||
],
|
||||
"type": "clock",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{
|
||||
"name": "hebrew_calendar.app.js",
|
||||
"url": "app.js"
|
||||
},
|
||||
{
|
||||
"name": "hebrewDate",
|
||||
"url": "hebrewDate.js"
|
||||
},
|
||||
{
|
||||
"name": "hebrew_calendar.img",
|
||||
"url": "app-icon.js",
|
||||
|
|
Loading…
Reference in New Issue