├── .gitignore ├── lib ├── zmanim-1.4.0alpha.jar ├── zmanimAstronomical-1.4.0alpha.jar └── readme.md ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── .github └── workflows │ ├── pull_request_worklow.yml │ └── codeql-analysis.yml ├── src ├── main │ └── java │ │ └── com │ │ └── kosherjava │ │ └── zmanim │ │ ├── util │ │ ├── package-info.java │ │ ├── Time.java │ │ ├── GeoLocationUtils.java │ │ ├── SunTimesCalculator.java │ │ ├── Zman.java │ │ ├── AstronomicalCalculator.java │ │ └── NOAACalculator.java │ │ ├── package-info.java │ │ └── hebrewcalendar │ │ ├── package-info.java │ │ ├── YerushalmiYomiCalculator.java │ │ ├── YomiCalculator.java │ │ └── Daf.java └── test │ └── java │ └── com │ └── kosherjava │ └── zmanim │ └── hebrewcalendar │ ├── UT_JewishDateNavigation.java │ ├── YomiCalculatorTest.java │ ├── UT_JewishLeapYear.java │ ├── package.html │ ├── UT_YerushalmiTest.java │ ├── UT_DaysInGregorianMonth.java │ ├── UT_DaysInJewishMonth.java │ └── UT_GregorianDateNavigation.java ├── SECURITY.md ├── gradlew.bat ├── README.md ├── pom.xml ├── gradlew ├── mvnw.cmd ├── mvnw └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | zmanim.iml 4 | .gradle 5 | build -------------------------------------------------------------------------------- /lib/zmanim-1.4.0alpha.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KosherJava/zmanim/HEAD/lib/zmanim-1.4.0alpha.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KosherJava/zmanim/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KosherJava/zmanim/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lib/zmanimAstronomical-1.4.0alpha.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KosherJava/zmanim/HEAD/lib/zmanimAstronomical-1.4.0alpha.jar -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | rootProject.name = 'zmanim' 6 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /lib/readme.md: -------------------------------------------------------------------------------- 1 | The latest Jar files can be downloaded from [Maven Central's KosherJava zmanim project](https://search.maven.org/artifact/com.kosherjava/zmanim). Click on the latest version and direct download of the Jar is available on the top right corner. The Jars available here are old legacy versions that need to be updated. 2 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_worklow.yml: -------------------------------------------------------------------------------- 1 | name: Run unit tests 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Check out Repository 8 | uses: actions/checkout@v4 9 | 10 | - name: Set up JDK 1.8 11 | uses: actions/setup-java@v4 12 | with: 13 | java-version: 8.0.232 14 | distribution: adopt 15 | 16 | - name: Run tests 17 | run: mvn test 18 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility classes for the Zmanim API including classes to calculate sun based times, {@link com.kosherjava.zmanim.util.GeoLocation location information}, 3 | * some {@link com.kosherjava.zmanim.util.ZmanimFormatter formatting} and {@link com.kosherjava.zmanim.util.GeoLocationUtils geographic location utilities}. Included in this package 4 | * are implementations for both the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO} and {@link com.kosherjava.zmanim.util.NOAACalculator NOAA / Jean Meeus} algorithms. 5 | * 6 | * @author © Eliyahu Hershfeld 2004 - 2022 7 | */ 8 | package com.kosherjava.zmanim.util; 9 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011. Jay R. Gindin 3 | */ 4 | 5 | package com.kosherjava.zmanim.hebrewcalendar; 6 | 7 | import org.junit.*; 8 | 9 | import java.util.Calendar; 10 | 11 | /** 12 | * 13 | */ 14 | @SuppressWarnings({ "MagicNumber" }) 15 | public class UT_JewishDateNavigation { 16 | 17 | 18 | @Test 19 | public void jewishForwardMonthToMonth() { 20 | 21 | JewishDate jewishDate = new JewishDate(); 22 | jewishDate.setJewishDate(5771, 1, 1); 23 | Assert.assertEquals(5, jewishDate.getGregorianDayOfMonth()); 24 | Assert.assertEquals(3, jewishDate.getGregorianMonth()); 25 | Assert.assertEquals(2011, jewishDate.getGregorianYear()); 26 | } 27 | 28 | 29 | @Test 30 | public void computeRoshHashana5771() { 31 | 32 | // At one point, this test was failing as the JewishDate class spun through a never-ending loop... 33 | 34 | JewishDate jewishDate = new JewishDate(); 35 | jewishDate.setJewishDate(5771, 7, 1); 36 | Assert.assertEquals(9, jewishDate.getGregorianDayOfMonth()); 37 | Assert.assertEquals(8, jewishDate.getGregorianMonth()); 38 | Assert.assertEquals(2010, jewishDate.getGregorianYear()); 39 | } 40 | 41 | 42 | } // End of UT_JewishDateNavigation class 43 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculatorTest.java: -------------------------------------------------------------------------------- 1 | package com.kosherjava.zmanim.hebrewcalendar; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class YomiCalculatorTest { 7 | private static HebrewDateFormatter hdf = new HebrewDateFormatter(); 8 | static { 9 | hdf.setHebrewFormat(true); 10 | } 11 | 12 | @Test 13 | public void testCorrectDaf1() { 14 | JewishCalendar jewishCalendar = new JewishCalendar(5685, JewishDate.KISLEV, 12); 15 | Daf daf = YomiCalculator.getDafYomiBavli(jewishCalendar); 16 | Assert.assertEquals(5, daf.getMasechtaNumber()); 17 | Assert.assertEquals(2, daf.getDaf()); 18 | System.out.println(hdf.formatDafYomiBavli(jewishCalendar.getDafYomiBavli())); 19 | } 20 | 21 | @Test 22 | public void testCorrectDaf2() { 23 | JewishCalendar jewishCalendar = new JewishCalendar(5736, JewishDate.ELUL, 26); 24 | Daf daf = YomiCalculator.getDafYomiBavli(jewishCalendar); 25 | Assert.assertEquals(4, daf.getMasechtaNumber()); 26 | Assert.assertEquals(14, daf.getDaf()); 27 | System.out.println(hdf.formatDafYomiBavli(jewishCalendar.getDafYomiBavli())); 28 | } 29 | 30 | @Test 31 | public void testCorrectDaf3() { 32 | JewishCalendar jewishCalendar = new JewishCalendar(5777, JewishDate.ELUL, 10); 33 | Daf daf = YomiCalculator.getDafYomiBavli(jewishCalendar); 34 | Assert.assertEquals(23, daf.getMasechtaNumber()); 35 | Assert.assertEquals(47, daf.getDaf()); 36 | System.out.println(hdf.formatDafYomiBavli(jewishCalendar.getDafYomiBavli())); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The KosherJava Zmanim library is an API for a specialized calendar that can calculate different 3 | * astronomical times including sunrise and sunset and Jewish zmanim or religious 4 | * times for prayers and other Jewish religious duties. These classes extend the {@link java.util.GregorianCalendar} and can therefore use the 5 | * standard Calendar functionality to change dates etc. For non-religious astronomical / solar calculations such as sunrise, sunset and twilight, use the {@link com.kosherjava.zmanim.AstronomicalCalendar}. The {@link com.kosherjava.zmanim.ZmanimCalendar} contains the most 8 | * commonly used zmanim or religious time calculations. For a much more extensive list of zmanim use the {@link com.kosherjava.zmanim.ComplexZmanimCalendar}. 9 | * Note: It is important to read the technical notes on top of the {@link com.kosherjava.zmanim.util.AstronomicalCalculator} documentation. 10 | *

Disclaimer:

I did my best to get accurate results using standardized astronomical calculations. Please use care when using the library 11 | * since people rely on the zmanim calculations for halacha lemaaseh. 12 | * @author © Eliyahu Hershfeld 2004 - 2022 13 | */ 14 | package com.kosherjava.zmanim; 15 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishLeapYear.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011. Jay R. Gindin 3 | */ 4 | 5 | package com.kosherjava.zmanim.hebrewcalendar; 6 | 7 | import org.junit.*; 8 | 9 | /** 10 | * Verify correct calculations of when a Hebrew leap year occurs. 11 | */ 12 | @SuppressWarnings({ "MagicNumber" }) 13 | public class UT_JewishLeapYear { 14 | 15 | 16 | @Test 17 | public void isLeapYear() { 18 | 19 | shouldBeLeapYear(5160); 20 | shouldNotBeLeapYear(5536); 21 | 22 | shouldNotBeLeapYear(5770); 23 | shouldBeLeapYear(5771); 24 | shouldNotBeLeapYear(5772); 25 | shouldNotBeLeapYear(5773); 26 | shouldBeLeapYear(5774); 27 | shouldNotBeLeapYear(5775); 28 | shouldBeLeapYear(5776); 29 | shouldNotBeLeapYear(5777); 30 | shouldNotBeLeapYear(5778); 31 | shouldBeLeapYear(5779); 32 | shouldNotBeLeapYear(5780); 33 | shouldNotBeLeapYear(5781); 34 | shouldBeLeapYear(5782); 35 | shouldNotBeLeapYear(5783); 36 | shouldBeLeapYear(5784); 37 | shouldNotBeLeapYear(5785); 38 | shouldNotBeLeapYear(5786); 39 | shouldBeLeapYear(5787); 40 | shouldNotBeLeapYear(5788); 41 | shouldNotBeLeapYear(5789); 42 | shouldBeLeapYear(5790); 43 | shouldNotBeLeapYear(5791); 44 | shouldNotBeLeapYear(5792); 45 | shouldBeLeapYear(5793); 46 | shouldNotBeLeapYear(5794); 47 | shouldBeLeapYear(5795); 48 | } 49 | 50 | 51 | private void shouldBeLeapYear(int year) { 52 | JewishDate jewishDate = new JewishDate(); 53 | jewishDate.setJewishYear(year); 54 | 55 | Assert.assertTrue(jewishDate.isJewishLeapYear( )); 56 | } 57 | 58 | 59 | private void shouldNotBeLeapYear(int year) { 60 | JewishDate jewishDate = new JewishDate(); 61 | jewishDate.setJewishYear(year); 62 | 63 | Assert.assertFalse(jewishDate.isJewishLeapYear( )); 64 | } 65 | 66 | } // End of UT_JewishLeapYear class 67 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policies and Procedures 2 | 3 | This document outlines security procedures and general policies for the `KosherJava Zmanim` 4 | project. 5 | 6 | * [Reporting a Bug](#reporting-a-bug) 7 | * [Disclosure Policy](#disclosure-policy) 8 | * [Comments on this Policy](#comments-on-this-policy) 9 | 10 | ## Reporting a Bug 11 | 12 | The `KosherJava Zmanim` team and community take all security bugs in `KosherJava Zmanim` seriously. 13 | Thank you for improving the security of `KosherJava Zmanim`. We appreciate your efforts and 14 | responsible disclosure and will make every effort to acknowledge your 15 | contributions. 16 | 17 | Report security bugs by emailing the lead maintainer via the contact information at the [KosherJava.com contact page](https://kosherjava.com/contact/). 18 | 19 | The lead maintainer will attempt to acknowledge your email within 48 hours, and will try to send a 20 | more detailed response within 48 hours indicating the next steps in handling 21 | your report. After the initial reply to your report, the security team will 22 | endeavor to keep you informed of the progress towards a fix and full 23 | announcement, and may ask for additional information or guidance. 24 | 25 | ## Disclosure Policy 26 | 27 | When the security team receives a security bug report, they will assign it to a 28 | primary handler. This person will coordinate the fix and release process, 29 | involving the following steps: 30 | 31 | * Confirm the problem and determine the affected versions. 32 | * Audit code to find any potential similar problems. 33 | * Prepare fixes for all releases still under maintenance. These fixes will be 34 | released as fast as possible on this site. 35 | 36 | ## Comments on this Policy 37 | 38 | If you have suggestions on how this process could be improved please submit a 39 | pull request. 40 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/hebrewcalendar/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contain classes that represent a Jewish Date/Calendar, 3 | * and allows conversion between {@link com.kosherjava.zmanim.hebrewcalendar.JewishDate Jewish} and {@link java.util.GregorianCalendar Gregorian dates}. The main calendar 4 | * classes {@link com.kosherjava.zmanim.hebrewcalendar.JewishCalendar} and {@link com.kosherjava.zmanim.hebrewcalendar.JewishDate} 5 | * are based on Avrom Finkelstien's code, 6 | * refactored to fit the Zmanim API. The parsha and season-based tefila change code was ported by Y. Paritcher from his 7 | * libzmanim code. 8 | * 9 | *

Design:

10 | * 18 | * @author © Eliyahu Hershfeld 2011 - 2022 19 | */ 20 | package com.kosherjava.zmanim.hebrewcalendar; 21 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/package.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | In writing these unit tests, I found http://www.printablejewishcalendar.com/ which produces a nice output 8 | for each month. And, given that Cheshvan, Kislev and Adar are the only variable months, it was fairly easy 9 | to work out the following: 10 | 11 |
12 | Year   Cheshvan  Kislev  LEAP?   TYPE
13 | 5769   29        30      No      Qesidrah
14 | 5770   30        30      No      Shalem
15 | 5771   30        30      Yes     Shalem Leap
16 | 5772   29        30      No      Qesidrah
17 | 5773   29        29      No      Haser
18 | 5774   30        30      Yes     Shalem Leap
19 | 5775   29        30      No      Qesidrah
20 | 5776   30        30      Yes     Shalem Leap
21 | 5777   29        29      No      Haser
22 | 5778   29        30      No      Qesidrah
23 | 5779   30        30      Yes     Shalem Leap
24 | 5780   30        30      No      Shalem
25 | 5781   29        29      No      Haser
26 | 5782   29        30      Yes     Qesidrah Leap
27 | 5783   30        30      No      Shalem
28 | 5784   29        29      Yes     Qesidrah Leap
29 | 5785   30        30      No      Shalem
30 | 5786   29        30      No      Qesidrah
31 | 5787   30        30      Yes     Shalem Leap
32 | 5788   30        30      No      Shalem
33 | 5789   29        30      No      Qesidrah
34 | 5790   29        29      Yes     Haser Leap
35 | 5791   30        30      No      Shalem
36 | 5792   29        30      No      Qesidrah
37 | 5793   29        29      Yes     Haser Leap
38 | 5794   30        30      No      Shalem
39 | 5795   30        30      Yes     Shalem Leap
40 | 
41 | 42 | 43 | Another bit of help is just to have a listing of the Hebrew months. The API declares Nisan as the first month 44 | and Adar (or Adar II) as the last month of the year: 45 |
    46 |
  1. Nisan
  2. 47 |
  3. Iyar
  4. 48 |
  5. Sivan
  6. 49 |
  7. Tamuz
  8. 50 |
  9. Av
  10. 51 |
  11. Elul
  12. 52 |
  13. Tishri
  14. 53 |
  15. Cheshvan
  16. 54 |
  17. Kislev
  18. 55 |
  19. Tevet
  20. 56 |
  21. Shevat
  22. 57 |
  23. Adar
  24. 58 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java: -------------------------------------------------------------------------------- 1 | package com.kosherjava.zmanim.hebrewcalendar; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.junit.*; 6 | 7 | import junit.framework.TestCase; 8 | public class UT_YerushalmiTest { 9 | private static HebrewDateFormatter hdf = new HebrewDateFormatter(); 10 | static { 11 | hdf.setHebrewFormat(true); 12 | } 13 | 14 | @Test 15 | public void testCorrectDaf1() { 16 | JewishCalendar jewishCalendar = new JewishCalendar(5777,JewishCalendar.ELUL,10); 17 | Assert.assertEquals(8, jewishCalendar.getDafYomiYerushalmi().getDaf()); 18 | Assert.assertEquals(29, jewishCalendar.getDafYomiYerushalmi().getMasechtaNumber()); 19 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 20 | } 21 | 22 | @Test 23 | public void testCorrectDaf2() { 24 | JewishCalendar jewishCalendar = new JewishCalendar(5744,JewishCalendar.KISLEV,1); 25 | Assert.assertEquals(26, jewishCalendar.getDafYomiYerushalmi().getDaf()); 26 | Assert.assertEquals(32, jewishCalendar.getDafYomiYerushalmi().getMasechtaNumber()); 27 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 28 | } 29 | 30 | @Test 31 | public void testCorrectDaf3() { 32 | JewishCalendar jewishCalendar = new JewishCalendar(5782,JewishCalendar.SIVAN,1); 33 | Assert.assertEquals(15, jewishCalendar.getDafYomiYerushalmi().getDaf()); 34 | Assert.assertEquals(33, jewishCalendar.getDafYomiYerushalmi().getMasechtaNumber()); 35 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 36 | } 37 | 38 | @Test 39 | public void testCorrectSpecialDate() { 40 | JewishCalendar jewishCalendar = new JewishCalendar(5775,JewishCalendar.TISHREI,10); 41 | Assert.assertNull(jewishCalendar.getDafYomiYerushalmi()); 42 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 43 | 44 | jewishCalendar = new JewishCalendar(5783,JewishCalendar.AV,9); 45 | Assert.assertNull(jewishCalendar.getDafYomiYerushalmi()); 46 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 47 | 48 | jewishCalendar = new JewishCalendar(5775,JewishCalendar.AV,10);// 9 Av delayed to Sunday 10 Av 49 | Assert.assertNull(jewishCalendar.getDafYomiYerushalmi()); 50 | System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi())); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 5 * * 1' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['java'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v4 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v3 42 | with: 43 | languages: ${{ matrix.language }} 44 | # If you wish to specify custom queries, you can do so here or in a config file. 45 | # By default, queries listed here will override any specified in a config file. 46 | # Prefix the list here with "+" to use these queries and those in the config file. 47 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 48 | 49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 50 | # If this step fails, then you should remove it and run the build manually (see below) 51 | - name: Autobuild 52 | uses: github/codeql-action/autobuild@v3 53 | 54 | # ℹ️ Command-line programs to run using the OS shell. 55 | # 📚 https://git.io/JvXDl 56 | 57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 58 | # and modify them (or add more) to build your code if your project 59 | # uses a compiled language 60 | 61 | #- run: | 62 | # make bootstrap 63 | # make release 64 | 65 | - name: Perform CodeQL Analysis 66 | uses: github/codeql-action/analyze@v3 67 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInGregorianMonth.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011. Jay R. Gindin 3 | */ 4 | 5 | package com.kosherjava.zmanim.hebrewcalendar; 6 | 7 | import org.junit.*; 8 | 9 | import java.util.Calendar; 10 | 11 | /** 12 | * Verify the calculation of the number of days in a month. Not too hard...just the rules about when February 13 | * has 28 or 29 days... 14 | */ 15 | @SuppressWarnings({ "MagicNumber" }) 16 | public class UT_DaysInGregorianMonth { 17 | 18 | 19 | @Test 20 | public void testDaysInMonth() { 21 | 22 | JewishDate hebrewDate = new JewishDate(); 23 | 24 | Calendar cal = Calendar.getInstance(); 25 | cal.set(Calendar.YEAR, 2011); 26 | cal.set(Calendar.MONTH, Calendar.JANUARY); 27 | hebrewDate.setDate(cal); 28 | 29 | assertDaysInMonth(false, hebrewDate); 30 | } 31 | 32 | 33 | 34 | @Test 35 | public void testDaysInMonthLeapYear() { 36 | 37 | JewishDate hebrewDate = new JewishDate(); 38 | 39 | Calendar cal = Calendar.getInstance(); 40 | cal.set(Calendar.YEAR, 2012); 41 | cal.set(Calendar.MONTH, Calendar.JANUARY); 42 | hebrewDate.setDate(cal); 43 | 44 | assertDaysInMonth(true, hebrewDate); 45 | } 46 | 47 | 48 | @Test 49 | public void testDaysInMonth100Year() { 50 | 51 | JewishDate hebrewDate = new JewishDate(); 52 | 53 | Calendar cal = Calendar.getInstance(); 54 | cal.set(Calendar.YEAR, 2100); 55 | cal.set(Calendar.MONTH, Calendar.JANUARY); 56 | hebrewDate.setDate(cal); 57 | 58 | assertDaysInMonth(false, hebrewDate); 59 | } 60 | 61 | 62 | @Test 63 | public void testDaysInMonth400Year() { 64 | 65 | JewishDate hebrewDate = new JewishDate(); 66 | 67 | Calendar cal = Calendar.getInstance(); 68 | cal.set(Calendar.YEAR, 2000); 69 | cal.set(Calendar.MONTH, Calendar.JANUARY); 70 | hebrewDate.setDate(cal); 71 | 72 | assertDaysInMonth(true, hebrewDate); 73 | } 74 | 75 | 76 | private void assertDaysInMonth( 77 | boolean febIsLeap, 78 | JewishDate hebrewDate 79 | ) { 80 | 81 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(1)); 82 | Assert.assertEquals(febIsLeap ? 29 : 28, hebrewDate.getLastDayOfGregorianMonth(2)); 83 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(3)); 84 | Assert.assertEquals(30, hebrewDate.getLastDayOfGregorianMonth(4)); 85 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(5)); 86 | Assert.assertEquals(30, hebrewDate.getLastDayOfGregorianMonth(6)); 87 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(7)); 88 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(8)); 89 | Assert.assertEquals(30, hebrewDate.getLastDayOfGregorianMonth(9)); 90 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(10)); 91 | Assert.assertEquals(30, hebrewDate.getLastDayOfGregorianMonth(11)); 92 | Assert.assertEquals(31, hebrewDate.getLastDayOfGregorianMonth(12)); 93 | } 94 | 95 | 96 | } // End of UT_DaysInGregorianMonth class 97 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInJewishMonth.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011. Jay R. Gindin 3 | */ 4 | 5 | package com.kosherjava.zmanim.hebrewcalendar; 6 | 7 | import org.junit.*; 8 | 9 | /** 10 | * Validate the days in a Hebrew month (in various types of years) are correct. 11 | */ 12 | @SuppressWarnings({ "MagicNumber" }) 13 | public class UT_DaysInJewishMonth { 14 | 15 | @Test 16 | public void daysInMonthsInHaserYear() { 17 | 18 | assertHaser(5773); 19 | assertHaser(5777); 20 | assertHaser(5781); 21 | assertHaserLeap(5784); 22 | assertHaserLeap(5790); 23 | assertHaserLeap(5793); 24 | } 25 | 26 | 27 | @Test 28 | public void daysInMonthsInQesidrahYear() { 29 | 30 | assertQesidrah(5769); 31 | assertQesidrah(5772); 32 | assertQesidrah(5778); 33 | assertQesidrah(5786); 34 | assertQesidrah(5789); 35 | assertQesidrah(5792); 36 | 37 | assertQesidrahLeap(5782); 38 | } 39 | 40 | 41 | @Test 42 | public void daysInMonthsInShalemYear() { 43 | 44 | assertShalem(5770); 45 | assertShalem(5780); 46 | assertShalem(5783); 47 | assertShalem(5785); 48 | assertShalem(5788); 49 | assertShalem(5791); 50 | assertShalem(5794); 51 | 52 | assertShalemLeap(5771); 53 | assertShalemLeap(5774); 54 | assertShalemLeap(5776); 55 | assertShalemLeap(5779); 56 | assertShalemLeap(5787); 57 | assertShalemLeap(5795); 58 | } 59 | 60 | 61 | private void assertHaser(int year) { 62 | JewishDate jewishDate = new JewishDate(); 63 | jewishDate.setJewishYear(year); 64 | 65 | Assert.assertFalse(jewishDate.isCheshvanLong()); 66 | Assert.assertTrue(jewishDate.isKislevShort()); 67 | } 68 | 69 | 70 | private void assertHaserLeap(int year) { 71 | JewishDate jewishDate = new JewishDate(); 72 | jewishDate.setJewishYear(year); 73 | 74 | assertHaser(year); 75 | Assert.assertTrue(jewishDate.isJewishLeapYear()); 76 | } 77 | 78 | 79 | private void assertQesidrah(int year) { 80 | JewishDate jewishDate = new JewishDate(); 81 | jewishDate.setJewishYear(year); 82 | 83 | Assert.assertFalse(jewishDate.isCheshvanLong( )); 84 | Assert.assertFalse(jewishDate.isKislevShort( )); 85 | } 86 | 87 | 88 | private void assertQesidrahLeap(int year) { 89 | JewishDate jewishDate = new JewishDate(); 90 | jewishDate.setJewishYear(year); 91 | 92 | assertQesidrah(year); 93 | Assert.assertTrue(jewishDate.isJewishLeapYear( )); 94 | } 95 | 96 | 97 | private void assertShalem(int year) { 98 | JewishDate jewishDate = new JewishDate(); 99 | jewishDate.setJewishYear(year); 100 | 101 | Assert.assertTrue(jewishDate.isCheshvanLong( )); 102 | Assert.assertFalse(jewishDate.isKislevShort( )); 103 | } 104 | 105 | 106 | private void assertShalemLeap(int year) { 107 | JewishDate jewishDate = new JewishDate(); 108 | jewishDate.setJewishYear(year); 109 | 110 | assertShalem(year); 111 | Assert.assertTrue(jewishDate.isJewishLeapYear( )); 112 | } 113 | 114 | } // End of UT_DaysInJewishMonth class 115 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | KosherJava Zmanim API 2 | ===================== 3 | 4 | The Zmanim library is an API for a specialized calendar that can calculate different astronomical 5 | times including sunrise and sunset and Jewish _zmanim_ or religious times for prayers and other 6 | Jewish religious duties. 7 | 8 | These classes extend GregorianCalendar and can therefore 9 | use the standard Calendar functionality to change dates etc. For non religious astronomical / solar 10 | calculations use the [AstronomicalCalendar](./src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java). 11 | 12 | The ZmanimCalendar contains the most common zmanim or religious time calculations. For a much more 13 | extensive list of _zmanim_ use the ComplexZmanimCalendar. 14 | This class contains the main functionality of the Zmanim library. 15 | 16 | For a basic set of instructions on the use of the API, see [How to Use the Zmanim API](https://kosherjava.com/zmanim-project/how-to-use-the-zmanim-api/), [zmanim code samples](https://kosherjava.com/tag/code-sample/) and the [KosherJava FAQ](https://kosherjava.com/tag/faq/). See the KosherJava Zmanim site for additional information. 17 | 18 | # Get Started 19 | To add KosherJava as a dependency to your project, add the following dependency: 20 | 21 | #### Maven 22 | Add the following to your `pom.xml` file: 23 | ```xml 24 | 25 | com.kosherjava 26 | zmanim 27 | 2.5.0 28 | 29 | ``` 30 | 31 | #### Gradle 32 | Add the following to your `build.gradle` file: 33 | ```groovy 34 | implementation group: 'com.kosherjava', name: 'zmanim', version: '2.5.0' 35 | ``` 36 | Or if you have `build.gradle.kts` file: 37 | 38 | ```kotlin 39 | implementation("com.kosherjava:zmanim:2.5.0") 40 | ``` 41 | 42 | 43 | License 44 | ------- 45 | The library is released under the [LGPL 2.1 license](https://kosherjava.com/2011/05/09/kosherjava-zmanim-api-released-under-the-lgpl-license/). 46 | 47 | Ports to Other Languages 48 | ------------------------ 49 | The KosherJava Zmanim API has been ported to: 50 | * .NET - https://github.com/Yitzchok/Zmanim 51 | * C - https://github.com/yparitcher/libzmanim 52 | * Dart / Flutter - https://github.com/yakir8/kosher_dart 53 | * Go - https://github.com/vlipovetskii/go-zmanim 54 | * JavaScript - https://github.com/yparitcher/zmanJS 55 | * Kotlin - https://github.com/Sternbach-Software/KosherKotlin 56 | * Monkey C - https://github.com/5E7EN/Garmin-ZmanIQ/tree/rebuild-zmaniq/source/utils/zmanim 57 | * Objective-C - https://github.com/MosheBerman/KosherCocoa 58 | * PHP - https://github.com/zachweix/PhpZmanim/ 59 | * Python - https://github.com/pinnymz/python-zmanim & https://pypi.org/project/zmanim/ 60 | * Ruby - https://github.com/pinnymz/ruby-zmanim 61 | * Rust - https://github.com/dickermoshe/zmanim-core & https://github.com/YSCohen/rust-zmanim (WIP) 62 | * Scala - https://github.com/nafg/jewish-date 63 | * SQL - https://github.com/BehindTheMath/zmanim-sql (alpha quality). 64 | * Swift - https://github.com/Elyahu41/KosherSwift & https://github.com/DanielSmith1239/KosherSwift 65 | * TypeScript - https://github.com/BehindTheMath/KosherZmanim 66 | * VB6/VBA (Visual Basic) - https://github.com/diaphone1/vbzmanim 67 | 68 | ZmanCode Desktop App 69 | ------------------------ 70 | The .NET port was used to create a desktop app that is available at https://github.com/NykUser/MyZman. 71 | 72 | Disclaimer: 73 | ----------- 74 | __While I did my best to get accurate results, please double check before relying on these zmanim for halacha lemaaseh__. 75 | 76 | ------------------------ 77 | [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/KosherJava/zmanim?color=eed6af&label=KosherJava&logo=github)](https://search.maven.org/artifact/com.kosherjava/zmanim) 78 | [![GitHub](https://img.shields.io/github/license/KosherJava/zmanim?color=eed6af&logo=gnu)](https://github.com/KosherJava/zmanim/blob/master/LICENSE) 79 | [![GitHub last commit](https://img.shields.io/github/last-commit/KosherJava/zmanim?logo=github)](https://github.com/KosherJava/zmanim/commits/master) 80 | [![CodeQL](https://github.com/KosherJava/zmanim/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/KosherJava/zmanim/actions/workflows/codeql-analysis.yml) 81 | [![Run unit tests](https://github.com/KosherJava/zmanim/actions/workflows/pull_request_worklow.yml/badge.svg)](https://github.com/KosherJava/zmanim/actions/workflows/pull_request_worklow.yml) 82 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if (mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if (mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if (!outputFile.getParentFile().exists()) { 80 | if (!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.kosherjava 7 | zmanim 8 | 2.6.0-SNAPSHOT 9 | KosherJava Zmanim 10 | 11 | The Zmanim library is an API for a specialized calendar that can calculate different astronomical times 12 | including sunrise and sunset and Jewish zmanim or religious times for prayers and other Jewish religious duties. 13 | 14 | https://kosherjava.com/ 15 | 16 | 17 | GNU LESSER GENERAL PUBLIC LICENSE 18 | http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 19 | 20 | 21 | 2004 22 | 23 | 24 | Eliyahu Hershfeld 25 | ehershfeld@outlook.com 26 | Kosher Java 27 | https://kosherjava.com/ 28 | 29 | 30 | 31 | scm:git:git://github.com/KosherJava/zmanim.git 32 | scm:git:ssh://github.com:KosherJava/zmanim.git 33 | https://github.com/KosherJava/zmanim/tree/master 34 | 35 | 36 | 37 | junit 38 | junit 39 | 4.13.1 40 | test 41 | 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-source-plugin 48 | 2.2.1 49 | 50 | 51 | attach-sources 52 | 53 | jar-no-fork 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-javadoc-plugin 61 | 3.2.0 62 | 63 | 64 | 65 | todo 66 | a 67 | TODO: 68 | 69 | 70 | 71 | https://docs.oracle.com/en/java/javase/17/docs/api/ 72 | 73 | private 74 |
KosherJava.com]]>
75 | 76 | Copyright © {inceptionYear} - {currentYear} Eliyahu Hershfeld. All Rights Reserved. Released under the LGPL 2.1 license]]> 77 | utf-8 78 | true 79 | true 80 |
81 | 82 | 83 | attach-javadocs 84 | 85 | jar 86 | 87 | 88 | 89 |
90 | 91 | org.apache.maven.plugins 92 | maven-gpg-plugin 93 | 1.6 94 | 95 | 96 | sign-artifacts 97 | verify 98 | 99 | sign 100 | 101 | 102 | 103 | 104 | 105 | org.apache.maven.plugins 106 | maven-compiler-plugin 107 | 3.10.1 108 | 109 | UTF-8 110 | 8 111 | 8 112 | 113 | 114 |
115 |
116 | 117 | 118 | ossrh 119 | https://oss.sonatype.org/content/repositories/snapshots 120 | 121 | 122 | ossrh 123 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 124 | 125 | 126 | 127 | 8 128 | 8 129 | 130 |
131 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/Time.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | import java.util.TimeZone; 19 | 20 | /** 21 | * A class that represents a numeric time. Times that represent a time of day are stored as {@link java.util.Date}s in 22 | * this API. The time class is used to represent numeric time such as the time in hours, minutes, seconds and 23 | * milliseconds of a {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour}. 24 | * 25 | * @author © Eliyahu Hershfeld 2004 - 2025 26 | */ 27 | public class Time { 28 | /** milliseconds in a second. */ 29 | private static final int SECOND_MILLIS = 1000; 30 | 31 | /** milliseconds in a minute. */ 32 | private static final int MINUTE_MILLIS = SECOND_MILLIS * 60; 33 | 34 | /** milliseconds in an hour. */ 35 | private static final int HOUR_MILLIS = MINUTE_MILLIS * 60; 36 | 37 | /** 38 | * The hour. 39 | * @see #getHours() 40 | */ 41 | private int hours; 42 | 43 | /** 44 | * The minutes. 45 | * @see #getMinutes() 46 | */ 47 | private int minutes; 48 | 49 | /** 50 | * The seconds. 51 | * @see #getSeconds() 52 | */ 53 | private int seconds; 54 | 55 | /** 56 | * The milliseconds. 57 | * @see #getMilliseconds() 58 | */ 59 | private int milliseconds; 60 | 61 | /** 62 | * Is the time negative 63 | * @see #isNegative() 64 | * @see #setIsNegative(boolean) 65 | */ 66 | private boolean isNegative = false; 67 | 68 | /** 69 | * Constructor with parameters for the hours, minutes, seconds and milliseconds. 70 | * 71 | * @param hours the hours to set 72 | * @param minutes the minutes to set 73 | * @param seconds the seconds to set 74 | * @param milliseconds the milliseconds to set 75 | */ 76 | public Time(int hours, int minutes, int seconds, int milliseconds) { 77 | this.hours = hours; 78 | this.minutes = minutes; 79 | this.seconds = seconds; 80 | this.milliseconds = milliseconds; 81 | } 82 | 83 | /** 84 | * Constructor with a parameter for milliseconds. This constructor casts the milliseconds to an int and 85 | * calls {@link #Time(int)} 86 | * @param millis the milliseconds to set the object with. 87 | */ 88 | public Time(double millis) { 89 | this((int) millis); 90 | } 91 | 92 | /** 93 | * A constructor that sets the time from milliseconds. The milliseconds are converted to hours, minutes, 94 | * seconds and milliseconds. If the milliseconds are negative it will call {@link#setIsNegative(boolean)}. 95 | * @param millis the milliseconds to set. 96 | */ 97 | public Time(int millis) { 98 | int adjustedMillis = millis; 99 | if (adjustedMillis < 0) { 100 | this.isNegative = true; 101 | adjustedMillis = Math.abs(adjustedMillis); 102 | } 103 | this.hours = adjustedMillis / HOUR_MILLIS; 104 | adjustedMillis = adjustedMillis - this.hours * HOUR_MILLIS; 105 | 106 | this.minutes = adjustedMillis / MINUTE_MILLIS; 107 | adjustedMillis = adjustedMillis - this.minutes * MINUTE_MILLIS; 108 | 109 | this.seconds = adjustedMillis / SECOND_MILLIS; 110 | adjustedMillis = adjustedMillis - this.seconds * SECOND_MILLIS; 111 | 112 | this.milliseconds = adjustedMillis; 113 | } 114 | 115 | /** 116 | * Does the time represent a negative time, such as using this to subtract time from another Time. 117 | * @return if the time is negative. 118 | */ 119 | public boolean isNegative() { 120 | return this.isNegative; 121 | } 122 | 123 | /** 124 | * Set this to represent a negative time. 125 | * @param isNegative that the Time represents negative time 126 | */ 127 | public void setIsNegative(boolean isNegative) { 128 | this.isNegative = isNegative; 129 | } 130 | 131 | /** 132 | * Get the hour. 133 | * @return Returns the hour. 134 | */ 135 | public int getHours() { 136 | return this.hours; 137 | } 138 | 139 | /** 140 | * Set the hour. 141 | * @param hours 142 | * The hours to set. 143 | */ 144 | public void setHours(int hours) { 145 | this.hours = hours; 146 | } 147 | 148 | /** 149 | * Get the minutes. 150 | * @return Returns the minutes. 151 | */ 152 | public int getMinutes() { 153 | return this.minutes; 154 | } 155 | 156 | /** 157 | * Set the minutes. 158 | * @param minutes 159 | * The minutes to set. 160 | */ 161 | public void setMinutes(int minutes) { 162 | this.minutes = minutes; 163 | } 164 | 165 | /** 166 | * Get the seconds. 167 | * @return Returns the seconds. 168 | */ 169 | public int getSeconds() { 170 | return this.seconds; 171 | } 172 | 173 | /** 174 | * Set the seconds. 175 | * @param seconds 176 | * The seconds to set. 177 | */ 178 | public void setSeconds(int seconds) { 179 | this.seconds = seconds; 180 | } 181 | 182 | /** 183 | * Get the milliseconds. 184 | * @return Returns the milliseconds. 185 | */ 186 | public int getMilliseconds() { 187 | return this.milliseconds; 188 | } 189 | 190 | /** 191 | * Set the milliseconds. 192 | * @param milliseconds 193 | * The milliseconds to set. 194 | */ 195 | public void setMilliseconds(int milliseconds) { 196 | this.milliseconds = milliseconds; 197 | } 198 | 199 | /** 200 | * Returns the time in milliseconds by converting hours, minutes and seconds into milliseconds. 201 | * @return the time in milliseconds 202 | */ 203 | public double getTime() { 204 | return this.hours * HOUR_MILLIS + this.minutes * MINUTE_MILLIS + this.seconds * SECOND_MILLIS 205 | + this.milliseconds; 206 | } 207 | 208 | /** 209 | * @see java.lang.Object#toString() 210 | */ 211 | public String toString() { 212 | return new ZmanimFormatter(TimeZone.getTimeZone("UTC")).format(this); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2017 - 2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.hebrewcalendar; 17 | 18 | import java.util.Calendar; 19 | import java.util.GregorianCalendar; 20 | 21 | 22 | /** 23 | * This class calculates the Talmud Yerusalmi Daf Yomi page ({@link Daf}) for the a given date. 25 | * 26 | * @author © elihaidv 27 | * @author © Eliyahu Hershfeld 2017 - 2025 28 | */ 29 | public class YerushalmiYomiCalculator { 30 | 31 | /** 32 | * The start date of the first Daf Yomi Yerushalmi cycle of February 2, 1980 / 15 Shevat, 5740. 33 | */ 34 | private final static Calendar DAF_YOMI_START_DAY = new GregorianCalendar(1980, Calendar.FEBRUARY, 2); 35 | /** The number of milliseconds in a day. */ 36 | private final static int DAY_MILIS = 1000 * 60 * 60 * 24; 37 | /** The number of pages in the Talmud Yerushalmi.*/ 38 | private final static int WHOLE_SHAS_DAFS = 1554; 39 | /** The number of pages per masechta (tractate).*/ 40 | private final static int[] BLATT_PER_MASECHTA = { 41 | 68, 37, 34, 44, 31, 59, 26, 33, 28, 20, 13, 92, 65, 71, 22, 22, 42, 26, 26, 33, 34, 22, 42 | 19, 85, 72, 47, 40, 47, 54, 48, 44, 37, 34, 44, 9, 57, 37, 19, 13}; 43 | 44 | /** 45 | * Default constructor. 46 | */ 47 | public YerushalmiYomiCalculator() { 48 | // nothing here 49 | } 50 | 51 | /** 52 | * Returns the Daf Yomi 53 | * Yerusalmi page ({@link Daf}) for a given date. 54 | * The first Daf Yomi cycle started on 15 Shevat (Tu Bishvat), 5740 (February, 2, 1980) and calculations 55 | * prior to this date will result in an IllegalArgumentException thrown. A null will be returned on Tisha B'Av or 56 | * Yom Kippur. 57 | * 58 | * @param calendar 59 | * the calendar date for calculation 60 | * @return the {@link Daf} or null if the date is on Tisha B'Av or Yom Kippur. 61 | * 62 | * @throws IllegalArgumentException 63 | * if the date is prior to the February 2, 1980, the start of the first Daf Yomi Yerushalmi cycle 64 | */ 65 | public static Daf getDafYomiYerushalmi(JewishCalendar calendar) { 66 | 67 | Calendar nextCycle = new GregorianCalendar(); 68 | Calendar prevCycle = new GregorianCalendar(); 69 | Calendar requested = calendar.getGregorianCalendar(); 70 | int masechta = 0; 71 | Daf dafYomi = null; 72 | 73 | // There isn't Daf Yomi on Yom Kippur or Tisha B'Av. 74 | if ( calendar.getYomTovIndex() == JewishCalendar.YOM_KIPPUR || 75 | calendar.getYomTovIndex() == JewishCalendar.TISHA_BEAV ) { 76 | return null; 77 | } 78 | 79 | 80 | if (requested.before(DAF_YOMI_START_DAY)) { 81 | throw new IllegalArgumentException(requested + " is prior to organized Daf Yomi Yerushalmi cycles that started on " 82 | + DAF_YOMI_START_DAY); 83 | } 84 | 85 | // Start to calculate current cycle. init the start day 86 | nextCycle.setTime(DAF_YOMI_START_DAY.getTime()); 87 | 88 | // Go cycle by cycle, until we get the next cycle 89 | while (requested.after(nextCycle)) { 90 | prevCycle.setTime(nextCycle.getTime()); 91 | 92 | // Adds the number of whole shas dafs. and the number of days that not have daf. 93 | nextCycle.add(Calendar.DAY_OF_MONTH, WHOLE_SHAS_DAFS); 94 | nextCycle.add(Calendar.DAY_OF_MONTH, getNumOfSpecialDays(prevCycle, nextCycle)); 95 | } 96 | 97 | // Get the number of days from cycle start until request. 98 | int dafNo = (int)(getDiffBetweenDays(prevCycle, requested)); 99 | 100 | // Get the number of special day to subtract 101 | int specialDays = getNumOfSpecialDays(prevCycle, requested); 102 | int total = dafNo - specialDays; 103 | 104 | // Finally find the daf. 105 | for (int i : BLATT_PER_MASECHTA) { 106 | if (total < i) { 107 | dafYomi = new Daf(masechta, total + 1); 108 | break; 109 | } 110 | total -= i; 111 | masechta++; 112 | } 113 | 114 | return dafYomi; 115 | } 116 | 117 | /** 118 | * Return the number of special days (Yom Kippur and Tisha Beav, where there are no dafim), between the start date 119 | * (as a Calendar) and end date (also as a Calendar). 120 | * 121 | * @param start date to start calculating from 122 | * @param end date to finish calculating at 123 | * @return the number of special days between the start and end dates 124 | */ 125 | private static int getNumOfSpecialDays(Calendar start, Calendar end) { 126 | 127 | // Find the start and end Jewish years 128 | int startYear = new JewishCalendar(start).getJewishYear(); 129 | int endYear = new JewishCalendar(end).getJewishYear(); 130 | 131 | // Value to return 132 | int specialDays = 0; 133 | 134 | //Instant of special Dates 135 | JewishCalendar yom_kippur = new JewishCalendar(5770, 7, 10); 136 | JewishCalendar tisha_beav = new JewishCalendar(5770, 5, 9); 137 | 138 | // Go over the years and find special dates 139 | for (int i = startYear; i <= endYear; i++) { 140 | yom_kippur.setJewishYear(i); 141 | tisha_beav.setJewishYear(i); 142 | 143 | if (isBetween(start, yom_kippur.getGregorianCalendar(), end)) { 144 | specialDays++; 145 | } 146 | if (isBetween(start, tisha_beav.getGregorianCalendar(), end)) { 147 | specialDays++; 148 | } 149 | } 150 | 151 | return specialDays; 152 | } 153 | 154 | /** 155 | * Return if the date is between two dates 156 | * 157 | * @param start the start date 158 | * @param date the date being compared 159 | * @param end the end date 160 | * @return if the date is between the start and end dates 161 | */ 162 | private static boolean isBetween(Calendar start, Calendar date, Calendar end ) { 163 | return start.before(date) && end.after(date); 164 | } 165 | 166 | /** 167 | * Return the number of days between the dates passed in 168 | * @param start the start date 169 | * @param end the end date 170 | * @return the number of days between the start and end dates 171 | */ 172 | private static long getDiffBetweenDays(Calendar start, Calendar end) { 173 | return (end.getTimeInMillis() - start.getTimeInMillis()) / DAY_MILIS; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2011-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.hebrewcalendar; 17 | 18 | import java.util.Calendar; 19 | import java.util.GregorianCalendar; 20 | 21 | /** 22 | * This class calculates the Daf Yomi Bavli page (daf) for a given date. To calculate Daf Yomi Yerushalmi 23 | * use the {@link YerushalmiYomiCalculator}. The library may cover Mishna Yomi etc. at some point in the future. 24 | * 25 | * @author © Bob Newell (original C code) 26 | * @author © Eliyahu Hershfeld 2011 - 2025 27 | */ 28 | public class YomiCalculator { 29 | 30 | /** 31 | * The start date of the first Daf Yomi Bavli cycle of September 11, 1923 / Rosh Hashana 5684. 32 | */ 33 | private static final Calendar dafYomiStartDay = new GregorianCalendar(1923, Calendar.SEPTEMBER, 11); 34 | /** The start date of the first Daf Yomi Bavli cycle in the Julian calendar. Used internally for calculations.*/ 35 | private static final int dafYomiJulianStartDay = getJulianDay(dafYomiStartDay); 36 | /** 37 | * The date that the pagination for the Daf Yomi Maseches Shekalim changed to use the commonly used Vilna 38 | * Shas pagination from the no longer commonly available Zhitomir / Slavuta Shas used by Rabbi Meir Shapiro. 39 | */ 40 | private static final Calendar shekalimChangeDay = new GregorianCalendar(1975, Calendar.JUNE, 24); 41 | 42 | /** The Julian date that the cycle for Shekalim changed. 43 | * @see #getDafYomiBavli(JewishCalendar) for details. 44 | */ 45 | private static final int shekalimJulianChangeDay = getJulianDay(shekalimChangeDay); 46 | 47 | /** 48 | * Default constructor. 49 | */ 50 | public YomiCalculator() { 51 | // nothing here 52 | } 53 | 54 | /** 55 | * Returns the Daf Yomi Bavli {@link Daf} for a given date. The first Daf Yomi cycle 57 | * started on Rosh Hashana 5684 (September 11, 1923) and calculations prior to this date will result in an 58 | * IllegalArgumentException thrown. For historical calculations (supported by this method), it is important to note 59 | * that a change in length of the cycle was instituted starting in the eighth Daf Yomi cycle beginning on June 24, 60 | * 1975. The Daf Yomi Bavli cycle has a single masechta of the Talmud Yerushalmi - Shekalim as part of the cycle. 61 | * Unlike the Bavli where the number of daf per masechta was standardized since the original Bomberg Edition published from 1520 - 1523, there is no 63 | * uniform page length in the Yerushalmi. The early cycles had the Yerushalmi Shekalim length of 13 days following the 64 | * Slavuta/Zhytomyr 66 | * Shas used by Rabbi Meir Shapiro. With the start of the eighth Daf Yomi 67 | * cycle beginning on June 24, 1975, the length of the Yerushalmi Shekalim was changed from 13 to 22 daf to follow 68 | * the Vilna Shas that is in common use today. 69 | * 70 | * @param jewishCalendar 71 | * The JewishCalendar date for calculation. TODO: this can be changed to use a regular GregorianCalendar since 72 | * there is nothing specific to the JewishCalendar in this class. 73 | * @return the {@link Daf}. 74 | * 75 | * @throws IllegalArgumentException 76 | * if the date is prior to the September 11, 1923, the start date of the first Daf Yomi cycle. 77 | */ 78 | public static Daf getDafYomiBavli(JewishCalendar jewishCalendar) { 79 | /* 80 | * The number of daf per masechta. Since the number of blatt in Shekalim changed on the 8th Daf Yomi cycle 81 | * beginning on June 24, 1975, from 13 to 22, the actual calculation for blattPerMasechta[4] will later be 82 | * adjusted based on the cycle. 83 | */ 84 | int[] blattPerMasechta = { 64, 157, 105, 121, 22, 88, 56, 40, 35, 31, 32, 29, 27, 122, 112, 91, 66, 49, 90, 82, 85 | 119, 119, 176, 113, 24, 49, 76, 14, 120, 110, 142, 61, 34, 34, 28, 22, 4, 9, 5, 73 }; 86 | Calendar calendar = jewishCalendar.getGregorianCalendar(); 87 | 88 | Daf dafYomi = null; 89 | int julianDay = getJulianDay(calendar); 90 | int cycleNo; 91 | int dafNo; 92 | if (calendar.before(dafYomiStartDay)) { 93 | // TODO: should we return a null or throw an IllegalArgumentException? 94 | throw new IllegalArgumentException(calendar + " is prior to organized Daf Yomi Bavli cycles that started on " 95 | + dafYomiStartDay); 96 | } 97 | if (calendar.equals(shekalimChangeDay) || calendar.after(shekalimChangeDay)) { 98 | cycleNo = 8 + ((julianDay - shekalimJulianChangeDay) / 2711); 99 | dafNo = ((julianDay - shekalimJulianChangeDay) % 2711); 100 | } else { 101 | cycleNo = 1 + ((julianDay - dafYomiJulianStartDay) / 2702); 102 | dafNo = ((julianDay - dafYomiJulianStartDay) % 2702); 103 | } 104 | 105 | int total = 0; 106 | int masechta = -1; 107 | int blatt; 108 | 109 | // Fix Shekalim for old cycles. 110 | if (cycleNo <= 7) { 111 | blattPerMasechta[4] = 13; 112 | } 113 | 114 | // Finally find the daf. 115 | for (int i : blattPerMasechta) { 116 | masechta++; 117 | total = total + i - 1; 118 | if (dafNo < total) { 119 | blatt = 1 + i - (total - dafNo); 120 | // Fiddle with the weird ones near the end. 121 | if (masechta == 36) { 122 | blatt += 21; 123 | } else if (masechta == 37) { 124 | blatt += 24; 125 | } else if (masechta == 38) { 126 | blatt += 32; 127 | } 128 | dafYomi = new Daf(masechta, blatt); 129 | break; 130 | } 131 | } 132 | 133 | return dafYomi; 134 | } 135 | 136 | /** 137 | * Return the Julian day from a Java Calendar. 138 | * 139 | * @param calendar 140 | * The Java Calendar of the date to be calculated 141 | * @return the Julian day number corresponding to the date 142 | */ 143 | private static int getJulianDay(Calendar calendar) { 144 | int year = calendar.get(Calendar.YEAR); 145 | int month = calendar.get(Calendar.MONTH) + 1; 146 | int day = calendar.get(Calendar.DAY_OF_MONTH); 147 | if (month <= 2) { 148 | year -= 1; 149 | month += 12; 150 | } 151 | int a = year / 100; 152 | int b = 2 - a + a / 4; 153 | return (int) (Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + b - 1524.5); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_GregorianDateNavigation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011. Jay R. Gindin 3 | */ 4 | 5 | package com.kosherjava.zmanim.hebrewcalendar; 6 | 7 | import org.junit.*; 8 | 9 | import java.util.Calendar; 10 | 11 | /** 12 | * Checks that we can roll forward & backward the gregorian dates... 13 | */ 14 | @SuppressWarnings({ "MagicNumber" }) 15 | public class UT_GregorianDateNavigation { 16 | 17 | @Test 18 | public void gregorianForwardMonthToMonth() { 19 | 20 | Calendar cal = Calendar.getInstance(); 21 | cal.set(Calendar.YEAR, 2011); 22 | cal.set(Calendar.MONTH, Calendar.JANUARY); 23 | cal.set(Calendar.DATE, 31); 24 | 25 | JewishDate hebrewDate = new JewishDate(cal); 26 | Assert.assertEquals(5771, hebrewDate.getJewishYear()); 27 | Assert.assertEquals(11, hebrewDate.getJewishMonth()); 28 | Assert.assertEquals(26, hebrewDate.getJewishDayOfMonth()); 29 | 30 | hebrewDate.forward(Calendar.DATE, 1); 31 | Assert.assertEquals(1, hebrewDate.getGregorianMonth()); 32 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 33 | Assert.assertEquals(11, hebrewDate.getJewishMonth()); 34 | Assert.assertEquals(27, hebrewDate.getJewishDayOfMonth()); 35 | 36 | cal.set(Calendar.MONTH, Calendar.FEBRUARY); 37 | cal.set(Calendar.DATE, 28); 38 | hebrewDate.setDate(cal); 39 | Assert.assertEquals(1, hebrewDate.getGregorianMonth()); 40 | Assert.assertEquals(28, hebrewDate.getGregorianDayOfMonth()); 41 | Assert.assertEquals(12, hebrewDate.getJewishMonth()); 42 | Assert.assertEquals(24, hebrewDate.getJewishDayOfMonth()); 43 | 44 | hebrewDate.forward(Calendar.DATE, 1); 45 | Assert.assertEquals(2, hebrewDate.getGregorianMonth()); 46 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 47 | Assert.assertEquals(12, hebrewDate.getJewishMonth()); 48 | Assert.assertEquals(25, hebrewDate.getJewishDayOfMonth()); 49 | 50 | cal.set(Calendar.MONTH, Calendar.MARCH); 51 | cal.set(Calendar.DATE, 31); 52 | hebrewDate.setDate(cal); 53 | hebrewDate.forward(Calendar.DATE, 1); 54 | Assert.assertEquals(3, hebrewDate.getGregorianMonth()); 55 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 56 | Assert.assertEquals(13, hebrewDate.getJewishMonth()); 57 | Assert.assertEquals(26, hebrewDate.getJewishDayOfMonth()); 58 | 59 | cal.set(Calendar.MONTH, Calendar.APRIL); 60 | cal.set(Calendar.DATE, 30); 61 | hebrewDate.setDate(cal); 62 | hebrewDate.forward(Calendar.DATE, 1); 63 | Assert.assertEquals(4, hebrewDate.getGregorianMonth()); 64 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 65 | Assert.assertEquals(1, hebrewDate.getJewishMonth()); 66 | Assert.assertEquals(27, hebrewDate.getJewishDayOfMonth()); 67 | 68 | cal.set(Calendar.MONTH, Calendar.MAY); 69 | cal.set(Calendar.DATE, 31); 70 | hebrewDate.setDate(cal); 71 | hebrewDate.forward(Calendar.DATE, 1); 72 | Assert.assertEquals(5, hebrewDate.getGregorianMonth()); 73 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 74 | Assert.assertEquals(2, hebrewDate.getJewishMonth()); 75 | Assert.assertEquals(28, hebrewDate.getJewishDayOfMonth()); 76 | 77 | cal.set(Calendar.MONTH, Calendar.JUNE); 78 | cal.set(Calendar.DATE, 30); 79 | hebrewDate.setDate(cal); 80 | hebrewDate.forward(Calendar.DATE, 1); 81 | Assert.assertEquals(6, hebrewDate.getGregorianMonth()); 82 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 83 | Assert.assertEquals(3, hebrewDate.getJewishMonth()); 84 | Assert.assertEquals(29, hebrewDate.getJewishDayOfMonth()); 85 | 86 | cal.set(Calendar.MONTH, Calendar.JULY); 87 | cal.set(Calendar.DATE, 31); 88 | hebrewDate.setDate(cal); 89 | hebrewDate.forward(Calendar.DATE, 1); 90 | Assert.assertEquals(7, hebrewDate.getGregorianMonth()); 91 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 92 | Assert.assertEquals(5, hebrewDate.getJewishMonth()); 93 | Assert.assertEquals(1, hebrewDate.getJewishDayOfMonth()); 94 | 95 | cal.set(Calendar.MONTH, Calendar.AUGUST); 96 | cal.set(Calendar.DATE, 31); 97 | hebrewDate.setDate(cal); 98 | hebrewDate.forward(Calendar.DATE, 1); 99 | Assert.assertEquals(8, hebrewDate.getGregorianMonth()); 100 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 101 | Assert.assertEquals(6, hebrewDate.getJewishMonth()); 102 | Assert.assertEquals(2, hebrewDate.getJewishDayOfMonth()); 103 | 104 | cal.set(Calendar.MONTH, Calendar.SEPTEMBER); 105 | cal.set(Calendar.DATE, 30); 106 | hebrewDate.setDate(cal); 107 | hebrewDate.forward(Calendar.DATE, 1); 108 | Assert.assertEquals(9, hebrewDate.getGregorianMonth()); 109 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 110 | Assert.assertEquals(7, hebrewDate.getJewishMonth()); 111 | Assert.assertEquals(3, hebrewDate.getJewishDayOfMonth()); 112 | 113 | cal.set(Calendar.MONTH, Calendar.OCTOBER); 114 | cal.set(Calendar.DATE, 31); 115 | hebrewDate.setDate(cal); 116 | hebrewDate.forward(Calendar.DATE, 1); 117 | Assert.assertEquals(10, hebrewDate.getGregorianMonth()); 118 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 119 | Assert.assertEquals(5772, hebrewDate.getJewishYear()); 120 | Assert.assertEquals(8, hebrewDate.getJewishMonth()); 121 | Assert.assertEquals(4, hebrewDate.getJewishDayOfMonth()); 122 | 123 | cal.set(Calendar.MONTH, Calendar.NOVEMBER); 124 | cal.set(Calendar.DATE, 30); 125 | hebrewDate.setDate(cal); 126 | hebrewDate.forward(Calendar.DATE, 1); 127 | Assert.assertEquals(11, hebrewDate.getGregorianMonth()); 128 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 129 | Assert.assertEquals(9, hebrewDate.getJewishMonth()); 130 | Assert.assertEquals(5, hebrewDate.getJewishDayOfMonth()); 131 | 132 | cal.set(Calendar.MONTH, Calendar.DECEMBER); 133 | cal.set(Calendar.DATE, 31); 134 | hebrewDate.setDate(cal); 135 | hebrewDate.forward(Calendar.DATE, 1); 136 | Assert.assertEquals(2012, hebrewDate.getGregorianYear()); 137 | Assert.assertEquals(0, hebrewDate.getGregorianMonth()); 138 | Assert.assertEquals(1, hebrewDate.getGregorianDayOfMonth()); 139 | Assert.assertEquals(10, hebrewDate.getJewishMonth()); 140 | Assert.assertEquals(6, hebrewDate.getJewishDayOfMonth()); 141 | } 142 | 143 | 144 | @Test 145 | public void gregorianBackwardMonthToMonth() { 146 | 147 | Calendar cal = Calendar.getInstance(); 148 | cal.set(Calendar.YEAR, 2011); 149 | cal.set(Calendar.MONTH, Calendar.JANUARY); 150 | cal.set(Calendar.DATE, 1); 151 | 152 | JewishDate hebrewDate = new JewishDate(cal); 153 | hebrewDate.back(); 154 | Assert.assertEquals(2010, hebrewDate.getGregorianYear()); 155 | Assert.assertEquals(11, hebrewDate.getGregorianMonth()); 156 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 157 | Assert.assertEquals(10, hebrewDate.getJewishMonth()); 158 | Assert.assertEquals(24, hebrewDate.getJewishDayOfMonth()); 159 | 160 | cal.set(Calendar.DATE, 1); 161 | cal.set(Calendar.MONTH, Calendar.DECEMBER); 162 | cal.set(Calendar.YEAR, 2010); 163 | hebrewDate.setDate(cal); 164 | hebrewDate.back(); 165 | Assert.assertEquals(10, hebrewDate.getGregorianMonth()); 166 | Assert.assertEquals(30, hebrewDate.getGregorianDayOfMonth()); 167 | Assert.assertEquals(9, hebrewDate.getJewishMonth()); 168 | Assert.assertEquals(23, hebrewDate.getJewishDayOfMonth()); 169 | 170 | cal.set(Calendar.DATE, 1); 171 | cal.set(Calendar.MONTH, Calendar.NOVEMBER); 172 | hebrewDate.setDate(cal); 173 | hebrewDate.back(); 174 | Assert.assertEquals(9, hebrewDate.getGregorianMonth()); 175 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 176 | Assert.assertEquals(8, hebrewDate.getJewishMonth()); 177 | Assert.assertEquals(23, hebrewDate.getJewishDayOfMonth()); 178 | 179 | cal.set(Calendar.DATE, 1); 180 | cal.set(Calendar.MONTH, Calendar.OCTOBER); 181 | hebrewDate.setDate(cal); 182 | hebrewDate.back(); 183 | Assert.assertEquals(8, hebrewDate.getGregorianMonth()); 184 | Assert.assertEquals(30, hebrewDate.getGregorianDayOfMonth()); 185 | Assert.assertEquals(7, hebrewDate.getJewishMonth()); 186 | Assert.assertEquals(22, hebrewDate.getJewishDayOfMonth()); 187 | 188 | cal.set(Calendar.DATE, 1); 189 | cal.set(Calendar.MONTH, Calendar.SEPTEMBER); 190 | hebrewDate.setDate(cal); 191 | hebrewDate.back(); 192 | Assert.assertEquals(7, hebrewDate.getGregorianMonth()); 193 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 194 | Assert.assertEquals(5770, hebrewDate.getJewishYear()); 195 | Assert.assertEquals(6, hebrewDate.getJewishMonth()); 196 | Assert.assertEquals(21, hebrewDate.getJewishDayOfMonth()); 197 | 198 | cal.set(Calendar.DATE, 1); 199 | cal.set(Calendar.MONTH, Calendar.AUGUST); 200 | hebrewDate.setDate(cal); 201 | hebrewDate.back(); 202 | Assert.assertEquals(6, hebrewDate.getGregorianMonth()); 203 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 204 | Assert.assertEquals(5, hebrewDate.getJewishMonth()); 205 | Assert.assertEquals(20, hebrewDate.getJewishDayOfMonth()); 206 | 207 | cal.set(Calendar.DATE, 1); 208 | cal.set(Calendar.MONTH, Calendar.JULY); 209 | hebrewDate.setDate(cal); 210 | hebrewDate.back(); 211 | Assert.assertEquals(5, hebrewDate.getGregorianMonth()); 212 | Assert.assertEquals(30, hebrewDate.getGregorianDayOfMonth()); 213 | Assert.assertEquals(4, hebrewDate.getJewishMonth()); 214 | Assert.assertEquals(18, hebrewDate.getJewishDayOfMonth()); 215 | 216 | cal.set(Calendar.DATE, 1); 217 | cal.set(Calendar.MONTH, Calendar.JUNE); 218 | hebrewDate.setDate(cal); 219 | hebrewDate.back(); 220 | Assert.assertEquals(4, hebrewDate.getGregorianMonth()); 221 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 222 | Assert.assertEquals(3, hebrewDate.getJewishMonth()); 223 | Assert.assertEquals(18, hebrewDate.getJewishDayOfMonth()); 224 | 225 | cal.set(Calendar.DATE, 1); 226 | cal.set(Calendar.MONTH, Calendar.MAY); 227 | hebrewDate.setDate(cal); 228 | hebrewDate.back(); 229 | Assert.assertEquals(3, hebrewDate.getGregorianMonth()); 230 | Assert.assertEquals(30, hebrewDate.getGregorianDayOfMonth()); 231 | Assert.assertEquals(2, hebrewDate.getJewishMonth()); 232 | Assert.assertEquals(16, hebrewDate.getJewishDayOfMonth()); 233 | 234 | cal.set(Calendar.DATE, 1); 235 | cal.set(Calendar.MONTH, Calendar.APRIL); 236 | hebrewDate.setDate(cal); 237 | hebrewDate.back(); 238 | Assert.assertEquals(2, hebrewDate.getGregorianMonth()); 239 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 240 | Assert.assertEquals(1, hebrewDate.getJewishMonth()); 241 | Assert.assertEquals(16, hebrewDate.getJewishDayOfMonth()); 242 | 243 | cal.set(Calendar.DATE, 1); 244 | cal.set(Calendar.MONTH, Calendar.MARCH); 245 | hebrewDate.setDate(cal); 246 | hebrewDate.back(); 247 | Assert.assertEquals(1, hebrewDate.getGregorianMonth()); 248 | Assert.assertEquals(28, hebrewDate.getGregorianDayOfMonth()); 249 | Assert.assertEquals(12, hebrewDate.getJewishMonth()); 250 | Assert.assertEquals(14, hebrewDate.getJewishDayOfMonth()); 251 | 252 | cal.set(Calendar.DATE, 1); 253 | cal.set(Calendar.MONTH, Calendar.FEBRUARY); 254 | hebrewDate.setDate(cal); 255 | hebrewDate.back(); 256 | Assert.assertEquals(0, hebrewDate.getGregorianMonth()); 257 | Assert.assertEquals(31, hebrewDate.getGregorianDayOfMonth()); 258 | Assert.assertEquals(11, hebrewDate.getJewishMonth()); 259 | Assert.assertEquals(16, hebrewDate.getJewishDayOfMonth()); 260 | 261 | } 262 | 263 | 264 | 265 | } // End of UT_GregorianDateNavigation class 266 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/GeoLocationUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2020 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | /** 19 | * A class for various location calculations 20 | * Most of the code in this class is ported from Chris Veness' 21 | * LGPL Javascript Implementation 22 | * 23 | * @author © Eliyahu Hershfeld 2009 - 2020 24 | * @deprecated All methods in this call are available in the {@link GeoLocation} class, and this class that duplicates that 25 | * code will be removed in release 3.0. 26 | */ 27 | public class GeoLocationUtils { 28 | /** 29 | * Constant for a distance type calculation. 30 | * @see #getGeodesicDistance(GeoLocation, GeoLocation) 31 | */ 32 | private static int DISTANCE = 0; 33 | 34 | /** 35 | * Constant for a initial bearing type calculation. 36 | * @see #getGeodesicInitialBearing(GeoLocation, GeoLocation) 37 | */ 38 | private static int INITIAL_BEARING = 1; 39 | 40 | /** 41 | * Constant for a final bearing type calculation. 42 | * @see #getGeodesicFinalBearing(GeoLocation, GeoLocation) 43 | */ 44 | private static int FINAL_BEARING = 2; 45 | 46 | /** 47 | * Calculate the geodesic initial bearing between this Object and 48 | * a second Object passed to this method using Thaddeus 49 | * Vincenty's inverse formula See T Vincenty, "Direct and 50 | * Inverse Solutions of Geodesics on the Ellipsoid with application of nested equations", Survey Review, vol XXII 51 | * no 176, 1975. 52 | * 53 | * @param location 54 | * the initial location 55 | * @param destination 56 | * the destination location 57 | * @return the geodesic bearing 58 | */ 59 | public static double getGeodesicInitialBearing(GeoLocation location, GeoLocation destination) { 60 | return vincentyFormula(location, destination, INITIAL_BEARING); 61 | } 62 | 63 | /** 64 | * Calculate the geodesic final bearing between this Object 65 | * and a second Object passed to this method using Thaddeus Vincenty's 66 | * inverse formula See T Vincenty, "Direct and Inverse Solutions of Geodesics 67 | * on the Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975. 68 | * 69 | * @param location 70 | * the initial location 71 | * @param destination 72 | * the destination location 73 | * @return the geodesic bearing 74 | */ 75 | public static double getGeodesicFinalBearing(GeoLocation location, GeoLocation destination) { 76 | return vincentyFormula(location, destination, FINAL_BEARING); 77 | } 78 | 79 | /** 80 | * Calculate geodesic distance in Meters 81 | * between this Object and a second Object passed to this method using Thaddeus Vincenty's inverse formula See T Vincenty, 83 | * "Direct and Inverse Solutions of Geodesics on the 84 | * Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975. This uses the 85 | * WGS-84 geodetic model. 86 | * 87 | * @param location 88 | * the initial location 89 | * @param destination 90 | * the destination location 91 | * @return the geodesic distance in Meters 92 | */ 93 | public static double getGeodesicDistance(GeoLocation location, GeoLocation destination) { 94 | return vincentyFormula(location, destination, DISTANCE); 95 | } 96 | 97 | /** 98 | * Calculates the initial geodesic bearing, final bearing or 99 | * geodesic distance using Thaddeus Vincenty's inverse formula See T Vincenty, "Direct and Inverse Solutions of Geodesics on the Ellipsoid 102 | * with application of nested equations", Survey Review, vol XXII no 176, 1975. 103 | * 104 | * @param location 105 | * the initial location 106 | * @param destination 107 | * the destination location 108 | * @param formula 109 | * This formula calculates initial bearing ({@link #INITIAL_BEARING}), 110 | * final bearing ({@link #FINAL_BEARING}) and distance ({@link #DISTANCE}). 111 | * @return 112 | * the geodesic distance, initial or final bearing (based on the formula passed in) between the location 113 | * and destination in Meters 114 | * @see #getGeodesicDistance(GeoLocation, GeoLocation) 115 | * @see #getGeodesicInitialBearing(GeoLocation, GeoLocation) 116 | * @see #getGeodesicFinalBearing(GeoLocation, GeoLocation) 117 | */ 118 | private static double vincentyFormula(GeoLocation location, GeoLocation destination, int formula) { 119 | double a = 6378137; // length of semi-major axis of the ellipsoid (radius at equator) in metres based on WGS-84 120 | double b = 6356752.3142; // length of semi-minor axis of the ellipsoid (radius at the poles) in meters based on WGS-84 121 | double f = 1 / 298.257223563; // flattening of the ellipsoid based on WGS-84 122 | double L = Math.toRadians(destination.getLongitude() - location.getLongitude()); //difference in longitude of two points; 123 | double U1 = Math.atan((1 - f) * Math.tan(Math.toRadians(location.getLatitude()))); // reduced latitude (latitude on the auxiliary sphere) 124 | double U2 = Math.atan((1 - f) * Math.tan(Math.toRadians(destination.getLatitude()))); // reduced latitude (latitude on the auxiliary sphere) 125 | 126 | double sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); 127 | double sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); 128 | 129 | double lambda = L; 130 | double lambdaP = 2 * Math.PI; 131 | double iterLimit = 20; 132 | double sinLambda = 0; 133 | double cosLambda = 0; 134 | double sinSigma = 0; 135 | double cosSigma = 0; 136 | double sigma = 0; 137 | double sinAlpha = 0; 138 | double cosSqAlpha = 0; 139 | double cos2SigmaM = 0; 140 | double C; 141 | while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0) { 142 | sinLambda = Math.sin(lambda); 143 | cosLambda = Math.cos(lambda); 144 | sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) 145 | + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) 146 | * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); 147 | if (sinSigma == 0) 148 | return 0; // co-incident points 149 | cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; 150 | sigma = Math.atan2(sinSigma, cosSigma); 151 | sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; 152 | cosSqAlpha = 1 - sinAlpha * sinAlpha; 153 | cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; 154 | if (Double.isNaN(cos2SigmaM)) 155 | cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) 156 | C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); 157 | lambdaP = lambda; 158 | lambda = L 159 | + (1 - C) 160 | * f 161 | * sinAlpha 162 | * (sigma + C 163 | * sinSigma 164 | * (cos2SigmaM + C * cosSigma 165 | * (-1 + 2 * cos2SigmaM * cos2SigmaM))); 166 | } 167 | if (iterLimit == 0) 168 | return Double.NaN; // formula failed to converge 169 | 170 | double uSq = cosSqAlpha * (a * a - b * b) / (b * b); 171 | double A = 1 + uSq / 16384 172 | * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); 173 | double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); 174 | double deltaSigma = B 175 | * sinSigma 176 | * (cos2SigmaM + B 177 | / 4 178 | * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B 179 | / 6 * cos2SigmaM 180 | * (-3 + 4 * sinSigma * sinSigma) 181 | * (-3 + 4 * cos2SigmaM * cos2SigmaM))); 182 | double distance = b * A * (sigma - deltaSigma); 183 | 184 | // initial bearing 185 | double fwdAz = Math.toDegrees(Math.atan2(cosU2 * sinLambda, cosU1 186 | * sinU2 - sinU1 * cosU2 * cosLambda)); 187 | // final bearing 188 | double revAz = Math.toDegrees(Math.atan2(cosU1 * sinLambda, -sinU1 189 | * cosU2 + cosU1 * sinU2 * cosLambda)); 190 | if (formula == DISTANCE) { 191 | return distance; 192 | } else if (formula == INITIAL_BEARING) { 193 | return fwdAz; 194 | } else if (formula == FINAL_BEARING) { 195 | return revAz; 196 | } else { // should never happen 197 | return Double.NaN; 198 | } 199 | } 200 | 201 | /** 202 | * Returns the rhumb line 203 | * bearing from the current location to the GeoLocation passed in. 204 | * 205 | * @param location 206 | * the initial location 207 | * @param destination 208 | * the destination location 209 | * @return the bearing in degrees 210 | */ 211 | public static double getRhumbLineBearing(GeoLocation location, GeoLocation destination) { 212 | double dLon = Math.toRadians(destination.getLongitude() - location.getLongitude()); 213 | double dPhi = Math.log(Math.tan(Math.toRadians(destination.getLatitude()) 214 | / 2 + Math.PI / 4) 215 | / Math.tan(Math.toRadians(location.getLatitude()) / 2 + Math.PI / 4)); 216 | if (Math.abs(dLon) > Math.PI) 217 | dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); 218 | return Math.toDegrees(Math.atan2(dLon, dPhi)); 219 | } 220 | 221 | /** 222 | * Returns the rhumb line distance between two GeoLocations 223 | * passed in. Ported from Chris Veness' Javascript Implementation. 224 | * 225 | * @param location 226 | * the initial location 227 | * @param destination 228 | * the destination location 229 | * @return the distance in Meters 230 | */ 231 | public static double getRhumbLineDistance(GeoLocation location, GeoLocation destination) { 232 | double earthRadius = 6378137; // Earth's radius in meters (WGS-84) 233 | double dLat = Math.toRadians(location.getLatitude()) - Math.toRadians(destination.getLatitude()); 234 | double dLon = Math.abs(Math.toRadians(location.getLongitude()) - Math.toRadians(destination.getLongitude())); 235 | double dPhi = Math.log(Math.tan(Math.toRadians(location.getLatitude()) / 2 + Math.PI / 4) 236 | / Math.tan(Math.toRadians(destination.getLatitude()) / 2 + Math.PI / 4)); 237 | double q = dLat / dPhi; 238 | 239 | if (!(Math.abs(q) <= Double.MAX_VALUE)) { 240 | q = Math.cos(Math.toRadians(destination.getLatitude())); 241 | } 242 | // if dLon over 180° take shorter rhumb across 180° meridian: 243 | if (dLon > Math.PI) { 244 | dLon = 2 * Math.PI - dLon; 245 | } 246 | double d = Math.sqrt(dLat * dLat + q * q * dLon * dLon); 247 | return d * earthRadius; 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.0.0 (future) 2 | ### Includes breaking changes 3 | * Remove deprecated methods flagged for removal. 4 | * Remove deprecated classes such as the redundant [GeoLocationUtils](https://github.com/KosherJava/zmanim/blob/master/src/main/java/com/kosherjava/zmanim/util/GeoLocationUtils.java). 5 | * Possibly rename some classes such as the confusingly named [ComplexZmanimCalendar](https://github.com/KosherJava/zmanim/blob/master/src/main/java/com/kosherjava/zmanim/ComplexZmanimCalendar.java). 6 | * `getSofZman*Chametz*` times will retun null if it is not _Erev Pesach_. 7 | * Possibly increase the minimum supported JRE version from version 8 (the code currently almost certainly works on 6 today). 8 | * ... 9 | 10 | ## [2.6.0](https://github.com/KosherJava/zmanim/compare/2.5.0...master) (future) 11 | 12 | * `ZmanimCalendar` [Astronomical Chatzos based changes](https://github.com/KosherJava/zmanim/commit/c523424b327f173d70f024bdf207ccae0413d487): 13 | * Add setting `useAstronomicalChatzos` (defaulted to true) to keep the mistaken compat break introduced in the v2.5.0 release. 14 | * Add setting `useAstronomicalChatzosForOtherZmanim` (defaulted to false). 15 | * Add `getChatzosAsHalfDay()` to retain the old behavior of chatzos being halfway between sunrise and sunset. 16 | * Use `useAstronomicalChatzos` to control if `getChatzos()` returns `getSunTransit()` (astronomical chatzos) or getChatzosAsHalfDay(). 17 | * Add `getHalfDayBasedZman(Date startOfHalfDay, Date endOfHalfDay, double hours)` to allow other zmanim to be impacted by chatzos. 18 | * Use `useAstronomicalChatzosForOtherZmanim`. 19 | * `ZmanimCalendar` - add utility method [getPercentOfShaahZmanisFromDegrees(double degrees, boolean sunset)`](https://github.com/KosherJava/zmanim/commit/60d1f09322835835035afa507ac2dc852f1cb033) to simplify zmaniyos time calculations. This allows calculations of various percentage of the day zmanim calculations. 20 | * Use Astronomical Chatzos Halayla (as opposed as halfway between sunset and sunrise or 12 hours after chatzos hayom) 21 | * `AstronomicalCalculator` - [add `getSunLowerTransit()`](https://github.com/KosherJava/zmanim/commit/a76a3b65aeb45912bfdb02ce354f74bb97a9d9b2) 22 | * `AstronomicalCalculator` - [add abstract method `getUTCMidnight()`](https://github.com/KosherJava/zmanim/commit/f1904b12393c48b069d1333a7397fce66804958d) 23 | * `NOAACalculator` - [implement `getUTCMidnight()`](https://github.com/KosherJava/zmanim/commit/b93eea3388bfdcc2dd526bbcb1be37ddb88fee08) 24 | * `AstronomicalCalculator` - [add abstract method `getUTCMidnight()`](https://github.com/KosherJava/zmanim/commit/1223dd0b6ad2b492818aacc5eb478747989e0ace) 25 | * `ComplexZmanimCalendar` - [significant updates](https://github.com/KosherJava/zmanim/commit/46800aa750ac56c2da9bc55fbf976ea1a092221d) 26 | * Deprecate `getTzaisGeonim3Point65Degrees()` and `getTzaisGeonim3Point676Degrees()`, very early tzais geonim time that are earlier than 13.5 minutes in Yerushalayim at the equinox / equilux. 27 | * Started coding some zmanim to use the half-day zmanim config. 28 | * Deprecate `getFixedLocalChatzosBasedZmanim()` in favor of `getHalfDayBasedZman()` in the parent ZmanimCalendar class. 29 | * `getFixedLocalChatzos()` now just calls the new getLocalMeanTime(12.0) in the grandparent AstronomicalCalendar class. 30 | * Remove `getSolarMidnight()` that was added to the AstronomicalCalendar grandparent class. 31 | * Undeprecate `getPlagAlosToSunset()` since it is not a zman that can be too late. 32 | * Add [`getSofZmanAchilasChametzMGA72MinutesZmanis()` and `getSofZmanBiurChametzMGA72MinutesZmanis()`](https://github.com/KosherJava/zmanim/commit/c444fd3d1ae327560158b5f11c918a59c4eff55e) 33 | * [Add null checks in `getMinchaGedolaAhavatShalom()`](https://github.com/KosherJava/zmanim/commit/93f441f1ff87d4669c91b596eed157c9cf448bca) 34 | * [Fix `getAlos60()` to use `getElevationAdjustedSunrise()`](https://github.com/KosherJava/zmanim/commit/f5a5b2c68e1f0e2f9f4fbdd2cc585085f2914b74) 35 | * Update Tefila method to Use [Consistent Spelling](https://github.com/KosherJava/zmanim/commit/bca6ddb85542683f229d905636a06fbfc66fbe03). 36 | * `HebrewdateFormatter` 37 | * add method [`formatParsha(JewishCalendar.Parsha parsha)`](https://github.com/KosherJava/zmanim/commit/ee3347b04bf0f4221bc8aa71af59437cd7533f72) to allow formatting of a parsha retrieved from `JewishCalendar.getUpcomingParshah()`. 38 | * [Fix NullPointer in HebrewDateFormatter week formatting](https://github.com/KosherJava/zmanim/commit/6cef302f4ac815941c1f61765f2749d698f86042) 39 | * `TefilaRules` 40 | * [add `isMizmorLesodaRecited()`](https://github.com/KosherJava/zmanim/commit/2cde42644dc72a49b3e4228244bc79cc276e138e) 41 | * fix [Tachanun is not recited on Erev Rosh Hashana](https://github.com/KosherJava/zmanim/commit/0b6b95cfdebd14f19078875564b87068ed2623c4) 42 | * `JewishCalendar` 43 | * [`isYomTov()` now returns true for 20 Nissan](https://github.com/KosherJava/zmanim/commit/4e5abe6e98d5404f41da519f2f902b3af1e58e30) 44 | * [add missing brace to `isYomTov()` and simplify logic](https://github.com/KosherJava/zmanim/commit/e34fc879313b045f35e70b5947e2c2e20a4364c5) 45 | * `GeoLocation` - [add NaN validation to `setLatitude` and `setLongitude`](https://github.com/KosherJava/zmanim/commit/d064715ebeaead29a01ec673f3885ee9bd9c78b4) 46 | * `NOAACalculator` - [fix Solar Azimuth and Elevation](https://github.com/KosherJava/zmanim/commit/860f1939c25b38dd4d23adb1772b12ccbc71fc76) 47 | * `AstronomicalCalculator` - [add `getSolarAzimuth()` and `getSolarElevation()`](https://github.com/KosherJava/zmanim/commit/feecf7ad2d9ce527cfe0314ae01710d68c6c3c2e) 48 | * `AstronomicalCalendar` 49 | * [Fix null handling in `getSunTransit(Date,Date)`](https://github.com/KosherJava/zmanim/commit/8221e2895cbab62b037c16de1711f9faacd78a7b) 50 | * [Deprecate `getSunriseSolarDipFromOffset` and `getSunsetSolarDipFromOffset`](https://github.com/KosherJava/zmanim/commit/0ce858258bff15c11235b1f1063d2eb0ef22b994) 51 | * [Pass proper parameter to `getDateFromTime` in `getLocalMeanTime`](https://github.com/KosherJava/zmanim/commit/da7e888299c27622e1786af7d517f620060a38e0) 52 | * [Add `getLocalMeanTime()`](https://github.com/KosherJava/zmanim/commit/14bcdc085011ccce327f69d6a001772c0581fcc2). 53 | * [Move `getSolarMidnight()`](https://github.com/KosherJava/zmanim/commit/a4535717353eb77da10b6951e4a627b10258ac9e) to the parent class where it belongs. 54 | * [Correct USNO noon calculation](https://github.com/KosherJava/zmanim/commit/3735c92289a66039b24d7e2b470955b5297f0ca5) in some locations where it was sometimes 12 hours off. 55 | 56 | ## [2.5.0](https://github.com/KosherJava/zmanim/compare/2.4.0...2.5.0) (2023-06-09) 57 | 58 | * Update `ComplexZmanimCalendar.getSolarMidnight()` to support astronomocal midnight that works even in the Arctic/Antarctic. 59 | * Add special Shabbasos/Parshiyos Shuva, Shira, Hagadol, Chazon and Nachamu 60 | * Fix isYomTov() should return false on Erev Shavuos. 61 | * Correct spelling of Bein Hashmashos methods the the `ComplexZmanimCalendar` (was missing the second H). 62 | * Various Daf Yomi Yerushalmi fixes including: 63 | * Correct calculation of the _daf_ number. 64 | * Correct the order of transliterated Yerushalmi _masechtos_. 65 | * Correct the Hebrew spelling of the _masechta_ Kilayim. 66 | * Added number of IS methods such as is `isYomKippur()`, `isSuccos()`, `isPesach()` etc. to the `JewishCalendar` class. 67 | * Add `isAlHanissimRecited(JewishCalendar)` and `isYaalehVeyavoRecited(JewishCalendar)` to the `TefilaRules` class. 68 | * Clarify documentation to explain that isMacharChodesh() Refers to the Haftorah 69 | 70 | ## [2.4.0](https://github.com/KosherJava/zmanim/compare/2.3.0...2.4.0) (2022-11-27) 71 | 72 | * JewishCalendar.getUpcomingParshah() that will return the upcoming _Parsha_ regardless of the day of week. 73 | * Change YerushalmiYomiCalculator to return null on Yom Kippur and Tisha Be'Av when there is no Daf. 74 | * Add some Luach Ahavat Shalom Zmanim 75 | * Add _BeHaB_ to the `JewishCalendar`class 76 | * Add _Yom Kippur Katan_ and _Isru Chag_ to the `JewishCalendar`class. 77 | * Add the `TefilaRules` class, a utility class for info like: 78 | * is _vesain tal umatar_ recited etc. 79 | * is _tachanun_ recited by _shacharis_ or _mincha_. 80 | * Is _hallel_ or _hallel shalem_ recited 81 | * Deprecate the _tefila_ rules methods that existed in JewishCalendar class in favor of using the ones in the `TefilaRules` class. 82 | * Add `getSamuchLeMinchaKetana` _zman_. 83 | * Deprecate `getSofZmanShmaFixedLocal()` and `getSofZmanTfilaFixedLocal()` with future plans of removal. 84 | * Deprecate multiple "dangerous" _zmanim_ as an alert to developers, with plans on retaining them. 85 | 86 | ## [2.3.0](https://github.com/KosherJava/zmanim/compare/98d704...2.3.0) (2021-12-07) 87 | 88 | * Fix an issue with sof _zman kiddush levana_ being off by an hour when the _molad_ is on one side of the DST change, and the _sof zman_ on the other. 89 | * Add seasonal _davening_ based _zmanim_ including _Vesein Tal Umatar/ Vesein Berachah / Mashiv Haruach_. 90 | * Add Rav Moshe Feinstein's _zmanim_ used in MTJ and Yeshiva of Staten Island. 91 | * Refactor code for alos and _tzeis zmaniyos_ based time (ports to other languages can simplify things by doing the same). 92 | * Fix Hebrew spelling of _Parshas Nitzavim_. 93 | 94 | ## [2.2.0](https://github.com/KosherJava/zmanim/compare/2.1.0...98d704) (2021-03-15) 95 | 96 | * Added JewishCalendar.isTaanisBechoros(). 97 | * Updated Javadocs - document sources for `getFixedLocalChatzos()` and clarify _Yerushalmi Yomi_ Start Date. 98 | 99 | ## [2.1.0](https://github.com/KosherJava/zmanim/compare/8ffa53b9a...2.1.0) (2020-12-02) 100 | 101 | * Added six variants of the Yereim's _bain hashmashos zmanim_. 102 | * `AstronomicalCalculator.getRefraction()` and `.getSolarRadius()` now have public access. 103 | * Deprecate the `GeoLocationUtils` class. All of its functionality is in the `GeoLocation` class. 104 | * Updated JavaDocs (no more errors or warnings). 105 | * Added Lag Ba'omer. 106 | * Added Shushan Purim Katan. 107 | * Added `Daf.setMasechtaTransliterated(String[] masechtosBavliTransliterated)` and `Daf.setYerushlmiMasechtaTransliterated(String[] masechtosYerushalmiTransliterated)`. 108 | * Simplify and reduce code duplication in `ZmanimCalendar` generic _zmanim_ calculations. 109 | * Fix `AstronomicalCalendar` `getSunriseSolarDipFromOffset()` and `getSunsetSolarDipFromOffset` (they are still inefficient) to properly allow calculations before and after sun rise/set. 110 | * Change some Hebrew lists that are not expected to change to be final. 111 | 112 | ## [2.0.3] (2020-10-01) 113 | * Semver change (just a versioning change). 114 | 115 | ## [2.02] (2020-09-30) 116 | * Fix JavaDoc references to new package structure. 117 | 118 | ## [2.01] (2020-09-29) 119 | * Fix #160 `isShabbosMevorchim` should return false for the month of Tishrei. 120 | * Fix #161 a mistake in `Zman.toString()`. 121 | * Fix java 6 compilation issues. 122 | 123 | ## [2.0] (2020-08-03) 124 | 125 | * Changed package structure to `com.kosherjava.zmanim` from `net.sourceforge.zmanim`. 126 | * Added Maven and Gradle support. 127 | * Use DST for TimeZone display name (#150). 128 | * Convert `formatMolad()` to static. 129 | * Convert `getTimeOffset()` to static. 130 | * Pass alos and tzais parameters for `TchilasZmanKidushLevana3Days`. 131 | * Historical _daf yomi_ dates should be final. 132 | * Add _Birkas Hachama_, update documentation. 133 | * Update formatter class for Enums in `JewishCalendar`. 134 | 135 | 136 | ## Older Changes (since 1.3) 137 | 138 | * Default calculator changed from USNO to NOAA. 139 | * Remove the redundant `ZmanimCalculator` class (backwards breaking if you used this calculator). 140 | * Support optional elevation adjustments for zmanim besides sunrise and sunset. 141 | * Added multiple alternative zmanim . 142 | * Added Baal Hatanya _zmanim_. 143 | * Replaced GPL parsha code with an LGPL kosher version. 144 | * Added JSON serialization / output (was previously limited to XML). 145 | * Add _Daf Yomi Yerishalmi_. 146 | * Many `JewishCalendar` related tweaks and enhancements. 147 | * Many minor bug fixes and enhancements. 148 | 149 | See [GitHub Commits](https://github.com/KosherJava/zmanim/commits/master) for more details. 150 | 151 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/SunTimesCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | import java.util.Calendar; 19 | 20 | /** 21 | * Implementation of sunrise and sunset methods to calculate astronomical times. This calculator uses the Java algorithm 22 | * written by Kevin 23 | * Boone that is based on the US Naval Observatory'sAstronomical Almanac and used with his permission. Added to Kevin's 25 | * code is adjustment of the zenith to account for elevation. This algorithm returns the same time every year and does not 26 | * account for leap years. It is not as accurate as the Jean Meeus based {@link NOAACalculator} that is the default calculator 27 | * use by the KosherJava zmanim library. 28 | * 29 | * @author © Eliyahu Hershfeld 2004 - 2025 30 | * @author © Kevin Boone 2000 31 | */ 32 | public class SunTimesCalculator extends AstronomicalCalculator { 33 | 34 | /** 35 | * Default constructor of the SunTimesCalculator. 36 | */ 37 | public SunTimesCalculator() { 38 | super(); 39 | } 40 | 41 | /** 42 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getCalculatorName() 43 | */ 44 | public String getCalculatorName() { 45 | return "US Naval Almanac Algorithm"; 46 | } 47 | 48 | /** 49 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCSunrise(Calendar, GeoLocation, double, boolean) 50 | */ 51 | public double getUTCSunrise(Calendar calendar, GeoLocation geoLocation, double zenith, boolean adjustForElevation) { 52 | double elevation = adjustForElevation ? geoLocation.getElevation() : 0; 53 | double adjustedZenith = adjustZenith(zenith, elevation); 54 | return getTimeUTC(calendar, geoLocation, adjustedZenith, true); 55 | } 56 | 57 | /** 58 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCSunset(Calendar, GeoLocation, double, boolean) 59 | */ 60 | public double getUTCSunset(Calendar calendar, GeoLocation geoLocation, double zenith, boolean adjustForElevation) { 61 | double elevation = adjustForElevation ? geoLocation.getElevation() : 0; 62 | double adjustedZenith = adjustZenith(zenith, elevation); 63 | return getTimeUTC(calendar, geoLocation, adjustedZenith, false); 64 | } 65 | 66 | /** 67 | * The number of degrees of longitude that corresponds to one hour of time difference. 68 | */ 69 | private static final double DEG_PER_HOUR = 360.0 / 24.0; 70 | 71 | /** 72 | * The sine in degrees. 73 | * @param deg the degrees 74 | * @return sin of the angle in degrees 75 | */ 76 | private static double sinDeg(double deg) { 77 | return Math.sin(deg * 2.0 * Math.PI / 360.0); 78 | } 79 | 80 | /** 81 | * Return the arc cosine in degrees. 82 | * @param x angle 83 | * @return acos of the angle in degrees 84 | */ 85 | private static double acosDeg(double x) { 86 | return Math.acos(x) * 360.0 / (2 * Math.PI); 87 | } 88 | 89 | /** 90 | * Return the arc sine in degrees. 91 | * @param x angle 92 | * @return asin of the angle in degrees 93 | */ 94 | private static double asinDeg(double x) { 95 | return Math.asin(x) * 360.0 / (2 * Math.PI); 96 | } 97 | 98 | /** 99 | * Return the tangent in degrees. 100 | * @param deg degrees 101 | * @return tan of the angle in degrees 102 | */ 103 | private static double tanDeg(double deg) { 104 | return Math.tan(deg * 2.0 * Math.PI / 360.0); 105 | } 106 | 107 | /** 108 | * Calculate cosine of the angle in degrees 109 | * 110 | * @param deg degrees 111 | * @return cosine of the angle in degrees 112 | */ 113 | private static double cosDeg(double deg) { 114 | return Math.cos(deg * 2.0 * Math.PI / 360.0); 115 | } 116 | 117 | /** 118 | * Get time difference between location's longitude and the Meridian, in hours. 119 | * 120 | * @param longitude the longitude 121 | * @return time difference between the location's longitude and the Meridian, in hours. West of Meridian has a negative time difference 122 | */ 123 | private static double getHoursFromMeridian(double longitude) { 124 | return longitude / DEG_PER_HOUR; 125 | } 126 | 127 | /** 128 | * Calculate the approximate time of sunset or sunrise in days since midnight Jan 1st, assuming 6am and 6pm events. We 129 | * need this figure to derive the Sun's mean anomaly. 130 | * 131 | * @param dayOfYear the day of year 132 | * @param hoursFromMeridian hours from the meridian 133 | * @param isSunrise true for sunrise and false for sunset 134 | * 135 | * @return the approximate time of sunset or sunrise in days since midnight Jan 1st, assuming 6am and 6pm events. We 136 | * need this figure to derive the Sun's mean anomaly. 137 | */ 138 | private static double getApproxTimeDays(int dayOfYear, double hoursFromMeridian, boolean isSunrise) { 139 | if (isSunrise) { 140 | return dayOfYear + ((6.0 - hoursFromMeridian) / 24); 141 | } else { // sunset 142 | return dayOfYear + ((18.0 - hoursFromMeridian) / 24); 143 | } 144 | } 145 | 146 | /** 147 | * Calculate the Sun's mean anomaly in degrees, at sunrise or sunset, given the longitude in degrees 148 | * 149 | * @param dayOfYear the day of the year 150 | * @param longitude longitude 151 | * @param isSunrise true for sunrise and false for sunset 152 | * @return the Sun's mean anomaly in degrees 153 | */ 154 | private static double getMeanAnomaly(int dayOfYear, double longitude, boolean isSunrise) { 155 | return (0.9856 * getApproxTimeDays(dayOfYear, getHoursFromMeridian(longitude), isSunrise)) - 3.289; 156 | } 157 | 158 | /** 159 | * Returns the Sun's true longitude in degrees. 160 | * @param sunMeanAnomaly the Sun's mean anomaly in degrees 161 | * @return the Sun's true longitude in degrees. The result is an angle >= 0 and <= 360. 162 | */ 163 | private static double getSunTrueLongitude(double sunMeanAnomaly) { 164 | double l = sunMeanAnomaly + (1.916 * sinDeg(sunMeanAnomaly)) + (0.020 * sinDeg(2 * sunMeanAnomaly)) + 282.634; 165 | 166 | // get longitude into 0-360 degree range 167 | if (l >= 360.0) { 168 | l = l - 360.0; 169 | } 170 | if (l < 0) { 171 | l = l + 360.0; 172 | } 173 | return l; 174 | } 175 | 176 | /** 177 | * Calculates the Sun's right ascension in hours. 178 | * @param sunTrueLongitude the Sun's true longitude in degrees > 0 and < 360. 179 | * @return the Sun's right ascension in hours in angles > 0 and < 360. 180 | */ 181 | private static double getSunRightAscensionHours(double sunTrueLongitude) { 182 | double a = 0.91764 * tanDeg(sunTrueLongitude); 183 | double ra = 360.0 / (2.0 * Math.PI) * Math.atan(a); 184 | 185 | double lQuadrant = Math.floor(sunTrueLongitude / 90.0) * 90.0; 186 | double raQuadrant = Math.floor(ra / 90.0) * 90.0; 187 | ra = ra + (lQuadrant - raQuadrant); 188 | 189 | return ra / DEG_PER_HOUR; // convert to hours 190 | } 191 | 192 | /** 193 | * Calculate the cosine of the Sun's local hour angle 194 | * 195 | * @param sunTrueLongitude the sun's true longitude 196 | * @param latitude the latitude 197 | * @param zenith the zenith 198 | * @return the cosine of the Sun's local hour angle 199 | */ 200 | private static double getCosLocalHourAngle(double sunTrueLongitude, double latitude, double zenith) { 201 | double sinDec = 0.39782 * sinDeg(sunTrueLongitude); 202 | double cosDec = cosDeg(asinDeg(sinDec)); 203 | return (cosDeg(zenith) - (sinDec * sinDeg(latitude))) / (cosDec * cosDeg(latitude)); 204 | } 205 | 206 | /** 207 | * Calculate local mean time of rising or setting. By 'local' is meant the exact time at the location, assuming that 208 | * there were no time zone. That is, the time difference between the location and the Meridian depended entirely on 209 | * the longitude. We can't do anything with this time directly; we must convert it to UTC and then to a local time. 210 | * 211 | * @param localHour the local hour 212 | * @param sunRightAscensionHours the sun's right ascension in hours 213 | * @param approxTimeDays approximate time days 214 | * 215 | * @return the fractional number of hours since midnight as a double 216 | */ 217 | private static double getLocalMeanTime(double localHour, double sunRightAscensionHours, double approxTimeDays) { 218 | return localHour + sunRightAscensionHours - (0.06571 * approxTimeDays) - 6.622; 219 | } 220 | 221 | /** 222 | * Get sunrise or sunset time in UTC, according to flag. This time is returned as 223 | * a double and is not adjusted for time-zone. 224 | * 225 | * @param calendar 226 | * the Calendar object to extract the day of year for calculation 227 | * @param geoLocation 228 | * the GeoLocation object that contains the latitude and longitude 229 | * @param zenith 230 | * Sun's zenith, in degrees 231 | * @param isSunrise 232 | * True for sunrise and false for sunset. 233 | * @return the time as a double. If an error was encountered in the calculation 234 | * (expected behavior for some locations such as near the poles, 235 | * {@link Double#NaN} will be returned. 236 | */ 237 | private static double getTimeUTC(Calendar calendar, GeoLocation geoLocation, double zenith, boolean isSunrise) { 238 | int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); 239 | double sunMeanAnomaly = getMeanAnomaly(dayOfYear, geoLocation.getLongitude(), isSunrise); 240 | double sunTrueLong = getSunTrueLongitude(sunMeanAnomaly); 241 | double sunRightAscensionHours = getSunRightAscensionHours(sunTrueLong); 242 | double cosLocalHourAngle = getCosLocalHourAngle(sunTrueLong, geoLocation.getLatitude(), zenith); 243 | 244 | double localHourAngle; 245 | if (isSunrise) { 246 | localHourAngle = 360.0 - acosDeg(cosLocalHourAngle); 247 | } else { // sunset 248 | localHourAngle = acosDeg(cosLocalHourAngle); 249 | } 250 | double localHour = localHourAngle / DEG_PER_HOUR; 251 | 252 | double localMeanTime = getLocalMeanTime(localHour, sunRightAscensionHours, 253 | getApproxTimeDays(dayOfYear, getHoursFromMeridian(geoLocation.getLongitude()), isSunrise)); 254 | double pocessedTime = localMeanTime - getHoursFromMeridian(geoLocation.getLongitude()); 255 | return pocessedTime > 0 ? pocessedTime % 24 : pocessedTime % 24 + 24; // ensure that the time is >= 0 and < 24 256 | } 257 | 258 | /** 259 | * Return the Universal Coordinated Time (UTC) 260 | * of solar noon for the given day at the given location 261 | * on earth. This implementation returns solar noon as the time halfway between sunrise and sunset. 262 | * {@link NOAACalculator}, the default calculator, returns true solar noon. See The Definition of Chatzos for details on solar 264 | * noon calculations. 265 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation) 266 | * @see NOAACalculator 267 | * 268 | * @param calendar 269 | * The Calendar representing the date to calculate solar noon for 270 | * @param geoLocation 271 | * The location information used for astronomical calculating sun times. 272 | * @return the time in minutes from zero UTC. If an error was encountered in the calculation (expected behavior for 273 | * some locations such as near the poles, {@link Double#NaN} will be returned. 274 | */ 275 | public double getUTCNoon(Calendar calendar, GeoLocation geoLocation) { 276 | double sunrise = getUTCSunrise(calendar, geoLocation, 90, false); 277 | double sunset = getUTCSunset(calendar, geoLocation, 90, false); 278 | double noon = sunrise + ((sunset - sunrise) / 2); 279 | if (noon < 0) { 280 | noon += 12; 281 | } 282 | if (noon < sunrise) { 283 | noon -= 12; 284 | } 285 | return noon; 286 | } 287 | 288 | /** 289 | * Return the Universal Coordinated Time (UTC) 290 | * of midnight for the given day at the given location on earth. This implementation returns solar midnight as 12 hours 291 | * after utc noon that is halfway between sunrise and sunset. 292 | * {@link NOAACalculator}, the default calculator, returns true solar noon. See The Definition of Chatzos for details on solar 294 | * noon calculations. 295 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation) 296 | * @see NOAACalculator 297 | * 298 | * @param calendar 299 | * The Calendar representing the date to calculate solar noon for 300 | * @param geoLocation 301 | * The location information used for astronomical calculating sun times. 302 | * @return the time in minutes from zero UTC. If an error was encountered in the calculation (expected behavior for 303 | * some locations such as near the poles, {@link Double#NaN} will be returned. 304 | */ 305 | public double getUTCMidnight(Calendar calendar, GeoLocation geoLocation) { 306 | return (getUTCNoon(calendar, geoLocation) + 12); 307 | } 308 | 309 | /** 310 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getSolarAzimuth(Calendar, GeoLocation) 311 | */ 312 | public double getSolarAzimuth(Calendar calendar, GeoLocation geoLocation) { 313 | throw new UnsupportedOperationException("The SunTimesCalculator class does not implement the getSolarAzimuth method. Use the NOAACalculator instead."); 314 | } 315 | 316 | /** 317 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getSolarElevation(Calendar, GeoLocation) 318 | */ 319 | public double getSolarElevation(Calendar calendar, GeoLocation geoLocation) { 320 | throw new UnsupportedOperationException("The SunTimesCalculator class does not implement the getSolarElevation method. Use the NOAACalculator instead."); 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/Zman.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | import java.text.SimpleDateFormat; 19 | import java.util.Comparator; 20 | import java.util.Date; 21 | 22 | /** 23 | * A wrapper class for astronomical times / zmanim that is mostly intended to allow sorting collections of astronomical times. 24 | * It has fields for both date/time and duration based zmanim, name / labels as well as a longer description or explanation of a 25 | * zman. 26 | *

27 | * Here is an example of various ways of sorting zmanim. 28 | *

First create the Calendar for the location you would like to calculate: 29 | * 30 | *

 31 |  * String locationName = "Lakewood, NJ";
 32 |  * double latitude = 40.0828; // Lakewood, NJ
 33 |  * double longitude = -74.2094; // Lakewood, NJ
 34 |  * double elevation = 20; // optional elevation correction in Meters
 35 |  * // the String parameter in getTimeZone() has to be a valid timezone listed in {@link java.util.TimeZone#getAvailableIDs()}
 36 |  * TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
 37 |  * GeoLocation location = new GeoLocation(locationName, latitude, longitude, elevation, timeZone);
 38 |  * ComplexZmanimCalendar czc = new ComplexZmanimCalendar(location);
 39 |   * Zman sunset = new Zman(czc.getSunset(), "Sunset");
 40 |  * Zman shaah16 = new Zman(czc.getShaahZmanis16Point1Degrees(), "Shaah zmanis 16.1");
 41 |  * Zman sunrise = new Zman(czc.getSunrise(), "Sunrise");
 42 |  * Zman shaah = new Zman(czc.getShaahZmanisGra(), "Shaah zmanis GRA");
 43 |  * ArrayList<Zman> zl = new ArrayList<Zman>();
 44 |  * zl.add(sunset);
 45 |  * zl.add(shaah16);
 46 |  * zl.add(sunrise);
 47 |  * zl.add(shaah);
 48 |  * //will sort sunset, shaah 1.6, sunrise, shaah GRA
 49 |  * System.out.println(zl);
 50 |  * Collections.sort(zl, Zman.DATE_ORDER);
 51 |  * // will sort sunrise, sunset, shaah, shaah 1.6 (the last 2 are not in any specific order)
 52 |  * Collections.sort(zl, Zman.DURATION_ORDER);
 53 |  * // will sort sunrise, sunset (the first 2 are not in any specific order), shaah GRA, shaah 1.6
 54 |  * Collections.sort(zl, Zman.NAME_ORDER);
 55 |  * // will sort shaah 1.6, shaah GRA, sunrise, sunset
 56 |  * 
57 | * 58 | * @author © Eliyahu Hershfeld 2007-2025 59 | * @todo Add secondary sorting. As of now the {@code Comparator}s in this class do not sort by secondary order. This means that when sorting a 60 | * {@link java.util.Collection} of zmanim and using the {@link #DATE_ORDER} {@code Comparator} will have the duration based zmanim 61 | * at the end, but they will not be sorted by duration. This should be N/A for label based sorting. 62 | */ 63 | public class Zman { 64 | /** 65 | * The name / label of the zman. 66 | */ 67 | private String label; 68 | 69 | /** 70 | * The {@link Date} of the zman 71 | */ 72 | private Date zman; 73 | 74 | /** 75 | * The duration if the zman is a {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various 76 | * shaah zmanis base times such as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah Zmanis GRA} or 77 | * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() shaah Zmanis 16.1°}). 78 | */ 79 | private long duration; 80 | 81 | /** 82 | * A longer description or explanation of a zman. 83 | */ 84 | private String description; 85 | 86 | /** 87 | * The location information of the zman. 88 | */ 89 | private GeoLocation geoLocation; 90 | 91 | /** 92 | * The constructor setting a {@link Date} based zman and a label. In most cases you will likely want to call 93 | * {@link #Zman(Date, GeoLocation, String)} that also sets the location. 94 | * @param date the Date of the zman. 95 | * @param label the label of the zman such as "Sof Zman Krias Shema GRA". 96 | * @see #Zman(Date, GeoLocation, String) 97 | */ 98 | public Zman(Date date, String label) { 99 | this(date, null, label); 100 | } 101 | 102 | /** 103 | * The constructor setting a {@link Date} based zman and a label. In most cases you will likely want to call 104 | * {@link #Zman(Date, GeoLocation, String)} that also sets the geo location. 105 | * @param date the Date of the zman. 106 | * @param geoLocation the {@link GeoLocation} of the zman. 107 | * @param label the label of the zman such as "Sof Zman Krias Shema GRA". 108 | */ 109 | public Zman(Date date, GeoLocation geoLocation, String label) { 110 | this.zman = date; 111 | this.geoLocation = geoLocation; 112 | this.label = label; 113 | } 114 | 115 | /** 116 | * The constructor setting a duration based zman such as 117 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various shaah zmanis times such as 118 | * {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah zmanis GRA} or 119 | * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() shaah Zmanis 16.1°}) and label. 120 | * @param duration a duration based zman such as ({@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour()} 121 | * @param label the label of the zman such as "Shaah Zmanis GRA". 122 | * @see #Zman(Date, String) 123 | */ 124 | public Zman(long duration, String label) { 125 | this.label = label; 126 | this.duration = duration; 127 | } 128 | 129 | /** 130 | * Returns the {@code Date} based zman. 131 | * @return the zman. 132 | * @see #setZman(Date) 133 | */ 134 | public Date getZman() { 135 | return this.zman; 136 | } 137 | 138 | /** 139 | * Sets a {@code Date} based zman. 140 | * @param date a {@code Date} based zman 141 | * @see #getZman() 142 | */ 143 | public void setZman(Date date) { 144 | this.zman = date; 145 | } 146 | 147 | /** 148 | * Returns the {link TimeZone} of the zman. 149 | * @return the time zone 150 | */ 151 | public GeoLocation getGeoLocation() { 152 | return geoLocation; 153 | } 154 | 155 | /** 156 | * Sets the {@code GeoLocation} of the zman. 157 | * @param geoLocation the {@code GeoLocation} of the zman. 158 | */ 159 | public void setGeoLocation(GeoLocation geoLocation) { 160 | this.geoLocation = geoLocation; 161 | } 162 | 163 | /** 164 | * Returns a duration based zman such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} 165 | * (or the various shaah zmanis times such as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah zmanis GRA} 166 | * or {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() shaah zmanis 16.1°}). 167 | * @return the duration based zman. 168 | * @see #setDuration(long) 169 | */ 170 | public long getDuration() { 171 | return this.duration; 172 | } 173 | 174 | /** 175 | * Sets a duration based zman such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} 176 | * (or the various shaah zmanis times as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah zmanis GRA} or 177 | * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() shaah zmanis 16.1°}). 178 | * @param duration duration based zman such as {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour()}. 179 | * @see #getDuration() 180 | */ 181 | public void setDuration(long duration) { 182 | this.duration = duration; 183 | } 184 | 185 | /** 186 | * Returns the name / label of the zman such as "Sof Zman Krias Shema GRA". There are no automatically set labels 187 | * and you must set them using {@link #setLabel(String)}. 188 | * @return the name/label of the zman. 189 | * @see #setLabel(String) 190 | */ 191 | public String getLabel() { 192 | return this.label; 193 | } 194 | 195 | /** 196 | * Sets the name / label of the zman such as "Sof Zman Krias Shema GRA". 197 | * @param label the name / label to set for the zman. 198 | * @see #getLabel() 199 | */ 200 | public void setLabel(String label) { 201 | this.label = label; 202 | } 203 | 204 | /** 205 | * Returns the longer description or explanation of a zman. There is no default value for this and it must be set using 206 | * {@link #setDescription(String)} 207 | * @return the description or explanation of a zman. 208 | * @see #setDescription(String) 209 | */ 210 | public String getDescription() { 211 | return this.description; 212 | } 213 | 214 | /** 215 | * Sets the longer description or explanation of a zman. 216 | * @param description 217 | * the zman description to set. 218 | * @see #getDescription() 219 | */ 220 | public void setDescription(String description) { 221 | this.description = description; 222 | } 223 | 224 | /** 225 | * A {@link Comparator} that will compare and sort zmanim by date/time order. Compares its two arguments by the zman's date/time 226 | * order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater 227 | * than the second. 228 | * Please note that this class will handle cases where either the {@code Zman} is a null or {@link #getZman()} returns a null. 229 | */ 230 | public static final Comparator DATE_ORDER = new Comparator() { 231 | public int compare(Zman zman1, Zman zman2) { 232 | long firstTime = (zman1 == null || zman1.getZman() == null) ? Long.MAX_VALUE : zman1.getZman().getTime(); 233 | long secondTime = (zman2 == null || zman2.getZman() == null) ? Long.MAX_VALUE : zman2.getZman().getTime(); 234 | return Long.valueOf(firstTime).compareTo(Long.valueOf(secondTime)); 235 | } 236 | }; 237 | 238 | /** 239 | * A {@link Comparator} that will compare and sort zmanim by zmanim label order. Compares its two arguments by the zmanim label 240 | * name order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater 241 | * than the second. 242 | * Please note that this class will sort cases where either the {@code Zman} is a null or {@link #label} returns a null 243 | * as empty {@code String}s. 244 | */ 245 | public static final Comparator NAME_ORDER = new Comparator() { 246 | public int compare(Zman zman1, Zman zman2) { 247 | String firstLabel = (zman1 == null || zman1.getLabel() == null) ? "" : zman1.getLabel(); 248 | String secondLabel = (zman2 == null || zman2.getLabel() == null) ? "" : zman2.getLabel(); 249 | return firstLabel.compareTo(secondLabel); 250 | } 251 | }; 252 | 253 | /** 254 | * A {@link Comparator} that will compare and sort duration based zmanim such as 255 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getTemporalHour() temporal hour} (or the various shaah zmanis times 256 | * such as {@link com.kosherjava.zmanim.ZmanimCalendar#getShaahZmanisGra() shaah zmanis GRA} or 257 | * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getShaahZmanis16Point1Degrees() shaah zmanis 16.1°}). Returns a negative 258 | * integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. 259 | * Please note that this class will sort cases where {@code Zman} is a null. 260 | */ 261 | public static final Comparator DURATION_ORDER = new Comparator() { 262 | public int compare(Zman zman1, Zman zman2) { 263 | long firstDuration = zman1 == null ? Long.MAX_VALUE : zman1.getDuration(); 264 | long secondDuration = zman2 == null ? Long.MAX_VALUE : zman2.getDuration(); 265 | return firstDuration == secondDuration ? 0 : firstDuration > secondDuration ? 1 : -1; 266 | } 267 | }; 268 | 269 | /** 270 | * A method that returns an XML formatted String representing the serialized Object. Very 271 | * similar to the toString method but the return value is in an xml format. The format currently used (subject to 272 | * change) is: 273 | * 274 | *
275 | 	 * <Zman>
276 | 	 * 	<Label>Sof Zman Krias Shema GRA</Label>
277 | 	 * 	<Zman>1969-02-08T09:37:56.820</Zman>
278 | 	 * 	<TimeZone>
279 | 	 * 		<TimezoneName>America/Montreal</TimezoneName>
280 | 	 * 		<TimeZoneDisplayName>Eastern Standard Time</TimeZoneDisplayName>
281 | 	 * 		<TimezoneGMTOffset>-5</TimezoneGMTOffset>
282 | 	 * 		<TimezoneDSTOffset>1</TimezoneDSTOffset>
283 | 	 * 	</TimeZone>
284 | 	 * 	<Duration>0</Duration>
285 | 	 * 	<Description>Sof Zman Krias Shema GRA is 3 sha'os zmaniyos calculated from sunrise to sunset.</Description>
286 | 	 * </Zman>
287 | 	 * 
288 | * @return The XML formatted String. 289 | */ 290 | public String toXML() { 291 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 292 | StringBuilder sb = new StringBuilder(); 293 | sb.append("\n"); 294 | sb.append("\t\n"); 295 | sb.append("\t").append(getZman() == null ? "": formatter.format(getZman())).append("\n"); 296 | sb.append("\t" + getGeoLocation().toXML().replaceAll("\n", "\n\t")); 297 | sb.append("\n\t").append(getDuration()).append("\n"); 298 | sb.append("\t").append(getDescription()).append("\n"); 299 | sb.append(""); 300 | return sb.toString(); 301 | } 302 | 303 | /** 304 | * @see java.lang.Object#toString() 305 | */ 306 | public String toString() { 307 | StringBuilder sb = new StringBuilder(); 308 | sb.append("\nLabel:\t").append(this.getLabel()); 309 | sb.append("\nZman:\t").append(getZman()); 310 | sb.append("\nGeoLocation:\t").append(getGeoLocation().toString().replaceAll("\n", "\n\t")); 311 | sb.append("\nDuration:\t").append(getDuration()); 312 | sb.append("\nDescription:\t").append(getDescription()); 313 | return sb.toString(); 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/hebrewcalendar/Daf.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2011 - 2023 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | 17 | package com.kosherjava.zmanim.hebrewcalendar; 18 | 19 | /** 20 | * An Object representing a daf (page) in the Daf Yomi cycle. 21 | * 22 | * @author © Eliyahu Hershfeld 2011 - 2023 23 | */ 24 | public class Daf { 25 | /** 26 | * See {@link #getMasechtaNumber()} and {@link #setMasechtaNumber(int)}. 27 | */ 28 | private int masechtaNumber; 29 | 30 | /** 31 | * See {@link #getDaf()} and {@link #setDaf(int)}. 32 | */ 33 | private int daf; 34 | 35 | /** 36 | * See {@link #getMasechtaTransliterated()} and {@link #setMasechtaTransliterated(String[])}. 37 | */ 38 | private static String[] masechtosBavliTransliterated = { "Berachos", "Shabbos", "Eruvin", "Pesachim", "Shekalim", 39 | "Yoma", "Sukkah", "Beitzah", "Rosh Hashana", "Taanis", "Megillah", "Moed Katan", "Chagigah", "Yevamos", 40 | "Kesubos", "Nedarim", "Nazir", "Sotah", "Gitin", "Kiddushin", "Bava Kamma", "Bava Metzia", "Bava Basra", 41 | "Sanhedrin", "Makkos", "Shevuos", "Avodah Zarah", "Horiyos", "Zevachim", "Menachos", "Chullin", "Bechoros", 42 | "Arachin", "Temurah", "Kerisos", "Meilah", "Kinnim", "Tamid", "Midos", "Niddah" }; 43 | 44 | /** 45 | * See {@link #getMasechta()}. 46 | */ 47 | private static final String[] masechtosBavli = { "\u05D1\u05E8\u05DB\u05D5\u05EA", "\u05E9\u05D1\u05EA", 48 | "\u05E2\u05D9\u05E8\u05D5\u05D1\u05D9\u05DF", "\u05E4\u05E1\u05D7\u05D9\u05DD", 49 | "\u05E9\u05E7\u05DC\u05D9\u05DD", "\u05D9\u05D5\u05DE\u05D0", "\u05E1\u05D5\u05DB\u05D4", 50 | "\u05D1\u05D9\u05E6\u05D4", "\u05E8\u05D0\u05E9 \u05D4\u05E9\u05E0\u05D4", 51 | "\u05EA\u05E2\u05E0\u05D9\u05EA", "\u05DE\u05D2\u05D9\u05DC\u05D4", 52 | "\u05DE\u05D5\u05E2\u05D3 \u05E7\u05D8\u05DF", "\u05D7\u05D2\u05D9\u05D2\u05D4", 53 | "\u05D9\u05D1\u05DE\u05D5\u05EA", "\u05DB\u05EA\u05D5\u05D1\u05D5\u05EA", "\u05E0\u05D3\u05E8\u05D9\u05DD", 54 | "\u05E0\u05D6\u05D9\u05E8", "\u05E1\u05D5\u05D8\u05D4", "\u05D2\u05D9\u05D8\u05D9\u05DF", 55 | "\u05E7\u05D9\u05D3\u05D5\u05E9\u05D9\u05DF", "\u05D1\u05D1\u05D0 \u05E7\u05DE\u05D0", 56 | "\u05D1\u05D1\u05D0 \u05DE\u05E6\u05D9\u05E2\u05D0", "\u05D1\u05D1\u05D0 \u05D1\u05EA\u05E8\u05D0", 57 | "\u05E1\u05E0\u05D4\u05D3\u05E8\u05D9\u05DF", "\u05DE\u05DB\u05D5\u05EA", 58 | "\u05E9\u05D1\u05D5\u05E2\u05D5\u05EA", "\u05E2\u05D1\u05D5\u05D3\u05D4 \u05D6\u05E8\u05D4", 59 | "\u05D4\u05D5\u05E8\u05D9\u05D5\u05EA", "\u05D6\u05D1\u05D7\u05D9\u05DD", "\u05DE\u05E0\u05D7\u05D5\u05EA", 60 | "\u05D7\u05D5\u05DC\u05D9\u05DF", "\u05D1\u05DB\u05D5\u05E8\u05D5\u05EA", "\u05E2\u05E8\u05DB\u05D9\u05DF", 61 | "\u05EA\u05DE\u05D5\u05E8\u05D4", "\u05DB\u05E8\u05D9\u05EA\u05D5\u05EA", "\u05DE\u05E2\u05D9\u05DC\u05D4", 62 | "\u05E7\u05D9\u05E0\u05D9\u05DD", "\u05EA\u05DE\u05D9\u05D3", "\u05DE\u05D9\u05D3\u05D5\u05EA", 63 | "\u05E0\u05D3\u05D4" }; 64 | 65 | /** 66 | * See {@link #getYerushalmiMasechtaTransliterated()}. 67 | */ 68 | private static String[] masechtosYerushalmiTransliterated = { "Berachos", "Pe'ah", "Demai", "Kilayim", "Shevi'is", 69 | "Terumos", "Ma'asros", "Ma'aser Sheni", "Chalah", "Orlah", "Bikurim", "Shabbos", "Eruvin", "Pesachim", 70 | "Beitzah", "Rosh Hashanah", "Yoma", "Sukah", "Ta'anis", "Shekalim", "Megilah", "Chagigah", "Moed Katan", 71 | "Yevamos", "Kesuvos", "Sotah", "Nedarim", "Nazir", "Gitin", "Kidushin", "Bava Kama", "Bava Metzia", 72 | "Bava Basra", "Shevuos", "Makos", "Sanhedrin", "Avodah Zarah", "Horayos", "Nidah", "No Daf Today" }; 73 | 74 | /** 75 | * See {@link #getYerushalmiMasechta()}. 76 | */ 77 | private static final String[] masechtosYerushalmi = { "\u05d1\u05e8\u05db\u05d5\u05ea","\u05e4\u05d9\u05d0\u05d4", 78 | "\u05d3\u05de\u05d0\u05d9","\u05db\u05dc\u05d0\u05d9\u05dd","\u05e9\u05d1\u05d9\u05e2\u05d9\u05ea", 79 | "\u05ea\u05e8\u05d5\u05de\u05d5\u05ea","\u05de\u05e2\u05e9\u05e8\u05d5\u05ea","\u05de\u05e2\u05e9\u05e8 \u05e9\u05e0\u05d9", 80 | "\u05d7\u05dc\u05d4","\u05e2\u05d5\u05e8\u05dc\u05d4","\u05d1\u05d9\u05db\u05d5\u05e8\u05d9\u05dd", 81 | "\u05e9\u05d1\u05ea","\u05e2\u05d9\u05e8\u05d5\u05d1\u05d9\u05df","\u05e4\u05e1\u05d7\u05d9\u05dd", 82 | "\u05d1\u05d9\u05e6\u05d4","\u05e8\u05d0\u05e9 \u05d4\u05e9\u05e0\u05d4","\u05d9\u05d5\u05de\u05d0", 83 | "\u05e1\u05d5\u05db\u05d4","\u05ea\u05e2\u05e0\u05d9\u05ea","\u05e9\u05e7\u05dc\u05d9\u05dd","\u05de\u05d2\u05d9\u05dc\u05d4", 84 | "\u05d7\u05d2\u05d9\u05d2\u05d4","\u05de\u05d5\u05e2\u05d3 \u05e7\u05d8\u05df","\u05d9\u05d1\u05de\u05d5\u05ea", 85 | "\u05db\u05ea\u05d5\u05d1\u05d5\u05ea","\u05e1\u05d5\u05d8\u05d4","\u05e0\u05d3\u05e8\u05d9\u05dd","\u05e0\u05d6\u05d9\u05e8", 86 | "\u05d2\u05d9\u05d8\u05d9\u05df","\u05e7\u05d9\u05d3\u05d5\u05e9\u05d9\u05df","\u05d1\u05d1\u05d0 \u05e7\u05de\u05d0", 87 | "\u05d1\u05d1\u05d0 \u05de\u05e6\u05d9\u05e2\u05d0","\u05d1\u05d1\u05d0 \u05d1\u05ea\u05e8\u05d0", 88 | "\u05e9\u05d1\u05d5\u05e2\u05d5\u05ea","\u05de\u05db\u05d5\u05ea","\u05e1\u05e0\u05d4\u05d3\u05e8\u05d9\u05df", 89 | "\u05e2\u05d1\u05d5\u05d3\u05d4 \u05d6\u05e8\u05d4","\u05d4\u05d5\u05e8\u05d9\u05d5\u05ea","\u05e0\u05d9\u05d3\u05d4", 90 | "\u05d0\u05d9\u05df \u05d3\u05e3 \u05d4\u05d9\u05d5\u05dd" }; 91 | 92 | /** 93 | * Gets the masechta number of the currently set Daf. The sequence is: Berachos, Shabbos, Eruvin, 94 | * Pesachim, Shekalim, Yoma, Sukkah, Beitzah, Rosh Hashana, Taanis, Megillah, Moed Katan, Chagigah, Yevamos, Kesubos, 95 | * Nedarim, Nazir, Sotah, Gitin, Kiddushin, Bava Kamma, Bava Metzia, Bava Basra, Sanhedrin, Makkos, Shevuos, Avodah 96 | * Zarah, Horiyos, Zevachim, Menachos, Chullin, Bechoros, Arachin, Temurah, Kerisos, Meilah, Kinnim, Tamid, Midos and 97 | * Niddah. 98 | * @return the masechtaNumber. 99 | * @see #setMasechtaNumber(int) 100 | */ 101 | public int getMasechtaNumber() { 102 | return masechtaNumber; 103 | } 104 | 105 | /** 106 | * Set the masechta number in the order of the Daf Yomi. The sequence is: Berachos, Shabbos, Eruvin, Pesachim, 107 | * Shekalim, Yoma, Sukkah, Beitzah, Rosh Hashana, Taanis, Megillah, Moed Katan, Chagigah, Yevamos, Kesubos, Nedarim, 108 | * Nazir, Sotah, Gitin, Kiddushin, Bava Kamma, Bava Metzia, Bava Basra, Sanhedrin, Makkos, Shevuos, Avodah Zarah, 109 | * Horiyos, Zevachim, Menachos, Chullin, Bechoros, Arachin, Temurah, Kerisos, Meilah, Kinnim, Tamid, Midos and 110 | * Niddah. 111 | * 112 | * @param masechtaNumber 113 | * the masechta number in the order of the Daf Yomi to set. 114 | */ 115 | public void setMasechtaNumber(int masechtaNumber) { 116 | this.masechtaNumber = masechtaNumber; 117 | } 118 | 119 | /** 120 | * Constructor that creates a Daf setting the {@link #setMasechtaNumber(int) masechta number} and 121 | * {@link #setDaf(int) daf number}. 122 | * 123 | * @param masechtaNumber the masechta number in the order of the Daf Yomi to set as the current masechta. 124 | * @param daf the daf (page) number to set. 125 | */ 126 | public Daf(int masechtaNumber, int daf) { 127 | this.masechtaNumber = masechtaNumber; 128 | this.daf = daf; 129 | } 130 | 131 | /** 132 | * Returns the daf (page) number of the Daf Yomi. 133 | * @return the daf (page) number of the Daf Yomi. 134 | */ 135 | public int getDaf() { 136 | return daf; 137 | } 138 | 139 | /** 140 | * Sets the daf (page) number of the Daf Yomi. 141 | * @param daf the daf (page) number. 142 | */ 143 | public void setDaf(int daf) { 144 | this.daf = daf; 145 | } 146 | 147 | /** 148 | * Returns the transliterated name of the masechta (tractate) of the Daf Yomi. The list of mashechtos 149 | * is: Berachos, Shabbos, Eruvin, Pesachim, Shekalim, Yoma, Sukkah, Beitzah, Rosh Hashana, Taanis, Megillah, Moed Katan, 150 | * Chagigah, Yevamos, Kesubos, Nedarim, Nazir, Sotah, Gitin, Kiddushin, Bava Kamma, Bava Metzia, Bava Basra, Sanhedrin, 151 | * Makkos, Shevuos, Avodah Zarah, Horiyos, Zevachim, Menachos, Chullin, Bechoros, Arachin, Temurah, Kerisos, Meilah, 152 | * Kinnim, Tamid, Midos and Niddah. 153 | * 154 | * @return the transliterated name of the masechta (tractate) of the Daf Yomi such as Berachos. 155 | * @see #setMasechtaTransliterated(String[]) 156 | */ 157 | public String getMasechtaTransliterated() { 158 | return masechtosBavliTransliterated[masechtaNumber]; 159 | } 160 | 161 | /** 162 | * Setter method to allow overriding of the default list of masechtos transliterated into Latin chars. 163 | * The default values use Ashkenazi American English transliteration. 164 | * 165 | * @param masechtosBavliTransliterated the list of transliterated Bavli masechtos to set. 166 | * @see #getMasechtaTransliterated() 167 | */ 168 | public void setMasechtaTransliterated(String[] masechtosBavliTransliterated) { 169 | Daf.masechtosBavliTransliterated = masechtosBavliTransliterated; 170 | } 171 | 172 | /** 173 | * Returns the masechta (tractate) of the Daf Yomi in Hebrew. The list is in the following format
174 | * ["ברכות", 175 | * "שבת", "עירובין", 176 | * "פסחים", "שקלים", "יומא", 177 | * "סוכה", "ביצה", "ראש השנה", 178 | * "תענית", "מגילה", "מועד 179 | * קטן", "חגיגה", "יבמות", 180 | * "כתובות", "נדרים","נזיר", 181 | * "סוטה", "גיטין", "קידושין", 182 | * "בבא קמא", "בבא מציעא", 183 | * "בבא בתרא", "סנהדרין", 184 | * "מכות", "שבועות", "עבודה 185 | * זרה", "הוריות", "זבחים", 186 | * "מנחות", "חולין", "בכורות", 187 | * "ערכין", "תמורה", "כריתות", 188 | * "מעילה", "קינים", "תמיד", 189 | * "מידות", "נדה"]. 190 | * 191 | * @return the masechta (tractate) of the Daf Yomi in Hebrew. As an example, it will return 192 | * ברכות for Berachos. 193 | */ 194 | public String getMasechta() { 195 | return masechtosBavli[masechtaNumber]; 196 | } 197 | 198 | /** 199 | * Returns the transliterated name of the masechta (tractate) of the Daf Yomi in Yerushalmi. The list of 200 | * mashechtos is: 201 | * Berachos, Pe'ah, Demai, Kilayim, Shevi'is, Terumos, Ma'asros, Ma'aser Sheni, Chalah, Orlah, Bikurim, 202 | * Shabbos, Eruvin, Pesachim, Beitzah, Rosh Hashanah, Yoma, Sukah, Ta'anis, Shekalim, Megilah, Chagigah, 203 | * Moed Katan, Yevamos, Kesuvos, Sotah, Nedarim, Nazir, Gitin, Kidushin, Bava Kama, Bava Metzia, 204 | * Bava Basra, Shevuos, Makos, Sanhedrin, Avodah Zarah, Horayos, Nidah and No Daf Today. 205 | * 206 | * @return the transliterated name of the masechta (tractate) of the Daf Yomi such as Berachos. 207 | */ 208 | public String getYerushalmiMasechtaTransliterated() { 209 | return masechtosYerushalmiTransliterated[masechtaNumber]; 210 | } 211 | 212 | /** 213 | * @see #getYerushalmiMasechtaTransliterated() 214 | * @deprecated misspelled method name to be removed in 3.0.0. 215 | * @return the transliterated name of the masechta (tractate) of the Daf Yomi such as Berachos. 216 | */ 217 | @Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version 218 | public String getYerushlmiMasechtaTransliterated() { 219 | return getYerushalmiMasechtaTransliterated(); 220 | } 221 | 222 | /** 223 | * Setter method to allow overriding of the default list of Yerushalmi masechtos transliterated into Latin chars. 224 | * The default uses Ashkenazi American English transliteration. 225 | * 226 | * @param masechtosYerushalmiTransliterated the list of transliterated Yerushalmi masechtos to set. 227 | */ 228 | public void setYerushalmiMasechtaTransliterated(String[] masechtosYerushalmiTransliterated) { 229 | Daf.masechtosYerushalmiTransliterated = masechtosYerushalmiTransliterated; 230 | } 231 | 232 | /** 233 | * @see #setYerushalmiMasechtaTransliterated(String[]) 234 | * @deprecated misspelled method name to be removed in 3.0.0. 235 | * @param masechtosYerushalmiTransliterated the list of transliterated Yerushalmi masechtos to set. 236 | */ 237 | @Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version 238 | public void setYerushlmiMasechtaTransliterated(String[] masechtosYerushalmiTransliterated) { 239 | setYerushalmiMasechtaTransliterated(masechtosYerushalmiTransliterated); 240 | } 241 | 242 | /** 243 | * Getter method to allow retrieving the list of Yerushalmi masechtos transliterated into Latin chars. 244 | * The default uses Ashkenazi American English transliteration. 245 | * 246 | * @return the array of transliterated masechta (tractate) names of the Daf Yomi Yerushalmi. 247 | */ 248 | public static String[] getYerushalmiMasechtosTransliterated() { 249 | return masechtosYerushalmiTransliterated; 250 | } 251 | 252 | /** 253 | * @see #getYerushalmiMasechtosTransliterated() 254 | * @deprecated misspelled method name to be removed in 3.0.0. 255 | * @return the array of transliterated masechta (tractate) names of the Daf Yomi Yerushalmi. 256 | */ 257 | @Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version 258 | public static String[] getYerushlmiMasechtosTransliterated() { 259 | return getYerushalmiMasechtosTransliterated(); 260 | } 261 | 262 | /** 263 | * Getter method to allow retrieving the list of Yerushalmi masechtos. 264 | * 265 | * @return the array of Hebrew masechta (tractate) names of the Daf Yomi Yerushalmi. 266 | */ 267 | public static String[] getYerushalmiMasechtos() { 268 | return masechtosYerushalmi; 269 | } 270 | 271 | /** 272 | * @see #getYerushalmiMasechtos() 273 | * @deprecated misspelled method name to be removed in 3.0.0. 274 | * @return the array of Hebrew masechta (tractate) names of the Daf Yomi Yerushalmi. 275 | */ 276 | @Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version 277 | public static String[] getYerushlmiMasechtos() { 278 | return getYerushalmiMasechtos(); 279 | } 280 | 281 | /** 282 | * Returns the Yerushalmi masechta (tractate) of the Daf Yomi in Hebrew. As an example, it will return 283 | * ברכות for Berachos. 284 | * 285 | * @return the Yerushalmi masechta (tractate) of the Daf Yomi in Hebrew. As an example, it will return 286 | * ברכות for Berachos. 287 | */ 288 | public String getYerushalmiMasechta() { 289 | return masechtosYerushalmi[masechtaNumber]; 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/AstronomicalCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | import java.util.Calendar; 19 | 20 | /** 21 | * An abstract class that all sun time calculating classes extend. This allows the algorithm used to be changed at 22 | * runtime, easily allowing comparison the results of using different algorithms. 23 | * @todo Consider methods that would allow atmospheric modeling. This can currently be adjusted by {@link 24 | * #setRefraction(double) setting the refraction}. 25 | * 26 | * @author © Eliyahu Hershfeld 2004 - 2025 27 | */ 28 | public abstract class AstronomicalCalculator implements Cloneable { 29 | /** 30 | * The commonly used average solar refraction. Calendrical Calculations lists a more accurate global average of 34.478885263888294 32 | * 33 | * @see #getRefraction() 34 | */ 35 | private double refraction = 34 / 60d; 36 | 37 | /** 38 | * The commonly used average solar radius in minutes of a degree. 39 | * 40 | * @see #getSolarRadius() 41 | */ 42 | private double solarRadius = 16 / 60d; 43 | 44 | /** 45 | * The commonly used average earth radius in KM. At this time, this only affects elevation adjustment and not the 46 | * sunrise and sunset calculations. The value currently defaults to 6356.9 KM. 47 | * 48 | * @see #getEarthRadius() 49 | * @see #setEarthRadius(double) 50 | */ 51 | private double earthRadius = 6356.9; // in KM 52 | 53 | /** 54 | * Default constructor using the default {@link #refraction refraction}, {@link #solarRadius solar radius} and 55 | * {@link #earthRadius earth radius}. 56 | */ 57 | public AstronomicalCalculator() { 58 | // keep the defaults for now. 59 | } 60 | 61 | /** 62 | * A method that returns the earth radius in KM. The value currently defaults to 6356.9 KM if not set. 63 | * 64 | * @return the earthRadius the earth radius in KM. 65 | */ 66 | public double getEarthRadius() { 67 | return earthRadius; 68 | } 69 | 70 | /** 71 | * A method that allows setting the earth's radius. 72 | * 73 | * @param earthRadius 74 | * the earthRadius to set in KM 75 | */ 76 | public void setEarthRadius(double earthRadius) { 77 | this.earthRadius = earthRadius; 78 | } 79 | 80 | /** 81 | * The zenith of astronomical sunrise and sunset. The sun is 90° from the vertical 0° 82 | */ 83 | private static final double GEOMETRIC_ZENITH = 90; 84 | 85 | /** 86 | * Returns the default class for calculating sunrise and sunset. This is currently the more accurate 87 | * {@link NOAACalculator}, but this may change in the future. 88 | * 89 | * @return AstronomicalCalculator the default class for calculating sunrise and sunset. In the current 90 | * implementation the default calculator returned is the more accurate {@link NOAACalculator}. 91 | */ 92 | public static AstronomicalCalculator getDefault() { 93 | return new NOAACalculator(); 94 | } 95 | 96 | /** 97 | * Returns the name of the algorithm. 98 | * 99 | * @return the descriptive name of the algorithm. 100 | */ 101 | public abstract String getCalculatorName(); 102 | 103 | /** 104 | * A method that calculates UTC sunrise as well as any time based on an angle above or below sunrise. This abstract 105 | * method is implemented by the classes that extend this class. 106 | * 107 | * @param calendar 108 | * Used to calculate day of year. 109 | * @param geoLocation 110 | * The location information used for astronomical calculating sun times. 111 | * @param zenith 112 | * the azimuth below the vertical zenith of 90 degrees. for sunrise typically the {@link #adjustZenith 113 | * zenith} used for the calculation uses geometric zenith of 90° and {@link #adjustZenith adjusts} 114 | * this slightly to account for solar refraction and the sun's radius. Another example would be 115 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getBeginNauticalTwilight()} that passes 116 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#NAUTICAL_ZENITH} to this method. 117 | * @param adjustForElevation 118 | * Should the time be adjusted for elevation 119 | * @return The UTC time of sunrise in 24-hour format. 5:45:00 AM will return 5.75.0. If an error was encountered in 120 | * the calculation (expected behavior for some locations such as near the poles, 121 | * {@link java.lang.Double#NaN} will be returned. 122 | * @see #getElevationAdjustment(double) 123 | */ 124 | public abstract double getUTCSunrise(Calendar calendar, GeoLocation geoLocation, double zenith, 125 | boolean adjustForElevation); 126 | 127 | /** 128 | * A method that calculates UTC sunset as well as any time based on an angle above or below sunset. This abstract 129 | * method is implemented by the classes that extend this class. 130 | * 131 | * @param calendar 132 | * Used to calculate day of year. 133 | * @param geoLocation 134 | * The location information used for astronomical calculating sun times. 135 | * @param zenith 136 | * the azimuth below the vertical zenith of 90°. For sunset typically the {@link #adjustZenith 137 | * zenith} used for the calculation uses geometric zenith of 90° and {@link #adjustZenith adjusts} 138 | * this slightly to account for solar refraction and the sun's radius. Another example would be 139 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getEndNauticalTwilight()} that passes 140 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#NAUTICAL_ZENITH} to this method. 141 | * @param adjustForElevation 142 | * Should the time be adjusted for elevation 143 | * @return The UTC time of sunset in 24-hour format. 5:45:00 AM will return 5.75.0. If an error was encountered in 144 | * the calculation (expected behavior for some locations such as near the poles, 145 | * {@link java.lang.Double#NaN} will be returned. 146 | * @see #getElevationAdjustment(double) 147 | */ 148 | public abstract double getUTCSunset(Calendar calendar, GeoLocation geoLocation, double zenith, 149 | boolean adjustForElevation); 150 | 151 | 152 | /** 153 | * Return solar noon (UTC) for the given day at the 154 | * given location on earth. The {@link com.kosherjava.zmanim.util.NOAACalculator} implementation calculates 155 | * true solar noon, while the {@link com.kosherjava.zmanim.util.SunTimesCalculator} approximates it, calculating 156 | * the time as halfway between sunrise and sunset. 157 | * 158 | * @param calendar 159 | * Used to calculate day of year. 160 | * @param geoLocation 161 | * The location information used for astronomical calculating sun times. 162 | * 163 | * @return the time in minutes from zero UTC 164 | */ 165 | public abstract double getUTCNoon(Calendar calendar, GeoLocation geoLocation); 166 | 167 | 168 | /** 169 | * Return solar midnight (UTC) for the given day at the 170 | * given location on earth. The the {@link com.kosherjava.zmanim.util.NOAACalculator} implementation calculates 171 | * true solar midnight, while the {@link com.kosherjava.zmanim.util.SunTimesCalculator} approximates it, calculating 172 | * the time as 12 hours after halfway between sunrise and sunset. 173 | * 174 | * @param calendar 175 | * Used to calculate day of year. 176 | * @param geoLocation 177 | * The location information used for astronomical calculating sun times. 178 | * 179 | * @return the time in minutes from zero UTC 180 | */ 181 | public abstract double getUTCMidnight(Calendar calendar, GeoLocation geoLocation); 182 | 183 | /** 184 | * Return the Solar Elevation for the 185 | * horizontal coordinate system at the given location at the given time. Can be negative if the sun is below the 186 | * horizon. Not corrected for altitude. 187 | * 188 | * @param calendar 189 | * time of calculation 190 | * @param geoLocation 191 | * The location information 192 | * @return solar elevation in degrees. The horizon (calculated in a vacuum using the solar radius as the point) 193 | * is 090°, civil twilight is -690° etc. This means that sunrise and sunset that do use 194 | * refraction and are calculated from the upper limb of the sun will return about 0.83390°. 195 | */ 196 | public abstract double getSolarElevation(Calendar calendar, GeoLocation geoLocation); 197 | 198 | /** 199 | * Return the Solar Azimuth for the 200 | * horizontal coordinate system at the given location at the given time. Not corrected for altitude. True south is 180 201 | * degrees. 202 | * 203 | * @param calendar 204 | * time of calculation 205 | * @param geoLocation 206 | * The location information 207 | * @return the solar azimuth in degrees. Astronomical midday would be 180 in the norther hemosphere and 0 in the 208 | * southern hemosphere. Depending on the location and time of year, sunrise will have an azimuth of about 209 | * 90° and sunset about 270°. 210 | */ 211 | public abstract double getSolarAzimuth(Calendar calendar, GeoLocation geoLocation); 212 | 213 | /** 214 | * Method to return the adjustment to the zenith required to account for the elevation. Since a person at a higher 215 | * elevation can see farther below the horizon, the calculation for sunrise / sunset is calculated below the horizon 216 | * used at sea level. This is only used for sunrise and sunset and not times before or after it such as 217 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getBeginNauticalTwilight() nautical twilight} since those 218 | * calculations are based on the level of available light at the given dip below the horizon, something that is not 219 | * affected by elevation, the adjustment should only be made if the zenith == 90° {@link #adjustZenith adjusted} 220 | * for refraction and solar radius. The algorithm used is 221 | * 222 | *
223 | 	 * elevationAdjustment = Math.toDegrees(Math.acos(earthRadiusInMeters / (earthRadiusInMeters + elevationMeters)));
224 | 	 * 
225 | * 226 | * The source of this algorithm is Calendrical 227 | * Calculations by Edward M. Reingold and Nachum Dershowitz. An alternate algorithm that produces similar (but 228 | * not completely accurate) result found in Ma'aglay Tzedek by Moishe Kosower and other sources is: 229 | * 230 | *
231 | 	 * elevationAdjustment = 0.0347 * Math.sqrt(elevationMeters);
232 | 	 * 
233 | * 234 | * @param elevation 235 | * elevation in Meters. 236 | * @return the adjusted zenith 237 | */ 238 | double getElevationAdjustment(double elevation) { 239 | double elevationAdjustment = Math.toDegrees(Math.acos(earthRadius / (earthRadius + (elevation / 1000)))); 240 | return elevationAdjustment; 241 | } 242 | 243 | /** 244 | * Adjusts the zenith of astronomical sunrise and sunset to account for solar refraction, solar radius and 245 | * elevation. The value for Sun's zenith and true rise/set Zenith (used in this class and subclasses) is the angle 246 | * that the center of the Sun makes to a line perpendicular to the Earth's surface. If the Sun were a point and the 247 | * Earth were without an atmosphere, true sunset and sunrise would correspond to a 90° zenith. Because the Sun 248 | * is not a point, and because the atmosphere refracts light, this 90° zenith does not, in fact, correspond to 249 | * true sunset or sunrise, instead the center of the Sun's disk must lie just below the horizon for the upper edge 250 | * to be obscured. This means that a zenith of just above 90° must be used. The Sun subtends an angle of 16 251 | * minutes of arc (this can be changed via the {@link #setSolarRadius(double)} method , and atmospheric refraction 252 | * accounts for 34 minutes or so (this can be changed via the {@link #setRefraction(double)} method), giving a total 253 | * of 50 arcminutes. The total value for ZENITH is 90+(5/6) or 90.8333333° for true sunrise/sunset. Since a 254 | * person at an elevation can see below the horizon of a person at sea level, this will also adjust the zenith to 255 | * account for elevation if available. Note that this will only adjust the value if the zenith is exactly 90 degrees. 256 | * For values below and above this no correction is done. As an example, astronomical twilight is when the sun is 257 | * 18° below the horizon or {@link com.kosherjava.zmanim.AstronomicalCalendar#ASTRONOMICAL_ZENITH 108° 258 | * below the zenith}. This is traditionally calculated with none of the above mentioned adjustments. The same goes 259 | * for various tzais and alos times such as the 260 | * {@link com.kosherjava.zmanim.ZmanimCalendar#ZENITH_16_POINT_1 16.1°} dip used in 261 | * {@link com.kosherjava.zmanim.ComplexZmanimCalendar#getAlos16Point1Degrees()}. 262 | * 263 | * @param zenith 264 | * the azimuth below the vertical zenith of 90°. For sunset typically the {@link #adjustZenith 265 | * zenith} used for the calculation uses geometric zenith of 90° and {@link #adjustZenith adjusts} 266 | * this slightly to account for solar refraction and the sun's radius. Another example would be 267 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#getEndNauticalTwilight()} that passes 268 | * {@link com.kosherjava.zmanim.AstronomicalCalendar#NAUTICAL_ZENITH} to this method. 269 | * @param elevation 270 | * elevation in Meters. 271 | * @return The zenith adjusted to include the {@link #getSolarRadius sun's radius}, {@link #getRefraction 272 | * refraction} and {@link #getElevationAdjustment elevation} adjustment. This will only be adjusted for 273 | * sunrise and sunset (if the zenith == 90°) 274 | * @see #getElevationAdjustment(double) 275 | */ 276 | double adjustZenith(double zenith, double elevation) { 277 | double adjustedZenith = zenith; 278 | if (zenith == GEOMETRIC_ZENITH) { // only adjust if it is exactly sunrise or sunset 279 | adjustedZenith = zenith + (getSolarRadius() + getRefraction() + getElevationAdjustment(elevation)); 280 | } 281 | return adjustedZenith; 282 | } 283 | 284 | /** 285 | * Method to get the refraction value to be used when calculating sunrise and sunset. The default value is 34 286 | * arcminutes. The Errata and Notes 287 | * for Calendrical Calculations: The Millennium Edition by Edward M. Reingold and Nachum Dershowitz lists the 288 | * actual average refraction value as 34.478885263888294 or approximately 34' 29". The refraction value as well 289 | * as the solarRadius and elevation adjustment are added to the zenith used to calculate sunrise and sunset. 290 | * 291 | * @return The refraction in arcminutes. 292 | */ 293 | public double getRefraction() { 294 | return this.refraction; 295 | } 296 | 297 | /** 298 | * A method to allow overriding the default refraction of the calculator. 299 | * @todo At some point in the future, an AtmosphericModel or Refraction object that models the atmosphere of different 300 | * locations might be used for increased accuracy. 301 | * 302 | * @param refraction 303 | * The refraction in arcminutes. 304 | * @see #getRefraction() 305 | */ 306 | public void setRefraction(double refraction) { 307 | this.refraction = refraction; 308 | } 309 | 310 | /** 311 | * Method to get the sun's radius. The default value is 16 arcminutes. The sun's radius as it appears from earth is 312 | * almost universally given as 16 arcminutes but in fact it differs by the time of the year. At the perihelion it has an apparent radius of 16.293, while at the 314 | * aphelion it has an apparent radius of 15.755. There is little 315 | * affect for most location, but at high and low latitudes the difference becomes more apparent. My Calculations for 316 | * the difference at the location of the Royal Observatory, Greenwich 317 | * shows only a 4.494-second difference between the perihelion and aphelion radii, but moving into the arctic circle the 318 | * difference becomes more noticeable. Tests for Tromso, Norway (latitude 69.672312, longitude 19.049787) show that 319 | * on May 17, the rise of the midnight sun, a 2 minute and 23 second difference is observed between the perihelion and 320 | * aphelion radii using the USNO algorithm, but only 1 minute and 6 seconds difference using the NOAA algorithm. 321 | * Areas farther north show an even greater difference. Note that these test are not real valid test cases because 322 | * they show the extreme difference on days that are not the perihelion or aphelion, but are shown for illustrative 323 | * purposes only. 324 | * 325 | * @return The sun's radius in arcminutes. 326 | */ 327 | public double getSolarRadius() { 328 | return this.solarRadius; 329 | } 330 | 331 | /** 332 | * Method to set the sun's radius. 333 | * 334 | * @param solarRadius 335 | * The sun's radius in arcminutes. 336 | * @see #getSolarRadius() 337 | */ 338 | public void setSolarRadius(double solarRadius) { 339 | this.solarRadius = solarRadius; 340 | } 341 | 342 | /** 343 | * @see java.lang.Object#clone() 344 | * @since 1.1 345 | */ 346 | public Object clone() { 347 | AstronomicalCalculator clone = null; 348 | try { 349 | clone = (AstronomicalCalculator) super.clone(); 350 | } catch (CloneNotSupportedException cnse) { 351 | System.out.print("Required by the compiler. Should never be reached since we implement clone()"); 352 | } 353 | return clone; 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zmanim Java API 3 | * Copyright (C) 2004-2025 Eliyahu Hershfeld 4 | * 5 | * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 6 | * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 7 | * any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 10 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 11 | * details. 12 | * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 13 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 14 | * or connect to: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 15 | */ 16 | package com.kosherjava.zmanim.util; 17 | 18 | import java.util.Calendar; 19 | 20 | /** 21 | * Implementation of sunrise and sunset methods to calculate astronomical times based on the NOAA algorithm. This calculator uses the Java algorithm based on the implementation by NOAA - National Oceanic and Atmospheric Administration's Surface Radiation Research Branch. NOAA's implementation is based on equations from Astronomical Algorithms by Jean Meeus. Added to the algorithm is an adjustment of the zenith 28 | * to account for elevation. The algorithm can be found in the Wikipedia Sunrise Equation article. 30 | * 31 | * @author © Eliyahu Hershfeld 2011 - 2025 32 | */ 33 | public class NOAACalculator extends AstronomicalCalculator { 34 | 35 | /** 36 | * The Julian day of January 1, 2000, known as 37 | * J2000.0. 38 | */ 39 | private static final double JULIAN_DAY_JAN_1_2000 = 2451545.0; 40 | 41 | /** 42 | * Julian days per century. 43 | */ 44 | private static final double JULIAN_DAYS_PER_CENTURY = 36525.0; 45 | 46 | /** 47 | * An enum to indicate what type of solar event ({@link #SUNRISE SUNRISE}, {@link #SUNSET SUNSET}, 48 | * {@link #NOON NOON} or {@link #MIDNIGHT MIDNIGHT}) is being calculated. 49 | * . 50 | */ 51 | protected enum SolarEvent { 52 | /**SUNRISE A solar event related to sunrise*/SUNRISE, /**SUNSET A solar event related to sunset*/SUNSET, 53 | /**NOON A solar event related to noon*/NOON, /**MIDNIGHT A solar event related to midnight*/MIDNIGHT 54 | } 55 | 56 | /** 57 | * Default constructor of the NOAACalculator. 58 | */ 59 | public NOAACalculator() { 60 | super(); 61 | } 62 | 63 | /** 64 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getCalculatorName() 65 | */ 66 | public String getCalculatorName() { 67 | return "US National Oceanic and Atmospheric Administration Algorithm"; // Implementation of the Jean Meeus algorithm 68 | } 69 | 70 | /** 71 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCSunrise(Calendar, GeoLocation, double, boolean) 72 | */ 73 | public double getUTCSunrise(Calendar calendar, GeoLocation geoLocation, double zenith, boolean adjustForElevation) { 74 | double elevation = adjustForElevation ? geoLocation.getElevation() : 0; 75 | double adjustedZenith = adjustZenith(zenith, elevation); 76 | double sunrise = getSunRiseSetUTC(calendar, geoLocation.getLatitude(), -geoLocation.getLongitude(), 77 | adjustedZenith, SolarEvent.SUNRISE); 78 | sunrise = sunrise / 60; 79 | return sunrise > 0 ? sunrise % 24 : sunrise % 24 + 24; // ensure that the time is >= 0 and < 24 80 | } 81 | 82 | /** 83 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCSunset(Calendar, GeoLocation, double, boolean) 84 | */ 85 | public double getUTCSunset(Calendar calendar, GeoLocation geoLocation, double zenith, boolean adjustForElevation) { 86 | double elevation = adjustForElevation ? geoLocation.getElevation() : 0; 87 | double adjustedZenith = adjustZenith(zenith, elevation); 88 | double sunset = getSunRiseSetUTC(calendar, geoLocation.getLatitude(), -geoLocation.getLongitude(), 89 | adjustedZenith, SolarEvent.SUNSET); 90 | sunset = sunset / 60; 91 | return sunset > 0 ? sunset % 24 : sunset % 24 + 24; // ensure that the time is >= 0 and < 24 92 | } 93 | 94 | /** 95 | * Return the Julian day from a Java Calendar. 96 | * 97 | * @param calendar 98 | * The Java Calendar 99 | * @return the Julian day corresponding to the date Note: Number is returned for the start of the Julian 100 | * day. Fractional days / time should be added later. 101 | */ 102 | private static double getJulianDay(Calendar calendar) { 103 | int year = calendar.get(Calendar.YEAR); 104 | int month = calendar.get(Calendar.MONTH) + 1; 105 | int day = calendar.get(Calendar.DAY_OF_MONTH); 106 | if (month <= 2) { 107 | year -= 1; 108 | month += 12; 109 | } 110 | int a = year / 100; 111 | int b = 2 - a + a / 4; 112 | return Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + b - 1524.5; 113 | } 114 | 115 | /** 116 | * Convert Julian day to centuries since J2000.0. 118 | * 119 | * @param julianDay 120 | * the Julian Day to convert 121 | * @return the centuries since 2000 Julian corresponding to the Julian Day 122 | */ 123 | private static double getJulianCenturiesFromJulianDay(double julianDay) { 124 | return (julianDay - JULIAN_DAY_JAN_1_2000) / JULIAN_DAYS_PER_CENTURY; 125 | } 126 | 127 | /** 128 | * Returns the Geometric Mean Longitude of the Sun. 129 | * 130 | * @param julianCenturies 131 | * the number of Julian centuries since J2000.0. 133 | * @return the Geometric Mean Longitude of the Sun in degrees 134 | */ 135 | private static double getSunGeometricMeanLongitude(double julianCenturies) { 136 | double longitude = 280.46646 + julianCenturies * (36000.76983 + 0.0003032 * julianCenturies); 137 | return longitude > 0 ? longitude % 360 : longitude % 360 + 360; // ensure that the longitude is >= 0 and < 360 138 | } 139 | 140 | /** 141 | * Returns the Geometric Mean Anomaly of the Sun in degrees. 142 | * 143 | * @param julianCenturies 144 | * the number of Julian centuries since J2000.0. 146 | * @return the Geometric Mean Anomaly of the Sun in degrees 147 | */ 148 | private static double getSunGeometricMeanAnomaly(double julianCenturies) { 149 | return 357.52911 + julianCenturies * (35999.05029 - 0.0001537 * julianCenturies); 150 | } 151 | 152 | /** 153 | * Return the unitless eccentricity of earth's orbit. 154 | * 155 | * @param julianCenturies 156 | * the number of Julian centuries since J2000.0. 158 | * @return the unitless eccentricity 159 | */ 160 | private static double getEarthOrbitEccentricity(double julianCenturies) { 161 | return 0.016708634 - julianCenturies * (0.000042037 + 0.0000001267 * julianCenturies); 162 | } 163 | 164 | /** 165 | * Returns the equation of center for the sun in degrees. 166 | * 167 | * @param julianCenturies 168 | * the number of Julian centuries since J2000.0. 170 | * @return the equation of center for the sun in degrees 171 | */ 172 | private static double getSunEquationOfCenter(double julianCenturies) { 173 | double m = getSunGeometricMeanAnomaly(julianCenturies); 174 | double mrad = Math.toRadians(m); 175 | double sinm = Math.sin(mrad); 176 | double sin2m = Math.sin(mrad + mrad); 177 | double sin3m = Math.sin(mrad + mrad + mrad); 178 | return sinm * (1.914602 - julianCenturies * (0.004817 + 0.000014 * julianCenturies)) + sin2m 179 | * (0.019993 - 0.000101 * julianCenturies) + sin3m * 0.000289; 180 | } 181 | 182 | /** 183 | * Return the true longitude of the sun. 184 | * 185 | * @param julianCenturies 186 | * the number of Julian centuries since J2000.0. 188 | * @return the sun's true longitude in degrees 189 | */ 190 | private static double getSunTrueLongitude(double julianCenturies) { 191 | double sunLongitude = getSunGeometricMeanLongitude(julianCenturies); 192 | double center = getSunEquationOfCenter(julianCenturies); 193 | return sunLongitude + center; 194 | } 195 | 196 | /** 197 | * Return the apparent longitude of the sun. 198 | * 199 | * @param julianCenturies 200 | * the number of Julian centuries since J2000.0. 202 | * @return sun's apparent longitude in degrees 203 | */ 204 | private static double getSunApparentLongitude(double julianCenturies) { 205 | double sunTrueLongitude = getSunTrueLongitude(julianCenturies); 206 | double omega = 125.04 - 1934.136 * julianCenturies; 207 | double lambda = sunTrueLongitude - 0.00569 - 0.00478 * Math.sin(Math.toRadians(omega)); 208 | return lambda; 209 | } 210 | 211 | /** 212 | * Returns the mean obliquity of the ecliptic (Axial tilt). 213 | * 214 | * @param julianCenturies 215 | * the number of Julian centuries since J2000.0. 217 | * @return the mean obliquity in degrees 218 | */ 219 | private static double getMeanObliquityOfEcliptic(double julianCenturies) { 220 | double seconds = 21.448 - julianCenturies 221 | * (46.8150 + julianCenturies * (0.00059 - julianCenturies * (0.001813))); 222 | return 23.0 + (26.0 + (seconds / 60.0)) / 60.0; 223 | } 224 | 225 | /** 226 | * Returns the corrected obliquity of the ecliptic (Axial 227 | * tilt). 228 | * 229 | * @param julianCenturies 230 | * the number of Julian centuries since J2000.0. 232 | * @return the corrected obliquity in degrees 233 | */ 234 | private static double getObliquityCorrection(double julianCenturies) { 235 | double obliquityOfEcliptic = getMeanObliquityOfEcliptic(julianCenturies); 236 | double omega = 125.04 - 1934.136 * julianCenturies; 237 | return obliquityOfEcliptic + 0.00256 * Math.cos(Math.toRadians(omega)); 238 | } 239 | 240 | /** 241 | * Return the declination of the sun. 242 | * 243 | * @param julianCenturies 244 | * the number of Julian centuries since J2000.0. 246 | * @return 247 | * the sun's declination in degrees 248 | */ 249 | private static double getSunDeclination(double julianCenturies) { 250 | double obliquityCorrection = getObliquityCorrection(julianCenturies); 251 | double lambda = getSunApparentLongitude(julianCenturies); 252 | double sint = Math.sin(Math.toRadians(obliquityCorrection)) * Math.sin(Math.toRadians(lambda)); 253 | double theta = Math.toDegrees(Math.asin(sint)); 254 | return theta; 255 | } 256 | 257 | /** 258 | * Return the Equation of Time - the difference between 259 | * true solar time and mean solar time 260 | * 261 | * @param julianCenturies 262 | * the number of Julian centuries since J2000.0. 264 | * @return equation of time in minutes of time 265 | */ 266 | private static double getEquationOfTime(double julianCenturies) { 267 | double epsilon = getObliquityCorrection(julianCenturies); 268 | double geomMeanLongSun = getSunGeometricMeanLongitude(julianCenturies); 269 | double eccentricityEarthOrbit = getEarthOrbitEccentricity(julianCenturies); 270 | double geomMeanAnomalySun = getSunGeometricMeanAnomaly(julianCenturies); 271 | double y = Math.tan(Math.toRadians(epsilon) / 2.0); 272 | y *= y; 273 | double sin2l0 = Math.sin(2.0 * Math.toRadians(geomMeanLongSun)); 274 | double sinm = Math.sin(Math.toRadians(geomMeanAnomalySun)); 275 | double cos2l0 = Math.cos(2.0 * Math.toRadians(geomMeanLongSun)); 276 | double sin4l0 = Math.sin(4.0 * Math.toRadians(geomMeanLongSun)); 277 | double sin2m = Math.sin(2.0 * Math.toRadians(geomMeanAnomalySun)); 278 | double equationOfTime = y * sin2l0 - 2.0 * eccentricityEarthOrbit * sinm + 4.0 * eccentricityEarthOrbit * y 279 | * sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * eccentricityEarthOrbit * eccentricityEarthOrbit * sin2m; 280 | return Math.toDegrees(equationOfTime) * 4.0; 281 | } 282 | 283 | /** 284 | * Return the hour angle of the sun in 285 | * radians at for the latitude. 286 | * 287 | * @param latitude 288 | * the latitude of observer in degrees 289 | * @param solarDeclination 290 | * the declination angle of sun in degrees 291 | * @param zenith 292 | * the zenith 293 | * @param solarEvent 294 | * If the hour angle is for {@link SolarEvent#SUNRISE SUNRISE} or {@link SolarEvent#SUNSET SUNSET} 295 | * @return hour angle of sunrise in radians 296 | */ 297 | private static double getSunHourAngle(double latitude, double solarDeclination, double zenith, SolarEvent solarEvent) { 298 | double latRad = Math.toRadians(latitude); 299 | double sdRad = Math.toRadians(solarDeclination); 300 | double hourAngle = (Math.acos(Math.cos(Math.toRadians(zenith)) / (Math.cos(latRad) * Math.cos(sdRad)) 301 | - Math.tan(latRad) * Math.tan(sdRad))); 302 | 303 | if (solarEvent == SolarEvent.SUNSET) { 304 | hourAngle = -hourAngle; 305 | } 306 | return hourAngle; 307 | } 308 | 309 | /** 310 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getSolarElevation(Calendar, GeoLocation) 311 | */ 312 | public double getSolarElevation(Calendar calendar, GeoLocation geoLocation) { 313 | return getSolarElevationAzimuth(calendar, geoLocation, false); 314 | 315 | } 316 | 317 | /** 318 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getSolarAzimuth(Calendar, GeoLocation) 319 | */ 320 | public double getSolarAzimuth(Calendar calendar, GeoLocation geoLocation) { 321 | return getSolarElevationAzimuth(calendar, geoLocation, true); 322 | } 323 | 324 | /** 325 | * Return the Solar Elevation or 326 | * Solar Azimuth at the given location 327 | * and time. Can be negative if the sun is below the horizon. Elevation is based on sea-level and is not 328 | * adjusted for altitude. 329 | * 330 | * @param calendar 331 | * time of calculation 332 | * @param geoLocation 333 | * The location for calculating the elevation or azimuth. 334 | * @param isAzimuth 335 | * true for azimuth, false for elevation 336 | * @return solar elevation or azimuth in degrees. 337 | * 338 | * @see #getSolarElevation(Calendar, GeoLocation) 339 | * @see #getSolarAzimuth(Calendar, GeoLocation) 340 | */ 341 | private double getSolarElevationAzimuth(Calendar calendar, GeoLocation geoLocation, boolean isAzimuth) { 342 | double latitude = geoLocation.getLatitude(); 343 | double longitude = geoLocation.getLongitude(); 344 | 345 | Calendar cloned = (Calendar) calendar.clone(); 346 | int offset = - adjustHourForTimeZone(cloned); 347 | cloned.add(Calendar.MILLISECOND, offset); 348 | int minute = cloned.get(Calendar.MINUTE); 349 | int second = cloned.get(Calendar.SECOND); 350 | int hour = cloned.get(Calendar.HOUR_OF_DAY); 351 | int milli = cloned.get(Calendar.MILLISECOND); 352 | 353 | double time = (hour + (minute + (second + (milli / 1000.0)) / 60.0) / 60.0 ) / 24.0; 354 | double julianDay = getJulianDay(cloned) + time; 355 | double julianCenturies = getJulianCenturiesFromJulianDay(julianDay); 356 | double eot = getEquationOfTime(julianCenturies); 357 | double theta = getSunDeclination(julianCenturies); 358 | 359 | double adjustment = time + eot / 1440; 360 | double trueSolarTime = ((adjustment + longitude / 360) + 2) % 1; // adding 2 to ensure that it never ends up negative 361 | double hourAngelRad = trueSolarTime * Math.PI * 2 - Math.PI; 362 | double cosZenith = Math.sin(Math.toRadians(latitude)) * Math.sin(Math.toRadians(theta)) 363 | + Math.cos(Math.toRadians(latitude)) * Math.cos(Math.toRadians(theta)) * Math.cos(hourAngelRad); 364 | double zenith = Math.toDegrees(Math.acos(cosZenith > 1 ? 1 : cosZenith < -1 ? -1 : cosZenith)); 365 | double azDenom = Math.cos(Math.toRadians(latitude)) * Math.sin(Math.toRadians(zenith)); 366 | double refractionAdjustment = 0; 367 | double elevation = 90.0 - (zenith - refractionAdjustment); 368 | double azimuth = 0; 369 | double azRad = (Math.sin(Math.toRadians(latitude)) * Math.cos(Math.toRadians(zenith)) 370 | - Math.sin(Math.toRadians(theta))) / azDenom; 371 | if(Math.abs(azDenom) > 0.001) { 372 | azimuth = 180 - Math.toDegrees(Math.acos(azRad > 1 ? 1 : azRad < -1? -1 : azRad)) * (hourAngelRad > 0 ? -1 : 1) ; 373 | } else { 374 | azimuth = latitude > 0 ? 180 : 0; 375 | } 376 | return isAzimuth ? azimuth % 360 : elevation; 377 | } 378 | 379 | /** 380 | * Returns the hour of day adjusted for the timezone and DST. This is needed for the azimuth and elevation 381 | * calculations. 382 | * @param calendar the Calendar to extract the hour from. This must have the timezone set to the proper timezone. 383 | * @return the adjusted hour corrected for timezone and DST offset. 384 | */ 385 | private int adjustHourForTimeZone(Calendar calendar) { 386 | int offset = calendar.getTimeZone().getRawOffset(); 387 | int dstOffset = calendar.getTimeZone().getDSTSavings(); 388 | if(calendar.getTimeZone().inDaylightTime(calendar.getTime())) { 389 | offset = offset + dstOffset; 390 | } 391 | return offset; 392 | } 393 | 394 | /** 395 | * Return the Universal Coordinated Time (UTC) 396 | * of solar noon for the given day at the given location 397 | * on earth. This implementation returns true solar noon as opposed to the time halfway between sunrise and sunset. 398 | * Other calculators may return a more simplified calculation of halfway between sunrise and sunset. See The Definition of Chatzos for details on 400 | * solar noon calculations. 401 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation) 402 | * @see #getSolarNoonMidnightUTC(double, double, SolarEvent) 403 | * 404 | * @param calendar 405 | * The Calendar representing the date to calculate solar noon for 406 | * @param geoLocation 407 | * The location information used for astronomical calculating sun times. This class uses only requires 408 | * the longitude for calculating noon since it is the same time anywhere along the longitude line. 409 | * @return the time in minutes from zero UTC 410 | */ 411 | public double getUTCNoon(Calendar calendar, GeoLocation geoLocation) { 412 | double noon = getSolarNoonMidnightUTC(getJulianDay(calendar), -geoLocation.getLongitude(), SolarEvent.NOON); 413 | noon = noon / 60; 414 | return noon > 0 ? noon % 24 : noon % 24 + 24; // ensure that the time is >= 0 and < 24 415 | } 416 | 417 | /** 418 | * Return the Universal Coordinated Time 419 | * (UTC) of the solar midnight for the end of the given civil 420 | * day at the given location on earth (about 12 hours after solar noon). This implementation returns true solar 421 | * midnight as opposed to the time halfway between sunrise and sunset. Other calculators may return a more 422 | * simplified calculation of halfway between sunrise and sunset. See The Definition of Chatzos for details on 424 | * solar noon / midnight calculations. 425 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation) 426 | * @see #getSolarNoonMidnightUTC(double, double, SolarEvent) 427 | * 428 | * @param calendar 429 | * The Calendar representing the date to calculate solar noon for 430 | * @param geoLocation 431 | * The location information used for astronomical calculating sun times. This class uses only requires 432 | * the longitude for calculating noon since it is the same time anywhere along the longitude line. 433 | * @return the time in minutes from zero UTC 434 | */ 435 | public double getUTCMidnight(Calendar calendar, GeoLocation geoLocation) { 436 | double midnight = getSolarNoonMidnightUTC(getJulianDay(calendar), -geoLocation.getLongitude(), SolarEvent.MIDNIGHT); 437 | midnight = midnight / 60; 438 | return midnight > 0 ? midnight % 24 : midnight % 24 + 24; // ensure that the time is >= 0 and < 24 439 | } 440 | 441 | /** 442 | * Return the Universal Coordinated Time (UTC) 443 | * of the current day solar noon or the the upcoming 444 | * midnight (about 12 hours after solar noon) of the given day at the given location on earth. 445 | * 446 | * @param julianDay 447 | * The Julian day since J2000.0. 449 | * @param longitude 450 | * The longitude of observer in degrees 451 | * @param solarEvent 452 | * If the calculation is for {@link SolarEvent#NOON NOON} or {@link SolarEvent#MIDNIGHT MIDNIGHT} 453 | * 454 | * @return the time in minutes from zero UTC 455 | * 456 | * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(Calendar, GeoLocation) 457 | * @see #getUTCNoon(Calendar, GeoLocation) 458 | */ 459 | private static double getSolarNoonMidnightUTC(double julianDay, double longitude, SolarEvent solarEvent) { 460 | julianDay = (solarEvent == SolarEvent.NOON) ? julianDay : julianDay + 0.5; 461 | // First pass for approximate solar noon to calculate equation of time 462 | double tnoon = getJulianCenturiesFromJulianDay(julianDay + longitude / 360.0); 463 | double equationOfTime = getEquationOfTime(tnoon); 464 | double solNoonUTC = (longitude * 4) - equationOfTime; // minutes 465 | 466 | // second pass 467 | double newt = getJulianCenturiesFromJulianDay(julianDay + solNoonUTC / 1440.0); 468 | equationOfTime = getEquationOfTime(newt); 469 | return (solarEvent == SolarEvent.NOON ? 720 : 1440) + (longitude * 4) - equationOfTime; 470 | } 471 | 472 | /** 473 | * Return the Universal Coordinated Time (UTC) 474 | * of sunrise or sunset in minutes for the given day at the given location on earth. 475 | * @todo Possibly increase the number of passes for improved accuracy, especially in the Arctic areas. 476 | * 477 | * @param calendar 478 | * The calendar 479 | * @param latitude 480 | * The latitude of observer in degrees 481 | * @param longitude 482 | * Longitude of observer in degrees 483 | * @param zenith 484 | * Zenith 485 | * @param solarEvent 486 | * If the calculation is for {@link SolarEvent#SUNRISE SUNRISE} or {@link SolarEvent#SUNSET SUNSET} 487 | * @return the time in minutes from zero Universal Coordinated Time (UTC) 488 | */ 489 | private static double getSunRiseSetUTC(Calendar calendar, double latitude, double longitude, double zenith, 490 | SolarEvent solarEvent) { 491 | double julianDay = getJulianDay(calendar); 492 | 493 | // Find the time of solar noon at the location, and use that declination. 494 | // This is better than start of the Julian day 495 | // TODO really not needed since the Julian day starts from local fixed noon. Changing this would be more 496 | // efficient but would likely cause a very minor discrepancy in the calculated times (likely not reducing 497 | // accuracy, just slightly different, thus potentially breaking test cases). Regardless, it would be within 498 | // milliseconds. 499 | double noonmin = getSolarNoonMidnightUTC(julianDay, longitude, SolarEvent.NOON); 500 | 501 | double tnoon = getJulianCenturiesFromJulianDay(julianDay + noonmin / 1440.0); 502 | 503 | // First calculates sunrise and approximate length of day 504 | double equationOfTime = getEquationOfTime(tnoon); 505 | double solarDeclination = getSunDeclination(tnoon); 506 | double hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent); 507 | double delta = longitude - Math.toDegrees(hourAngle); 508 | double timeDiff = 4 * delta; 509 | double timeUTC = 720 + timeDiff - equationOfTime; 510 | 511 | // Second pass includes fractional Julian Day in gamma calc 512 | double newt = getJulianCenturiesFromJulianDay(julianDay + timeUTC / 1440.0); 513 | equationOfTime = getEquationOfTime(newt); 514 | 515 | solarDeclination = getSunDeclination(newt); 516 | hourAngle = getSunHourAngle(latitude, solarDeclination, zenith, solarEvent); 517 | delta = longitude - Math.toDegrees(hourAngle); 518 | timeDiff = 4 * delta; 519 | timeUTC = 720 + timeDiff - equationOfTime; 520 | return timeUTC; 521 | } 522 | } 523 | --------------------------------------------------------------------------------