localBadiDate.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import * as MeeusSunMoon from 'meeussunmoon';
  2. import * as luxon from 'luxon';
  3. import { BadiDate, badiDateSettings as badiDateBaseSettings } from './badiDate';
  4. import { clockLocationFromPolygons, useClockLocations } from './clockLocations';
  5. import { BadiDateSettings, InputDate } from './types';
  6. /* eslint-disable complexity */
  7. class LocalBadiDate {
  8. private _badiDate: BadiDate;
  9. private _start: luxon.DateTime;
  10. private _sunrise: luxon.DateTime;
  11. private _solarNoon: luxon.DateTime;
  12. private _end: luxon.DateTime;
  13. private _clockLocation: string | undefined;
  14. private _holyDayCommemoration: luxon.DateTime | undefined;
  15. private _latitude: number;
  16. private _longitude: number;
  17. private _timezoneId: string;
  18. constructor(date: InputDate, latitude: number, longitude: number, timezoneId: string) {
  19. this._latitude = latitude;
  20. this._longitude = longitude;
  21. this._timezoneId = timezoneId;
  22. // If a datetime object is being passed, we use date and time, not just the
  23. // date. For a JS Date object, we can't assume it's in the correct timezone,
  24. // so in that case we use the date information only.
  25. this._badiDate = new BadiDate(this._setInputDateToCorrectDay(date, latitude, longitude));
  26. const gregDate = this._badiDate.gregorianDate.setZone(timezoneId, { keepLocalTime: true });
  27. this._clockLocation = clockLocationFromPolygons(latitude, longitude);
  28. if (!this._clockLocation ||
  29. (this._clockLocation === 'Finland' &&
  30. this._badiDate.month === 19)) {
  31. this._end = MeeusSunMoon.sunset(gregDate, latitude, longitude) as luxon.DateTime;
  32. this._solarNoon = MeeusSunMoon.solarNoon(gregDate, longitude);
  33. this._sunrise = MeeusSunMoon.sunrise(gregDate, latitude, longitude) as luxon.DateTime;
  34. this._start = MeeusSunMoon.sunset(gregDate.minus({ days: 1 }), latitude, longitude) as luxon.DateTime;
  35. } else {
  36. // First we set times to 18:00, 06:00, 12:00, 18:00, modifications are
  37. // then made depending on the region.
  38. this._start = gregDate.minus({ days: 1 }).set({ hour: 18 });
  39. this._solarNoon = gregDate.set({ hour: 12 });
  40. this._sunrise = gregDate.set({ hour: 6 });
  41. this._end = gregDate.set({ hour: 18 });
  42. if (this._clockLocation === 'Canada') {
  43. this._sunrise = this._sunrise.plus({ minutes: 30 });
  44. } else if (this._clockLocation === 'Iceland') {
  45. this._solarNoon = this._solarNoon.plus({ hours: 1 });
  46. } else if (this._clockLocation === 'Finland' ||
  47. this._clockLocation === 'USA') {
  48. if (this._end.isInDST) {
  49. this._sunrise = this._sunrise.plus({ hours: 1 });
  50. this._solarNoon = this._solarNoon.plus({ hours: 1 });
  51. this._end = this._end.plus({ hours: 1 });
  52. }
  53. if (this._start.isInDST) {
  54. this._start = this._start.plus({ hours: 1 });
  55. }
  56. }
  57. }
  58. switch (this._badiDate.holyDayNumber) {
  59. case 2:
  60. // First Day of Ridvan: 15:00 local standard time
  61. this._holyDayCommemoration = gregDate.set({ hour: gregDate.isInDST ? 16 : 15 });
  62. break;
  63. case 5:
  64. // Declaration of the Báb: 2 hours 11 minutes after sunset
  65. this._holyDayCommemoration = this._start.plus({ minutes: 131 });
  66. break;
  67. case 6:
  68. // Ascension of Bahá'u'lláh: 03:00 local standard time
  69. this._holyDayCommemoration = gregDate.set({ hour: gregDate.isInDST ? 4 : 3 });
  70. break;
  71. case 7:
  72. // Martyrdom of the Báb: solar noon
  73. this._holyDayCommemoration = this._solarNoon;
  74. break;
  75. case 11:
  76. // Ascension of 'Abdu'l-Bahá: 01:00 local standard time
  77. this._holyDayCommemoration = gregDate.set({ hour: gregDate.isInDST ? 2 : 1 });
  78. break;
  79. // skip default
  80. }
  81. }
  82. _setInputDateToCorrectDay(date: InputDate, latitude, longitude): InputDate {
  83. if (luxon.DateTime.isDateTime(date)) {
  84. const sunset = MeeusSunMoon.sunset(date, latitude, longitude);
  85. return (date > sunset) ? date.plus({ days: 1 }) : date;
  86. }
  87. return date;
  88. }
  89. get badiDate(): BadiDate {
  90. return this._badiDate;
  91. }
  92. get start(): luxon.DateTime {
  93. return this._start;
  94. }
  95. get sunrise(): luxon.DateTime {
  96. return this._sunrise;
  97. }
  98. get solarNoon(): luxon.DateTime {
  99. return this._solarNoon;
  100. }
  101. get end(): luxon.DateTime {
  102. return this._end;
  103. }
  104. get holyDayCommemoration(): luxon.DateTime | undefined {
  105. return this._holyDayCommemoration;
  106. }
  107. get clockLocation(): string | undefined {
  108. return this._clockLocation;
  109. }
  110. get latitude(): number {
  111. return this._latitude;
  112. }
  113. get longitude(): number {
  114. return this._longitude;
  115. }
  116. get timezoneId(): string {
  117. return this._timezoneId;
  118. }
  119. get nextMonth(): LocalBadiDate {
  120. return new LocalBadiDate(this.badiDate.nextMonth, this._latitude, this._longitude, this._timezoneId);
  121. }
  122. get previousMonth(): LocalBadiDate {
  123. return new LocalBadiDate(this.badiDate.previousMonth, this._latitude, this._longitude, this._timezoneId);
  124. }
  125. get nextDay(): LocalBadiDate {
  126. return new LocalBadiDate(this.badiDate.nextDay, this._latitude, this._longitude, this._timezoneId);
  127. }
  128. get previousDay(): LocalBadiDate {
  129. return new LocalBadiDate(this.badiDate.previousDay, this._latitude, this._longitude, this._timezoneId);
  130. }
  131. }
  132. const badiDateSettings = (settings: BadiDateSettings) => {
  133. if (typeof settings.defaultLanguage === 'string' ||
  134. typeof settings.underlineFormat === 'string') {
  135. badiDateBaseSettings(settings);
  136. }
  137. if (typeof settings.useClockLocations === 'boolean') {
  138. useClockLocations(settings.useClockLocations);
  139. }
  140. };
  141. MeeusSunMoon.settings({ returnTimeForNoEventCase: true, roundToNearestMinute: true });
  142. export { BadiDate, LocalBadiDate, badiDateSettings };