Skip to content
Open
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ The `options` object has the following structure and defaults:
## Note about how zmanim are calculated
This library uses [Luxon](https://moment.github.io/luxon) as a date/time library, since
Javascript's `Date` object does not support setting timezones other than the system timezone.
All class methods that return a `DateTime` object will be in UTC.
All class methods that return a `Temporal.ZonedDateTime` object will be in UTC.

# Breaking changes from KosherJava
* `AstronomicalCalendar.getTemporalHour()` returns `null` instead of `Long.MIN_VALUE` if the calculations cannot be completed.
Expand Down
4,809 changes: 2,387 additions & 2,422 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
],
"dependencies": {
"big.js": "^6.1.1",
"luxon": "^1.26.0"
"temporal-polyfill": "^0.3.0"
},
"devDependencies": {
"@types/big.js": "^6.0.2",
Expand Down
118 changes: 62 additions & 56 deletions src/AstronomicalCalendar.ts

Large diffs are not rendered by default.

405 changes: 201 additions & 204 deletions src/ComplexZmanimCalendar.ts

Large diffs are not rendered by default.

79 changes: 40 additions & 39 deletions src/ZmanimCalendar.ts

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions src/hebrewcalendar/HebrewDateFormatter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTimeFormatOptions } from 'luxon';
import { Temporal } from 'temporal-polyfill';

import { Daf } from './Daf';
import { JewishDate } from './JewishDate';
Expand Down Expand Up @@ -56,7 +56,7 @@ export class HebrewDateFormatter {
/**
* The internal DateFormat.  See {@link #isLongWeekFormat()} and {@link #setLongWeekFormat(boolean)}.
*/
private weekFormat: DateTimeFormatOptions | null = { weekday: 'long' };
private weekFormat: Intl.DateTimeFormatOptions | null = { weekday: 'long' };

/**
* List of transliterated parshiyos using the default <em>Ashkenazi</em> pronounciation.&nbsp; The formatParsha method uses this
Expand Down Expand Up @@ -639,8 +639,8 @@ export class HebrewDateFormatter {

const dateTime = jewishDate.getDate();
return this.weekFormat
? dateTime.toLocaleString(this.weekFormat)
: dateTime.toISO();
? dateTime.toLocaleString('en-US', this.weekFormat)
: dateTime.toString();
}

/**
Expand Down Expand Up @@ -911,7 +911,8 @@ export class HebrewDateFormatter {
* @see #isHebrewFormat()
*
*/
public formatHebrewNumber(num: number): string {
public formatHebrewNumber(num0: number): string {
let num: number = num0;
if (num !== Math.trunc(num)) throw new IllegalArgumentException('number must be an integer.');

if (num < 0) {
Expand Down
40 changes: 20 additions & 20 deletions src/hebrewcalendar/JewishCalendar.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTime } from 'luxon';
import { Temporal } from 'temporal-polyfill';

import { GeoLocation } from '../util/GeoLocation';
import { Daf } from './Daf';
Expand Down Expand Up @@ -359,11 +359,11 @@ export class JewishCalendar extends JewishDate {
*/
constructor(jewishYear: number, jewishMonth: number, jewishDayOfMonth: number, inIsrael?: boolean)
constructor(date: Date)
constructor(date: DateTime)
constructor(date: Temporal.PlainDate)
constructor()
constructor(jewishYearOrDateTimeOrDate?: number | Date | DateTime, jewishMonth?: number, jewishDayOfMonth?: number, inIsrael?: boolean) {
constructor(jewishYearOrDateTime?: number | Date | Temporal.PlainDate, jewishMonth?: number, jewishDayOfMonth?: number, inIsrael?: boolean) {
// @ts-ignore
super(jewishYearOrDateTimeOrDate, jewishMonth, jewishDayOfMonth);
super(jewishYearOrDateTime, jewishMonth, jewishDayOfMonth);
if (inIsrael) this.setInIsrael(inIsrael);
}

Expand Down Expand Up @@ -1347,7 +1347,7 @@ export class JewishCalendar extends JewishDate {
*
* @return the Date representing the moment of the molad in Yerushalayim standard time (GMT + 2)
*/
public getMoladAsDate(): DateTime {
public getMoladAsDate(): Temporal.ZonedDateTime {
const molad: JewishDate = this.getMolad();
const locationName: string = 'Jerusalem, Israel';

Expand All @@ -1364,17 +1364,17 @@ export class JewishCalendar extends JewishDate {
// subtract local time difference of 20.94 minutes (20 minutes and 56.496 seconds) to get to Standard time
const milliseconds: number = Math.trunc(1000 * (moladSeconds - Math.trunc(moladSeconds)));

return DateTime.fromObject({
return Temporal.ZonedDateTime.from({
year: molad.getGregorianYear(),
month: molad.getGregorianMonth() + 1,
day: molad.getGregorianDayOfMonth(),
hour: molad.getMoladHours(),
minute: molad.getMoladMinutes(),
second: Math.trunc(moladSeconds),
millisecond: milliseconds,
zone: geo.getTimeZone(),
timeZone: geo.getTimeZone(),
})
.minus({ milliseconds: Math.trunc(geo.getLocalMeanTimeOffset()) });
.subtract({ milliseconds: Math.trunc(geo.getLocalMeanTimeOffset()) });
}

/**
Expand All @@ -1387,10 +1387,10 @@ export class JewishCalendar extends JewishDate {
* @see ComplexZmanimCalendar#getTchilasZmanKidushLevana3Days()
* @see ComplexZmanimCalendar#getTchilasZmanKidushLevana3Days(Date, Date)
*/
public getTchilasZmanKidushLevana3Days(): DateTime {
const molad: DateTime = this.getMoladAsDate();
public getTchilasZmanKidushLevana3Days(): Temporal.ZonedDateTime {
const molad: Temporal.ZonedDateTime = this.getMoladAsDate();

return molad.plus({ hours: 72 });
return molad.add({ hours: 72 });
}

/**
Expand All @@ -1405,10 +1405,10 @@ export class JewishCalendar extends JewishDate {
* @see ComplexZmanimCalendar#getTchilasZmanKidushLevana7Days()
* @see ComplexZmanimCalendar#getTchilasZmanKidushLevana7Days(Date, Date)
*/
public getTchilasZmanKidushLevana7Days(): DateTime {
const molad: DateTime = this.getMoladAsDate();
public getTchilasZmanKidushLevana7Days(): Temporal.ZonedDateTime {
const molad: Temporal.ZonedDateTime = this.getMoladAsDate();

return molad.plus({ hours: 168 });
return molad.add({ hours: 168 });
}

/**
Expand All @@ -1425,13 +1425,13 @@ export class JewishCalendar extends JewishDate {
* @see ComplexZmanimCalendar#getSofZmanKidushLevanaBetweenMoldos()
* @see ComplexZmanimCalendar#getSofZmanKidushLevanaBetweenMoldos(Date, Date)
*/
public getSofZmanKidushLevanaBetweenMoldos(): DateTime {
const molad: DateTime = this.getMoladAsDate();
public getSofZmanKidushLevanaBetweenMoldos(): Temporal.ZonedDateTime {
const molad: Temporal.ZonedDateTime = this.getMoladAsDate();

// add half the time between molad and molad (half of 29 days, 12 hours and 793 chalakim (44 minutes, 3.3
// seconds), or 14 days, 18 hours, 22 minutes and 666 milliseconds). Add it as hours, not days, to avoid
// DST/ST crossover issues.
return molad.plus({
return molad.add({
hours: (24 * 14) + 18,
minutes: 22,
seconds: 1,
Expand All @@ -1456,11 +1456,11 @@ export class JewishCalendar extends JewishDate {
* @see ComplexZmanimCalendar#getSofZmanKidushLevana15Days()
* @see ComplexZmanimCalendar#getSofZmanKidushLevana15Days(Date, Date)
*/
public getSofZmanKidushLevana15Days(): DateTime {
const molad: DateTime = this.getMoladAsDate();
public getSofZmanKidushLevana15Days(): Temporal.ZonedDateTime {
const molad: Temporal.ZonedDateTime = this.getMoladAsDate();

// 15 days after the molad. Add it as hours, not days, to avoid DST/ST crossover issues.
return molad.plus({ hours: 24 * 15 });
return molad.add({ hours: 24 * 15 });
}

/**
Expand Down
21 changes: 11 additions & 10 deletions src/hebrewcalendar/JewishDate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTime } from 'luxon';
import { Temporal } from 'temporal-polyfill';

import { Calendar, IntegerUtils } from '../polyfills/Utils';
import { IllegalArgumentException } from '../polyfills/errors';
Expand Down Expand Up @@ -939,17 +939,18 @@ export class JewishDate {
constructor(jewishYear: number, jewishMonth: number, jewishDayOfMonth: number)
constructor(molad: number)
constructor(date: Date)
constructor(date: DateTime)
constructor(date: Temporal.PlainDate)
constructor()
constructor(jewishYearOrDateTimeOrDateOrMolad?: number | Date | DateTime, jewishMonth?: number, jewishDayOfMonth?: number) {
constructor(jewishYearOrDateTimeOrDateOrMolad?: number | Date | Temporal.PlainDate, jewishMonth?: number, jewishDayOfMonth?: number) {
if (!jewishYearOrDateTimeOrDateOrMolad) {
this.resetDate();
} else if (jewishMonth) {
this.setJewishDate(jewishYearOrDateTimeOrDateOrMolad as number, jewishMonth, jewishDayOfMonth!);
} else if (jewishYearOrDateTimeOrDateOrMolad instanceof Date) {
this.setDate(DateTime.fromJSDate(jewishYearOrDateTimeOrDateOrMolad as Date));
} else if (DateTime.isDateTime(jewishYearOrDateTimeOrDateOrMolad)) {
this.setDate(jewishYearOrDateTimeOrDateOrMolad as DateTime);
const instant = Temporal.Instant.fromEpochMilliseconds(jewishYearOrDateTimeOrDateOrMolad.getTime());
this.setDate(instant.toZonedDateTimeISO('UTC').toPlainDate());
} else if (jewishYearOrDateTimeOrDateOrMolad instanceof Temporal.PlainDate) {
this.setDate(jewishYearOrDateTimeOrDateOrMolad as Temporal.PlainDate);
} else if (typeof jewishYearOrDateTimeOrDateOrMolad === 'number') {
const molad = jewishYearOrDateTimeOrDateOrMolad as number;
this.absDateToDate(JewishDate.moladToAbsDate(molad));
Expand Down Expand Up @@ -1028,7 +1029,7 @@ export class JewishDate {
* @throws IllegalArgumentException
* if the {@link Calendar#ERA} is {@link GregorianCalendar#BC}
*/
public setDate(date: DateTime): void {
public setDate(date: Temporal.PlainDate): void {
if (date.year < 1) {
throw new IllegalArgumentException(`Dates with a BC era are not supported. The year ${date.year} is invalid.`);
}
Expand Down Expand Up @@ -1183,8 +1184,8 @@ export class JewishDate {
*
* @return The {@link java.util.Calendar}
*/
public getDate(): DateTime {
return DateTime.fromObject({
public getDate(): Temporal.PlainDate {
return Temporal.PlainDate.from({
year: this.gregorianYear,
month: this.gregorianMonth,
day: this.gregorianDayOfMonth,
Expand All @@ -1195,7 +1196,7 @@ export class JewishDate {
* Resets this date to the current system date.
*/
public resetDate(): void {
this.setDate(DateTime.local());
this.setDate(Temporal.Now.plainDateISO());
}

/**
Expand Down
33 changes: 19 additions & 14 deletions src/hebrewcalendar/YerushalmiYomiCalculator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTime, Interval } from 'luxon';
import { Temporal } from 'temporal-polyfill';

import { Calendar } from '../polyfills/Utils';
import { Daf } from './Daf';
Expand All @@ -16,7 +16,7 @@ export class YerushalmiYomiCalculator {
/**
* The start date of the first Daf Yomi Yerushalmi cycle of February 2, 1980 / 15 Shevat, 5740.
*/
private static readonly DAF_YOMI_START_DAY: DateTime = DateTime.fromObject({
private static readonly DAF_YOMI_START_DAY: Temporal.PlainDate = Temporal.PlainDate.from({
year: 1980,
month: Calendar.FEBRUARY + 1,
day: 2,
Expand Down Expand Up @@ -53,9 +53,9 @@ export class YerushalmiYomiCalculator {
* if the date is prior to the February 2, 1980, the start of the first Daf Yomi Yerushalmi cycle
*/
public static getDafYomiYerushalmi(jewishCalendar: JewishCalendar): Daf | null {
let nextCycle: DateTime = YerushalmiYomiCalculator.DAF_YOMI_START_DAY;
let prevCycle: DateTime = YerushalmiYomiCalculator.DAF_YOMI_START_DAY;
const requested: DateTime = jewishCalendar.getDate();
let nextCycle: Temporal.PlainDate = YerushalmiYomiCalculator.DAF_YOMI_START_DAY;
let prevCycle: Temporal.PlainDate = YerushalmiYomiCalculator.DAF_YOMI_START_DAY;
const requested: Temporal.PlainDate = jewishCalendar.getDate();
let masechta: number = 0;
let dafYomi: Daf;

Expand All @@ -64,25 +64,25 @@ export class YerushalmiYomiCalculator {
return null;
}

if (requested < YerushalmiYomiCalculator.DAF_YOMI_START_DAY) {
if (Temporal.PlainDate.compare(requested, YerushalmiYomiCalculator.DAF_YOMI_START_DAY) < 0) {
throw new IllegalArgumentException(`${requested} is prior to organized Daf Yomi Yerushalmi cycles that started on ${YerushalmiYomiCalculator.DAF_YOMI_START_DAY}`);
}

// Start to calculate current cycle. Initialize the start day
// nextCycle = YerushalmiYomiCalculator.DAF_YOMI_START_DAY;

// Go cycle by cycle, until we get the next cycle
while (requested > nextCycle) {
while (Temporal.PlainDate.compare(requested, nextCycle) > 0) {
prevCycle = nextCycle;

// Adds the number of whole shas dafs, and then the number of days that not have daf.
nextCycle = nextCycle.plus({ days: YerushalmiYomiCalculator.WHOLE_SHAS_DAFS });
nextCycle = nextCycle.add({ days: YerushalmiYomiCalculator.WHOLE_SHAS_DAFS });
// This needs to be a separate step
nextCycle = nextCycle.plus({ days: YerushalmiYomiCalculator.getNumOfSpecialDays(prevCycle, nextCycle) });
nextCycle = nextCycle.add({ days: YerushalmiYomiCalculator.getNumOfSpecialDays(prevCycle, nextCycle) });
}

// Get the number of days from cycle start until request.
const dafNo: number = requested.diff(prevCycle, ['days']).days;
const dafNo: number = requested.since(prevCycle).days;

// Get the number of special days to subtract
const specialDays: number = YerushalmiYomiCalculator.getNumOfSpecialDays(prevCycle, requested);
Expand Down Expand Up @@ -110,7 +110,7 @@ export class YerushalmiYomiCalculator {
* @param end - end date to calculate at
* @return the number of special days between the start and end dates
*/
private static getNumOfSpecialDays(start: DateTime, end: DateTime): number {
private static getNumOfSpecialDays(start: Temporal.PlainDate, end: Temporal.PlainDate): number {
// Find the start and end Jewish years
const jewishStartYear: number = new JewishCalendar(start).getJewishYear();
const jewishEndYear: number = new JewishCalendar(end).getJewishYear();
Expand All @@ -127,9 +127,14 @@ export class YerushalmiYomiCalculator {
yomKippur.setJewishYear(i);
tishaBeav.setJewishYear(i);

const interval = Interval.fromDateTimes(start, end);
if (interval.contains(yomKippur.getDate())) specialDays++;
if (interval.contains(tishaBeav.getDate())) specialDays++;
const yk = yomKippur.getDate();
if (Temporal.PlainDate.compare(yk, start) >= 0 && Temporal.PlainDate.compare(yk, end) <= 0) {
specialDays++;
}
const av9 = tishaBeav.getDate();
if (Temporal.PlainDate.compare(av9, start) >= 0 && Temporal.PlainDate.compare(av9, end) <= 0) {
specialDays++;
}
}

return specialDays;
Expand Down
15 changes: 8 additions & 7 deletions src/hebrewcalendar/YomiCalculator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTime } from 'luxon';
import { Temporal } from 'temporal-polyfill';

import { Calendar } from '../polyfills/Utils';
import { Daf } from './Daf';
Expand All @@ -17,7 +17,7 @@ export class YomiCalculator {
/**
* The start date of the first Daf Yomi Bavli cycle of September 11, 1923 / Rosh Hashana 5684.
*/
private static readonly dafYomiStartDate: DateTime = DateTime.fromObject({
private static readonly dafYomiStartDate: Temporal.PlainDate = Temporal.PlainDate.from({
year: 1923,
month: Calendar.SEPTEMBER + 1,
day: 11,
Expand All @@ -30,7 +30,7 @@ export class YomiCalculator {
* The date that the pagination for the Daf Yomi <em>Maseches Shekalim</em> changed to use the commonly used Vilna
* Shas pagination from the no longer commonly available Zhitomir / Slavuta Shas used by Rabbi Meir Shapiro.
*/
private static readonly shekalimChangeDate: DateTime = DateTime.fromObject({ year: 1975, month: Calendar.JUNE + 1, day: 24 });
private static readonly shekalimChangeDate: Temporal.PlainDate = Temporal.PlainDate.from({ year: 1975, month: Calendar.JUNE + 1, day: 24 });

/** The Julian date that the cycle for Shekalim changed.
* @see #getDafYomiBavli(JewishCalendar) for details.
Expand Down Expand Up @@ -78,17 +78,18 @@ export class YomiCalculator {
const blattPerMasechta: number[] = [64, 157, 105, 121, 22, 88, 56, 40, 35, 31, 32, 29, 27, 122, 112, 91, 66, 49, 90, 82,
119, 119, 176, 113, 24, 49, 76, 14, 120, 110, 142, 61, 34, 34, 28, 22, 4, 9, 5, 73];

const date: DateTime = calendar.getDate();
const date: Temporal.PlainDate = calendar.getDate();

let dafYomi: Daf;
const julianDay: number = this.getJulianDay(date);
let cycleNo: number;
let dafNo: number;
if (date < YomiCalculator.dafYomiStartDate) {
if (Temporal.PlainDate.compare(date, YomiCalculator.dafYomiStartDate) < 0) {
// TODO: should we return a null or throw an IllegalArgumentException?
throw new IllegalArgumentException(`${calendar} is prior to organized Daf Yomi Bavli cycles that started on ${YomiCalculator.dafYomiStartDate}`);
}
if ((date > YomiCalculator.shekalimChangeDate) || date.equals(YomiCalculator.shekalimChangeDate)) {
if ((Temporal.PlainDate.compare(date, YomiCalculator.shekalimChangeDate) > 0) ||
date.equals(YomiCalculator.shekalimChangeDate)) {
cycleNo = 8 + ((julianDay - YomiCalculator.shekalimJulianChangeDay) / 2711);
dafNo = ((julianDay - YomiCalculator.shekalimJulianChangeDay) % 2711);
} else {
Expand Down Expand Up @@ -134,7 +135,7 @@ export class YomiCalculator {
* The Java Date
* @return the Julian day number corresponding to the date
*/
private static getJulianDay(date: DateTime): number {
private static getJulianDay(date: Temporal.PlainDate): number {
let { year, month } = date;
const { day } = date;

Expand Down
12 changes: 3 additions & 9 deletions src/kosher-zmanim.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as _Luxon from 'luxon';

import { Temporal } from 'temporal-polyfill';
import { GeoLocation } from './util/GeoLocation';
import { ZmanimCalendar } from './ZmanimCalendar';
import { ComplexZmanimCalendar } from './ComplexZmanimCalendar';
Expand All @@ -12,15 +11,15 @@ export function getZmanimJson(options: Options): JsonOutput {
const zmanimCalendar: ZmanimCalendar = options.complexZmanim
? new ComplexZmanimCalendar(geoLocation)
: new ZmanimCalendar(geoLocation);
zmanimCalendar.setDate(options.date || _Luxon.DateTime.local());
zmanimCalendar.setDate(options.date || Temporal.Now.plainDateISO());
return ZmanimFormatter.toJSON(zmanimCalendar);
}

export interface Options {
/**
* @default The current local date. The time is ignored.
*/
date?: Date | string | number | _Luxon.DateTime;
date?: Date | string | number | Temporal.PlainDate;
/**
* IANA timezone ID
*/
Expand Down Expand Up @@ -60,8 +59,3 @@ export * from './hebrewcalendar/YerushalmiYomiCalculator';

export * from './hebrewcalendar/HebrewDateFormatter';
export * from './util/ZmanimFormatter';

export const Luxon = _Luxon;

// Exported explicitly as a convenience.
export const DateTime = _Luxon.DateTime;
Loading