Skip to content

Commit

Permalink
fix timezone issues with JewishCalendar
Browse files Browse the repository at this point in the history
  • Loading branch information
Elyahu41 committed Dec 24, 2023
1 parent 365e888 commit dcfb71e
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 25 deletions.
125 changes: 100 additions & 25 deletions KosherSwift/hebrewcalendar/JewishCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -684,10 +684,15 @@ public class JewishCalendar {
}

/**
* The internal date object that all the calculations are dependant on. Change this date to effect all the other methods of the class. By default the date is set to the system's current time.
* The internal date object that all the calculations are dependant on. Change this date to effect all the other methods of the class. By default the date is set to the system's current time with the system's current timezone.
*/
var workingDate:Date = Date()

/**
* By default the date is set to the system's current time with the system's current timezone. However, if you are using this class for a working date in another time zone. You must set the timezone as well as the date can change.
*/
var timeZone:TimeZone = TimeZone.current

/**
* Resets this date to the current system date.
*/
Expand Down Expand Up @@ -721,6 +726,17 @@ public class JewishCalendar {
self.workingDate = workingDate
}

/**
* A constructor that initializes the date to the Date parameter. useModernHolidays and inIsrael will be set to false
*
* @param date
* the <code>Date</code> to set the calendar to
*/
init(workingDate:Date, timezone:TimeZone) {
self.workingDate = workingDate
self.timeZone = timezone
}

/**
* A constructor that initializes the date to the Date parameter.
*
Expand All @@ -734,6 +750,20 @@ public class JewishCalendar {
self.useModernHolidays = useModernHolidays
}

/**
* A constructor that initializes the date to the Date parameter.
*
* @param date the <code>Date</code> to set the calendar to
* @param inIsrael a bool to determine whether or not the methods should use in Israel calculations
* @param shouldUseModernHolidays a bool to determine to use modern holidays in the methods or not
*/
init(workingDate:Date, timezone:TimeZone, inIsrael:Bool, useModernHolidays:Bool) {
self.workingDate = workingDate
self.inIsrael = inIsrael
self.useModernHolidays = useModernHolidays
self.timeZone = timezone
}

/**
* A constructor that initializes the date to the Date parameter. useModernHolidays and inIsrael will be set to false
*
Expand All @@ -742,7 +772,8 @@ public class JewishCalendar {
* @param shouldUseModernHolidays a bool to determine to use modern holidays in the methods or not
*/
init(jewishYear:Int, jewishMonth:Int, jewishDayOfMonth:Int) {//Test this
let hebrewCalendar = Calendar(identifier: .hebrew)
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(from: DateComponents(calendar: hebrewCalendar, year: jewishYear, month: jewishMonth, day: jewishDayOfMonth))!
}

Expand All @@ -755,7 +786,8 @@ public class JewishCalendar {
* @param isInIsrael a bool to determine whether or not the methods should use in Israel calculations
*/
init(jewishYear:Int, jewishMonth:Int, jewishDayOfMonth:Int, isInIsrael:Bool) {//Test this
let hebrewCalendar = Calendar(identifier: .hebrew)
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(from: DateComponents(calendar: hebrewCalendar, year: jewishYear, month: jewishMonth, day: jewishDayOfMonth))!
inIsrael = isInIsrael
}
Expand All @@ -768,7 +800,9 @@ public class JewishCalendar {
* and goes to 13 for Adar II
*/
public func setJewishMonth(month:Int) {
workingDate = Calendar(identifier: .hebrew).date(bySetting: .month, value: month, of: workingDate)!
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(bySetting: .month, value: month, of: workingDate)!
}

/**
Expand All @@ -778,7 +812,9 @@ public class JewishCalendar {
* the Jewish year
*/
public func setJewishYear(year:Int) {
workingDate = Calendar(identifier: .hebrew).date(bySetting: .year, value: year, of: workingDate)!
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(bySetting: .year, value: year, of: workingDate)!
}

/**
Expand All @@ -788,7 +824,9 @@ public class JewishCalendar {
* the Jewish day of month
*/
public func setJewishDayOfMonth(dayOfMonth:Int) {
workingDate = Calendar(identifier: .hebrew).date(bySetting: .day, value: dayOfMonth, of: workingDate)!
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(bySetting: .day, value: dayOfMonth, of: workingDate)!
}

/**
Expand All @@ -799,7 +837,9 @@ public class JewishCalendar {
* goes to 13 for Adar II
*/
public func getJewishMonth() -> Int {
return Calendar(identifier: .hebrew).component(.month, from: workingDate);
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
return hebrewCalendar.component(.month, from: workingDate);
}

/**
Expand All @@ -808,7 +848,9 @@ public class JewishCalendar {
* @return the Jewish day of the month
*/
public func getJewishDayOfMonth() -> Int {
return Calendar(identifier: .hebrew).component(.day, from: workingDate);
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
return hebrewCalendar.component(.day, from: workingDate);
}

/**
Expand All @@ -817,15 +859,19 @@ public class JewishCalendar {
* @return the Jewish year
*/
public func getJewishYear() -> Int {
return Calendar(identifier: .hebrew).component(.year, from: workingDate);
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
return hebrewCalendar.component(.year, from: workingDate);
}

/**
* Forward the Jewish date by the number of months passed in.
* @param amount the number of months to roll the month forward
*/
private func forwardJewishMonth(amount:Int) {
workingDate = Calendar(identifier: .hebrew).date(byAdding: .month, value: amount, to: workingDate)!
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(byAdding: .month, value: amount, to: workingDate)!
}

/**
Expand All @@ -834,7 +880,9 @@ public class JewishCalendar {
* @return the Gregorian month (between 0-11).
*/
public func getGregorianMonth() -> Int {
return Calendar(identifier: .gregorian).component(.month, from: workingDate)
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.component(.month, from: workingDate)
}

/**
Expand All @@ -843,7 +891,9 @@ public class JewishCalendar {
* @return the Gregorian day of the mont
*/
public func getGregorianDayOfMonth() -> Int {
return Calendar(identifier: .gregorian).component(.day, from: workingDate)
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.component(.day, from: workingDate)
}

/**
Expand All @@ -852,7 +902,9 @@ public class JewishCalendar {
* @return the Gregorian year
*/
public func getGregorianYear() -> Int {
return Calendar(identifier: .gregorian).component(.year, from: workingDate)
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.component(.year, from: workingDate)
}

/**
Expand All @@ -863,7 +915,9 @@ public class JewishCalendar {
*
*/
public func setGregorianMonth(month:Int) {
workingDate = Calendar(identifier: .gregorian).date(bySetting: .month, value: month, of: workingDate)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
workingDate = gregCalendar.date(bySetting: .month, value: month, of: workingDate)!
}

/**
Expand All @@ -873,7 +927,9 @@ public class JewishCalendar {
* the Gregorian year.
*/
public func setGregorianYear(year:Int) {
workingDate = Calendar(identifier: .gregorian).date(bySetting: .year, value: year, of: workingDate)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
workingDate = gregCalendar.date(bySetting: .year, value: year, of: workingDate)!
}

/**
Expand All @@ -883,7 +939,9 @@ public class JewishCalendar {
* the Gregorian Day of month.
*/
public func setGregorianDayOfMonth(dayOfMonth:Int) {
workingDate = Calendar(identifier: .gregorian).date(bySetting: .day, value: dayOfMonth, of: workingDate)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
workingDate = gregCalendar.date(bySetting: .day, value: dayOfMonth, of: workingDate)!
}

/**
Expand All @@ -898,7 +956,9 @@ public class JewishCalendar {
* the month will be set
*/
public func setGregorianDate(year:Int, month:Int, dayOfMonth:Int) {
workingDate = Calendar(identifier: .gregorian).date(from: DateComponents(year: year, month: month, day: dayOfMonth))!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
workingDate = gregCalendar.date(from: DateComponents(year: year, month: month, day: dayOfMonth))!
}

/**
Expand All @@ -915,7 +975,9 @@ public class JewishCalendar {
* has 29 days, the day will be set as 29.
*/
public func setJewishDate(year:Int, month:Int, dayOfMonth:Int) {
workingDate = Calendar(identifier: .hebrew).date(from: DateComponents(year: year, month: month, day: dayOfMonth))!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
workingDate = gregCalendar.date(from: DateComponents(year: year, month: month, day: dayOfMonth))!
}

/**
Expand All @@ -941,7 +1003,9 @@ public class JewishCalendar {
*
*/
public func setJewishDate(year:Int, month:Int, dayOfMonth:Int, hours:Int, minutes:Int, chalakim:Int) {
workingDate = Calendar(identifier: .hebrew).date(from: DateComponents(year: year, month: month, day: dayOfMonth, hour: hours, minute: minutes + (chalakim / 18)))!//Need to test the chalakim
var hebrewCalendar = Calendar(identifier: .hebrew)
hebrewCalendar.timeZone = timeZone
workingDate = hebrewCalendar.date(from: DateComponents(year: year, month: month, day: dayOfMonth, hour: hours, minute: minutes + (chalakim / 18)))!//Need to test the chalakim
}

/**
Expand All @@ -950,7 +1014,9 @@ public class JewishCalendar {
* @return the day of the week as a number between 1-7.
*/
public func getDayOfWeek() -> Int {
return Calendar(identifier: .gregorian).component(.weekday, from: workingDate);
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.component(.weekday, from: workingDate);
}

/**
Expand Down Expand Up @@ -1155,7 +1221,9 @@ public class JewishCalendar {
* @return the last day of the Gregorian month
*/
func getLastDayOfGregorianMonth(month:Int) -> Int {
return getLastDayOfGregorianMonth(month: month, year: Calendar(identifier: .gregorian).component(.year, from: workingDate));
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return getLastDayOfGregorianMonth(month: month, year: gregCalendar.component(.year, from: workingDate));
}

/**
Expand Down Expand Up @@ -2158,7 +2226,9 @@ public class JewishCalendar {
*/
public func getTchilasZmanKidushLevana3Days() -> Date {
let molad = getMoladAsDate();
return Calendar(identifier: .gregorian).date(byAdding: .day, value: 3, to: molad)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.date(byAdding: .day, value: 3, to: molad)!
}

/**
Expand All @@ -2175,7 +2245,9 @@ public class JewishCalendar {
*/
public func getTchilasZmanKidushLevana7Days() -> Date {
let molad = getMoladAsDate();
return Calendar(identifier: .gregorian).date(byAdding: .day, value: 7, to: molad)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.date(byAdding: .day, value: 7, to: molad)!
}

/**
Expand All @@ -2195,7 +2267,8 @@ public class JewishCalendar {
*/
public func getSofZmanKidushLevanaBetweenMoldos() -> Date {
let molad = getMoladAsDate();
let gregCalendar = Calendar(identifier: .gregorian)
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
// add half the time between molad and molad (half of 29 days, 12 hours and 793 chalakim (44 minutes, 3.3
// seconds), or 14 days, 18 hours, 22 minutes and 666 milliseconds). Add it as hours, not days, to avoid
// DST/ST crossover issues.
Expand Down Expand Up @@ -2224,7 +2297,9 @@ public class JewishCalendar {
*/
public func getSofZmanKidushLevana15Days() -> Date {
let molad = getMoladAsDate();
return Calendar(identifier: .gregorian).date(byAdding: .day, value: 7, to: molad)!
var gregCalendar = Calendar(identifier: .gregorian)
gregCalendar.timeZone = timeZone
return gregCalendar.date(byAdding: .day, value: 7, to: molad)!
}

/**
Expand Down
14 changes: 14 additions & 0 deletions KosherSwiftTests/KosherSwiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ class KosherSwiftTests: XCTestCase {
XCTAssertEqual(jewishCalendar.getGregorianDayOfMonth(), 25)
}

func testGregorianDateChangeWithTimzone() {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "America/New_York")!
var comp = DateComponents()
comp.setValue(2023, for: .year)
comp.setValue(12, for: .month)
comp.setValue(24, for: .day)
jewishCalendar.workingDate = calendar.date(from: comp)!
jewishCalendar.timeZone = TimeZone(identifier: "America/New_York")!
XCTAssertEqual(jewishCalendar.getGregorianYear(), 2023)
XCTAssertEqual(jewishCalendar.getGregorianMonth(), 12)
XCTAssertEqual(jewishCalendar.getGregorianDayOfMonth(), 24)
}

func testHebrewDateChange() {
jewishCalendar.setJewishDate(year: 5784, month: JewishCalendar.TEVES, dayOfMonth: 5)
XCTAssertEqual(jewishCalendar.getJewishYear(), 5784)
Expand Down

0 comments on commit dcfb71e

Please sign in to comment.