├── .gitignore ├── go.mod ├── go.sum ├── 2-asr.go ├── 6-utils-slice.go ├── LICENSE ├── 5-high-lat-nearest-day.go ├── internal └── datatest │ ├── common.go │ ├── tromso.go │ └── london.go ├── 5-high-lat-nearest-latitude-as-is.go ├── 5-high-lat-seventh-night.go ├── 5-high-lat-middle-night.go ├── scripts └── test-gen │ ├── location.go │ └── main.go ├── example └── main.go ├── 5-high-lat-mecca-always.go ├── 5-high-lat-angle-based.go ├── 5-high-lat-nearest-latitude.go ├── 5-high-lat-shari-day.go ├── 6-abnormal-schedules.go ├── 4-normal.go ├── 0-root_test.go ├── 1-twilight.go ├── 0-root.go ├── 5-high-lat-local-relative.go ├── 5-high-lat-mecca.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hablullah/go-prayer 2 | 3 | go 1.20 4 | 5 | require github.com/hablullah/go-juliandays v1.0.1-0.20220316153050-f56193695a5b // indirect 6 | 7 | require github.com/hablullah/go-sampa v1.0.0 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/hablullah/go-juliandays v1.0.1-0.20220316153050-f56193695a5b h1:Qp6WC5idnPxaUQpX50s+1jrrjIqaCSuCu2BkQgGx/tQ= 2 | github.com/hablullah/go-juliandays v1.0.1-0.20220316153050-f56193695a5b/go.mod h1:0JOYq4oFOuDja+oospuc61YoX+uNEn7Z6uHYTbBzdGc= 3 | github.com/hablullah/go-sampa v0.0.0-20230520122823-970ebed37f51 h1:BFsDqUioPKInNAsQ2EaEIAAJYJeakalheEVLt+TKZPw= 4 | github.com/hablullah/go-sampa v0.0.0-20230520122823-970ebed37f51/go.mod h1:NgDnpqL95HgRPkal510TVk7tI6+aLwO3wJgoj0dQ4Pc= 5 | github.com/hablullah/go-sampa v1.0.0 h1:8SiiPC7LktYsBYkoitGGPRL416TDXjkECRZsAkUbgy4= 6 | github.com/hablullah/go-sampa v1.0.0/go.mod h1:NgDnpqL95HgRPkal510TVk7tI6+aLwO3wJgoj0dQ4Pc= 7 | -------------------------------------------------------------------------------- /2-asr.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | // AsrConvention is the convention for calculating Asr time. 4 | type AsrConvention int 5 | 6 | const ( 7 | // Shafii is the school which said that the Asr time is when the shadow of an 8 | // object is equals the length of the object plus the length of its shadow when 9 | // the Sun is at its zenith. 10 | Shafii AsrConvention = iota 11 | 12 | // Hanafi is the school which said that the Asr time is when the shadow of an 13 | // object is twice the length of the object plus the length of its shadow when 14 | // the Sun is at its zenith. 15 | Hanafi 16 | ) 17 | 18 | func getAsrCoefficient(cv AsrConvention) float64 { 19 | if cv == Hanafi { 20 | return 2 21 | } 22 | return 1 23 | } 24 | -------------------------------------------------------------------------------- /6-utils-slice.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | func sliceRealIdx[T any](arr []T, idx int) int { 4 | arrLen := len(arr) 5 | 6 | if idx < 0 { 7 | for { 8 | idx += arrLen 9 | if idx >= 0 { 10 | return idx 11 | } 12 | } 13 | } 14 | 15 | if idx >= arrLen { 16 | for { 17 | idx -= arrLen 18 | if idx < arrLen { 19 | return idx 20 | } 21 | } 22 | } 23 | 24 | return idx 25 | } 26 | 27 | func sliceAt[T any](arr []T, idx int) T { 28 | realIdx := sliceRealIdx(arr, idx) 29 | return arr[realIdx] 30 | } 31 | 32 | func firstSliceItem[T any](arr []T) (T, bool) { 33 | var zero T 34 | if len(arr) == 0 { 35 | return zero, false 36 | } 37 | return arr[0], true 38 | } 39 | 40 | func lastSliceItem[T any](arr []T) (T, bool) { 41 | var zero T 42 | if len(arr) == 0 { 43 | return zero, false 44 | } 45 | return arr[len(arr)-1], true 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Radhi Fadlillah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /5-high-lat-nearest-day.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | // NearestDay is adapter where the schedule for "abnormal" days will be taken from the 4 | // schedule of the last "normal" day. 5 | // 6 | // This adapter doesn't require the sunrise and sunset to be exist in a day, so it's 7 | // usable for area in extreme latitudes (>=65 degrees). 8 | // 9 | // Reference: https://www.islamicity.com/prayertimes/Salat.pdf 10 | func NearestDay() HighLatitudeAdapter { 11 | return highLatNearestDay 12 | } 13 | 14 | func highLatNearestDay(_ Config, _ int, schedules []Schedule) []Schedule { 15 | abnormalSummer, abnormalWinter := extractAbnormalSchedules(schedules) 16 | 17 | for _, as := range []abnormalRange{abnormalSummer, abnormalWinter} { 18 | // If this abnormal period is empty, skip 19 | if as.IsEmpty() { 20 | continue 21 | } 22 | 23 | // Get the last normal schedule 24 | abnormalIdxStart := as.Indexes[0] 25 | lastNormalSchedule := sliceAt(schedules, abnormalIdxStart-1) 26 | 27 | // Use the last normal schedule for the entire abnormal period 28 | for _, idx := range as.Indexes { 29 | schedules[idx] = lastNormalSchedule 30 | } 31 | } 32 | 33 | return schedules 34 | } 35 | -------------------------------------------------------------------------------- /internal/datatest/common.go: -------------------------------------------------------------------------------- 1 | package datatest 2 | 3 | import ( 4 | "regexp" 5 | "strconv" 6 | "time" 7 | 8 | "github.com/hablullah/go-prayer" 9 | ) 10 | 11 | var rxDT = regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})`) 12 | 13 | type TestData struct { 14 | Name string 15 | Latitude float64 16 | Longitude float64 17 | Timezone *time.Location 18 | Schedules []prayer.Schedule 19 | } 20 | 21 | func schedule(date string, fajr, sunrise, zuhr, asr, maghrib, isha string, tz *time.Location) prayer.Schedule { 22 | return prayer.Schedule{ 23 | Date: date, 24 | Fajr: st(fajr, tz), 25 | Sunrise: st(sunrise, tz), 26 | Zuhr: st(zuhr, tz), 27 | Asr: st(asr, tz), 28 | Maghrib: st(maghrib, tz), 29 | Isha: st(isha, tz), 30 | } 31 | } 32 | 33 | func st(s string, tz *time.Location) time.Time { 34 | parts := rxDT.FindStringSubmatch(s) 35 | if len(parts) != 7 { 36 | return time.Time{} 37 | } 38 | 39 | year, _ := strconv.Atoi(parts[1]) 40 | month, _ := strconv.Atoi(parts[2]) 41 | day, _ := strconv.Atoi(parts[3]) 42 | hour, _ := strconv.Atoi(parts[4]) 43 | minute, _ := strconv.Atoi(parts[5]) 44 | second, _ := strconv.Atoi(parts[6]) 45 | return time.Date(year, time.Month(month), day, hour, minute, second, 0, tz) 46 | } 47 | -------------------------------------------------------------------------------- /5-high-lat-nearest-latitude-as-is.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | // NearestLatitudeAsIs is similar with `NearestLatitude` except it will use the 4 | // schedule from 45 degrees latitude as it is without any change. Like `NearestLatitude`, 5 | // this method will change the schedule for entire year to prevent sudden changes in 6 | // fasting time. 7 | // 8 | // This adapter doesn't require the sunrise and sunset to be exist in a day, so it's 9 | // usable for area in extreme latitudes (>=65 degrees). 10 | // 11 | // Reference: https://fiqh.islamonline.net/en/praying-and-fasting-at-high-latitudes/ 12 | func NearestLatitudeAsIs() HighLatitudeAdapter { 13 | return highLatNearestLatitudeAsIs 14 | } 15 | 16 | func highLatNearestLatitudeAsIs(cfg Config, year int, _ []Schedule) []Schedule { 17 | // Get the nearest latitude 18 | latitude := cfg.Latitude 19 | if latitude > 45 { 20 | latitude = 45 21 | } else if latitude < -45 { 22 | latitude = -45 23 | } 24 | 25 | // Calculate schedule for the nearest latitude 26 | newCfg := Config{ 27 | Latitude: latitude, 28 | Longitude: cfg.Longitude, 29 | Timezone: cfg.Timezone, 30 | TwilightConvention: cfg.TwilightConvention, 31 | AsrConvention: cfg.AsrConvention} 32 | newSchedules, _ := calcNormal(newCfg, year) 33 | return newSchedules 34 | } 35 | -------------------------------------------------------------------------------- /5-high-lat-seventh-night.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // OneSeventhNight is adapter where the night period is divided into seven parts. 8 | // Isha starts when the first seventh part ends, and Fajr starts when the last seventh 9 | // part starts. 10 | // 11 | // This adapter depends on sunrise and sunset time, so it might not be suitable for 12 | // area in extreme latitudes (>=65 degrees). 13 | // 14 | // Reference: http://praytimes.org/calculation 15 | func OneSeventhNight() HighLatitudeAdapter { 16 | return highLatOneSeventhNight 17 | } 18 | 19 | func highLatOneSeventhNight(_ Config, _ int, schedules []Schedule) []Schedule { 20 | for i, s := range schedules { 21 | // Seventh night require Sunrise and Maghrib, and only done if Fajr or Isha missing 22 | if !s.Sunrise.IsZero() && !s.Maghrib.IsZero() && (s.Fajr.IsZero() || s.Isha.IsZero()) { 23 | // Calculate night duration 24 | dayDuration := s.Maghrib.Sub(s.Sunrise).Seconds() 25 | nightDuration := float64(24*60*60) - dayDuration 26 | 27 | // Calculate Fajr and Isha time 28 | seventhDuration := time.Duration(nightDuration / 7 * float64(time.Second)) 29 | schedules[i].Fajr = s.Sunrise.Add(-seventhDuration) 30 | schedules[i].Isha = s.Maghrib.Add(seventhDuration) 31 | } 32 | } 33 | 34 | return schedules 35 | } 36 | -------------------------------------------------------------------------------- /5-high-lat-middle-night.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // MiddleNight is adapter where the night period is divided into two halves. The 8 | // first half is considered to be the "night" and the other half as "day break". 9 | // Fajr and Isha in this method are assumed to be at mid-night during the abnormal 10 | // periods. 11 | // 12 | // This adapter depends on sunrise and sunset time, so it might not be suitable for 13 | // area in extreme latitudes (>=65 degrees). 14 | // 15 | // Reference: http://praytimes.org/calculation 16 | func MiddleNight() HighLatitudeAdapter { 17 | return highLatMiddleNight 18 | } 19 | 20 | func highLatMiddleNight(_ Config, _ int, schedules []Schedule) []Schedule { 21 | for i, s := range schedules { 22 | // Middle night require Sunrise and Maghrib, and only done if Fajr or Isha missing 23 | if !s.Sunrise.IsZero() && !s.Maghrib.IsZero() && (s.Fajr.IsZero() || s.Isha.IsZero()) { 24 | // Calculate night duration 25 | dayDuration := s.Maghrib.Sub(s.Sunrise).Seconds() 26 | nightDuration := float64(24*60*60) - dayDuration 27 | 28 | // Calculate Fajr and Isha time 29 | halfDuration := time.Duration(nightDuration * 0.5 * float64(time.Second)) 30 | schedules[i].Fajr = s.Sunrise.Add(-halfDuration) 31 | schedules[i].Isha = s.Maghrib.Add(halfDuration) 32 | } 33 | } 34 | 35 | return schedules 36 | } 37 | -------------------------------------------------------------------------------- /scripts/test-gen/location.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hablullah/go-prayer" 7 | ) 8 | 9 | type Location struct { 10 | Name string 11 | Timezone string 12 | Latitude float64 13 | Longitude float64 14 | } 15 | 16 | var testLocations = []Location{ 17 | { // Tromso (Norway) is representation for location in North Frigid area 18 | Name: "Tromso", 19 | Timezone: "CET", 20 | Latitude: 69.682778, 21 | Longitude: 18.942778, 22 | }, { // London (UK) is representation for location in North Temperate area 23 | Name: "London", 24 | Timezone: "Europe/London", 25 | Latitude: 51.507222, 26 | Longitude: -0.1275, 27 | }, { // Jakarta (Indonesia) is representation for location in Torrid area 28 | Name: "Jakarta", 29 | Timezone: "Asia/Jakarta", 30 | Latitude: -6.175, 31 | Longitude: 106.825, 32 | }, { // Wellington (New Zealand) is representation for location in South Temperate area 33 | Name: "Wellington", 34 | Timezone: "Pacific/Auckland", 35 | Latitude: -41.288889, 36 | Longitude: 174.777222, 37 | }, 38 | } 39 | 40 | func getSchedules(loc Location) []prayer.Schedule { 41 | tz, _ := time.LoadLocation(loc.Timezone) 42 | schedules, _ := prayer.Calculate(prayer.Config{ 43 | Latitude: loc.Latitude, 44 | Longitude: loc.Longitude, 45 | Timezone: tz, 46 | TwilightConvention: prayer.AstronomicalTwilight(), 47 | AsrConvention: prayer.Shafii, 48 | HighLatitudeAdapter: prayer.NearestLatitude(), 49 | PreciseToSeconds: true, 50 | }, 2023) 51 | return schedules 52 | } 53 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/hablullah/go-prayer" 8 | ) 9 | 10 | func main() { 11 | // Calculate prayer schedule in Jakarta for 2023. 12 | asiaJakarta, _ := time.LoadLocation("Asia/Jakarta") 13 | jakartaSchedules, _ := prayer.Calculate(prayer.Config{ 14 | Latitude: -6.14, 15 | Longitude: 106.81, 16 | Timezone: asiaJakarta, 17 | TwilightConvention: prayer.Kemenag(), 18 | AsrConvention: prayer.Shafii, 19 | PreciseToSeconds: true, 20 | }, 2023) 21 | print(jakartaSchedules) 22 | 23 | // Calculate prayer schedule in London for 2023. 24 | // Since London in higher latitude, make sure to enable the adapter. 25 | europeLondon, _ := time.LoadLocation("Europe/London") 26 | londonSchedules, _ := prayer.Calculate(prayer.Config{ 27 | Latitude: 51.507222, 28 | Longitude: -0.1275, 29 | Timezone: europeLondon, 30 | TwilightConvention: prayer.ISNA(), 31 | AsrConvention: prayer.Shafii, 32 | HighLatitudeAdapter: prayer.NearestLatitude(), 33 | PreciseToSeconds: true, 34 | }, 2023) 35 | print(londonSchedules) 36 | } 37 | 38 | func print(schedules []prayer.Schedule) { 39 | for _, s := range schedules { 40 | fmt.Println( 41 | "'"+s.Date+"'", 42 | s.Fajr.Format("'2006-01-02 15:04:05'"), 43 | s.Sunrise.Format("'2006-01-02 15:04:05'"), 44 | s.Zuhr.Format("'2006-01-02 15:04:05'"), 45 | s.Asr.Format("'2006-01-02 15:04:05'"), 46 | s.Maghrib.Format("'2006-01-02 15:04:05'"), 47 | s.Isha.Format("'2006-01-02 15:04:05'"), 48 | ) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /5-high-lat-mecca-always.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // AlwaysMecca is similar with `Mecca`, except it will be applied every day and not 8 | // only on the "abnormal" days. 9 | // 10 | // This adapter doesn't require the sunrise and sunset to be exist in a day, so it's 11 | // usable for area in extreme latitudes (>=65 degrees). 12 | func AlwaysMecca() HighLatitudeAdapter { 13 | return highLatAlwaysMecca 14 | } 15 | 16 | func highLatAlwaysMecca(cfg Config, year int, schedules []Schedule) []Schedule { 17 | // Calculate schedule for Mecca 18 | meccaTz, _ := time.LoadLocation("Asia/Riyadh") 19 | meccaCfg := Config{ 20 | Latitude: 21.425506007708996, 21 | Longitude: 39.8254579358597, 22 | Timezone: meccaTz, 23 | TwilightConvention: cfg.TwilightConvention, 24 | AsrConvention: cfg.AsrConvention} 25 | meccaSchedules, _ := calcNormal(meccaCfg, year) 26 | 27 | // Apply schedules to current location, by matching it with duration in Mecca 28 | // using transit time (noon) as the base. 29 | for i, s := range schedules { 30 | // Calculate duration from Mecca schedule 31 | ms := meccaSchedules[i] 32 | msFajrTransit := ms.Zuhr.Sub(ms.Fajr) 33 | msRiseTransit := ms.Zuhr.Sub(ms.Sunrise) 34 | msTransitAsr := ms.Asr.Sub(ms.Zuhr) 35 | msTransitMaghrib := ms.Maghrib.Sub(ms.Zuhr) 36 | msTransitIsha := ms.Isha.Sub(ms.Zuhr) 37 | 38 | // Apply Mecca times 39 | s.Fajr = s.Zuhr.Add(-msFajrTransit) 40 | s.Sunrise = s.Zuhr.Add(-msRiseTransit) 41 | s.Asr = s.Zuhr.Add(msTransitAsr) 42 | s.Maghrib = s.Zuhr.Add(msTransitMaghrib) 43 | s.Isha = s.Zuhr.Add(msTransitIsha) 44 | schedules[i] = s 45 | } 46 | 47 | return schedules 48 | } 49 | -------------------------------------------------------------------------------- /5-high-lat-angle-based.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // AngleBased is adapter where the night period is divided into several parts, 8 | // depending on the value of twilight angle for Fajr and Isha. 9 | // 10 | // For example, let a be the twilight angle for Isha, and let t = a/60. The period 11 | // between sunset and sunrise is divided into t parts. Isha begins after the first 12 | // part. So, if the twilight angle for Isha is 15, then Isha begins at the end of the 13 | // first quarter (15/60) of the night. Time for Fajr is calculated similarly. 14 | // 15 | // This adapter depends on sunrise and sunset time, so it might not be suitable for 16 | // area in extreme latitudes (>=65 degrees). 17 | // 18 | // Reference: http://praytimes.org/calculation 19 | func AngleBased() HighLatitudeAdapter { 20 | return highLatAngleBased 21 | } 22 | 23 | func highLatAngleBased(cfg Config, year int, schedules []Schedule) []Schedule { 24 | // Fetch the twilight angle 25 | var fajrAngle, ishaAngle float64 26 | if cfg.TwilightConvention != nil { 27 | fajrAngle = cfg.TwilightConvention.FajrAngle 28 | ishaAngle = cfg.TwilightConvention.IshaAngle 29 | } 30 | 31 | // If twilight angle missing, use the astronomical twilight 32 | astronomical := AstronomicalTwilight() 33 | if fajrAngle == 0 { 34 | fajrAngle = astronomical.FajrAngle 35 | } 36 | 37 | if ishaAngle == 0 { 38 | ishaAngle = astronomical.IshaAngle 39 | } 40 | 41 | // Apply schedules 42 | for i, s := range schedules { 43 | // Angle based require Sunrise and Maghrib, and only done if Fajr or Isha missing 44 | if !s.Sunrise.IsZero() && !s.Maghrib.IsZero() && (s.Fajr.IsZero() || s.Isha.IsZero()) { 45 | // Calculate night duration 46 | dayDuration := s.Maghrib.Sub(s.Sunrise).Seconds() 47 | nightDuration := float64(24*60*60) - dayDuration 48 | 49 | // Calculate Fajr time 50 | fajrPercentage := fajrAngle / 60 51 | fajrDuration := nightDuration * fajrPercentage * float64(time.Second) 52 | schedules[i].Fajr = s.Sunrise.Add(-time.Duration(fajrDuration)) 53 | 54 | // Calculate Isha time 55 | ishaPercentage := ishaAngle / 60 56 | ishaDuration := nightDuration * ishaPercentage * float64(time.Second) 57 | schedules[i].Isha = s.Maghrib.Add(time.Duration(ishaDuration)) 58 | } 59 | } 60 | 61 | return schedules 62 | } 63 | -------------------------------------------------------------------------------- /5-high-lat-nearest-latitude.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // NearestLatitude is adapter where the schedules will be estimated using percentage 8 | // of schedule in location at 45 degrees latitude. This method will change the schedule 9 | // for entire year to prevent sudden changes in fasting time. 10 | // 11 | // This adapter only estimates time for Isha and Fajr and require sunrise and sunset 12 | // time. Therefore it's not suitable for area in extreme latitude (>=65 degrees). 13 | // 14 | // Reference: https://fiqh.islamonline.net/en/praying-and-fasting-at-high-latitudes/ 15 | func NearestLatitude() HighLatitudeAdapter { 16 | return highLatNearestLatitude 17 | } 18 | 19 | func highLatNearestLatitude(cfg Config, year int, schedules []Schedule) []Schedule { 20 | // This conventions only works if daytime exists (in other words, sunrise 21 | // and Maghrib must exist). So if there are days where those time don't 22 | // exist, stop and just return the schedule as it is. 23 | // TODO: maybe put some warning log later. 24 | for _, s := range schedules { 25 | if s.Sunrise.IsZero() || s.Maghrib.IsZero() { 26 | return schedules 27 | } 28 | } 29 | 30 | // Get the nearest latitude 31 | latitude := cfg.Latitude 32 | if latitude > 45 { 33 | latitude = 45 34 | } else if latitude < -45 { 35 | latitude = -45 36 | } 37 | 38 | // Calculate schedule for the nearest latitude 39 | newCfg := Config{ 40 | Latitude: latitude, 41 | Longitude: cfg.Longitude, 42 | Timezone: cfg.Timezone, 43 | TwilightConvention: cfg.TwilightConvention, 44 | AsrConvention: cfg.AsrConvention} 45 | nearestSchedules, _ := calcNormal(newCfg, year) 46 | 47 | for i := range schedules { 48 | // Calculate duration from schedule of nearest latitude 49 | ns := nearestSchedules[i] 50 | nsDay := ns.Maghrib.Sub(ns.Sunrise).Seconds() 51 | nsFajrRise := ns.Sunrise.Sub(ns.Fajr).Seconds() 52 | nsMaghribIsha := ns.Isha.Sub(ns.Maghrib).Seconds() 53 | 54 | nsNight := 24*60*60 - nsDay 55 | nsFajrPercentage := nsFajrRise / nsNight 56 | nsIshaPercentage := nsMaghribIsha / nsNight 57 | 58 | // Calculate duration from current schedule 59 | s := schedules[i] 60 | sDay := s.Maghrib.Sub(s.Sunrise).Seconds() 61 | sNight := 24*60*60 - sDay 62 | 63 | // Apply the new durations 64 | fajrDuration := time.Duration(sNight * nsFajrPercentage * float64(time.Second)) 65 | ishaDuration := time.Duration(sNight * nsIshaPercentage * float64(time.Second)) 66 | s.Fajr = s.Sunrise.Add(-fajrDuration) 67 | s.Isha = s.Maghrib.Add(ishaDuration) 68 | schedules[i] = s 69 | } 70 | 71 | return schedules 72 | } 73 | -------------------------------------------------------------------------------- /5-high-lat-shari-day.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import "time" 4 | 5 | // ShariNormalDay is adapter following method that proposed by Mohamed Nabeel 6 | // Tarabishy, Ph.D. 7 | // 8 | // He proposes that a normal day is defined as day when the fasting period is between 9 | // 10h17m and 17h36m. If the day is "abnormal" then the fasting times is calculated 10 | // using the schedule for area with 45 degrees latitude. 11 | // 12 | // This adapter doesn't require the sunrise and sunset to be exist in a day, so it's 13 | // usable for area in extreme latitudes (>=65 degrees). 14 | // 15 | // Do note in this method there will be sudden changes in the length of the day of 16 | // fasting. To avoid this issue, the author has given suggestion to just use the 17 | // schedule from 45° on permanent basis. So, following that suggestion, you might be 18 | // better using other adapter like `NearestLatitude` or `NearestLatitudeAsIs`. 19 | // 20 | // Reference: https://www.astronomycenter.net/pdf/tarabishyshigh_2014.pdf 21 | func ShariNormalDay() HighLatitudeAdapter { 22 | return highLatShariNormalDay 23 | } 24 | 25 | func highLatShariNormalDay(cfg Config, year int, schedules []Schedule) []Schedule { 26 | // Get the nearest latitude 27 | latitude := cfg.Latitude 28 | if latitude > 45 { 29 | latitude = 45 30 | } else if latitude < -45 { 31 | latitude = -45 32 | } 33 | 34 | // Calculate schedule for the nearest latitude 35 | newCfg := Config{ 36 | Latitude: latitude, 37 | Longitude: cfg.Longitude, 38 | Timezone: cfg.Timezone, 39 | TwilightConvention: cfg.TwilightConvention, 40 | AsrConvention: cfg.AsrConvention} 41 | nearestSchedules, _ := calcNormal(newCfg, year) 42 | 43 | // Apply schedules for the abnormal days using schedules from nearest latitude 44 | // with transit as common point. 45 | minFastingDuration := 10*time.Hour + 17*time.Minute 46 | maxFastingDuration := 17*time.Hour + 36*time.Minute 47 | for i, s := range schedules { 48 | // If day is normal, just continue 49 | fastingDuration := s.Maghrib.Sub(s.Fajr) 50 | if s.IsNormal && fastingDuration >= minFastingDuration && fastingDuration <= maxFastingDuration { 51 | continue 52 | } 53 | 54 | // Calculate duration from schedule for nearest latitude 55 | ns := nearestSchedules[i] 56 | nsFajrTransit := ns.Zuhr.Sub(ns.Fajr) 57 | nsRiseTransit := ns.Zuhr.Sub(ns.Sunrise) 58 | nsTransitAsr := ns.Asr.Sub(ns.Zuhr) 59 | nsTransitMaghrib := ns.Maghrib.Sub(ns.Zuhr) 60 | nsTransitIsha := ns.Isha.Sub(ns.Zuhr) 61 | 62 | // Apply durations 63 | s.Fajr = s.Zuhr.Add(-nsFajrTransit) 64 | s.Sunrise = s.Zuhr.Add(-nsRiseTransit) 65 | s.Asr = s.Zuhr.Add(nsTransitAsr) 66 | s.Maghrib = s.Zuhr.Add(nsTransitMaghrib) 67 | s.Isha = s.Zuhr.Add(nsTransitIsha) 68 | schedules[i] = s 69 | } 70 | 71 | return schedules 72 | } 73 | -------------------------------------------------------------------------------- /6-abnormal-schedules.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import "time" 4 | 5 | type abnormalRange struct { 6 | Start time.Time 7 | End time.Time 8 | Indexes []int 9 | } 10 | 11 | func (ar abnormalRange) IsEmpty() bool { 12 | return len(ar.Indexes) == 0 13 | } 14 | 15 | func extractAbnormalSchedules(schedules []Schedule) (abnormalSummer, abnormalWinter abnormalRange) { 16 | // If there are no schedules, return empty 17 | if len(schedules) == 0 { 18 | return 19 | } 20 | 21 | // Loop each schedule 22 | lastAbnormalIdx := -2 23 | var ranges []abnormalRange 24 | var currentRange abnormalRange 25 | for i, s := range schedules { 26 | // If schedule is normal, skip 27 | if s.IsNormal { 28 | continue 29 | } 30 | 31 | // If current schedule is continuation of the previous, just add the index 32 | if i == lastAbnormalIdx+1 { 33 | currentRange.End = s.Zuhr 34 | currentRange.Indexes = append(currentRange.Indexes, i) 35 | } else { 36 | // If current range is not empty, save it to range list 37 | if len(currentRange.Indexes) > 0 { 38 | ranges = append(ranges, currentRange) 39 | } 40 | 41 | // Re-initiate current range 42 | currentRange = abnormalRange{ 43 | Start: s.Zuhr, 44 | End: s.Zuhr, 45 | Indexes: []int{i}, 46 | } 47 | } 48 | 49 | lastAbnormalIdx = i 50 | } 51 | 52 | // Handle leftover range 53 | if len(currentRange.Indexes) > 0 { 54 | // Check if we can merge the leftover range to the first range: 55 | // - there are more than one range 56 | // - the first index of first range = zero 57 | // - the last index of current range = last schedule index 58 | // If we can't merge it, just append current range to the end 59 | if len(ranges) > 0 && 60 | ranges[0].Indexes[0] == 0 && 61 | currentRange.Indexes[len(currentRange.Indexes)-1] == len(schedules)-1 { 62 | ranges[0].Start = currentRange.Start.AddDate(-1, 0, 0) // move start to last year 63 | ranges[0].Indexes = append(currentRange.Indexes, ranges[0].Indexes...) 64 | } else { 65 | ranges = append(ranges, currentRange) 66 | } 67 | } 68 | 69 | // At this point we at most only have two abnormal periods: one for summer and one for winter 70 | for _, sr := range ranges { 71 | // Extract months in range 72 | months := make(map[int]int) 73 | for tmp := sr.Start; tmp.Before(sr.End.AddDate(0, 1, 0)); tmp = tmp.AddDate(0, 1, 0) { 74 | months[int(tmp.Month())] = 1 75 | } 76 | 77 | // Calculate score: 78 | // - Summer is in June, July and August 79 | // - Winter is in December, January and February 80 | summerScore := months[6] + months[7] + months[8] 81 | winterScore := months[12] + months[1] + months[2] 82 | 83 | switch { 84 | case summerScore == 3, summerScore > winterScore: 85 | abnormalSummer = sr 86 | case winterScore == 3, winterScore > summerScore: 87 | abnormalWinter = sr 88 | } 89 | } 90 | 91 | return 92 | } 93 | -------------------------------------------------------------------------------- /4-normal.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "math" 5 | "time" 6 | 7 | "github.com/hablullah/go-sampa" 8 | ) 9 | 10 | func calcNormal(cfg Config, year int) ([]Schedule, int) { 11 | // Prepare location 12 | location := sampa.Location{ 13 | Latitude: cfg.Latitude, 14 | Longitude: cfg.Longitude, 15 | Elevation: cfg.Elevation, 16 | } 17 | 18 | // Prepare custom Sun events 19 | customEvents := []sampa.CustomSunEvent{{ 20 | Name: "dawn", 21 | BeforeTransit: true, 22 | Elevation: func(sampa.SunPosition) float64 { return -18 }, 23 | }, { 24 | Name: "dusk", 25 | BeforeTransit: false, 26 | Elevation: func(sampa.SunPosition) float64 { return -18 }, 27 | }, { 28 | Name: "fajr", 29 | BeforeTransit: true, 30 | Elevation: func(sampa.SunPosition) float64 { return -cfg.TwilightConvention.FajrAngle }, 31 | }, { 32 | Name: "isha", 33 | BeforeTransit: false, 34 | Elevation: func(sampa.SunPosition) float64 { return -cfg.TwilightConvention.IshaAngle }, 35 | }, { 36 | Name: "asr", 37 | BeforeTransit: false, 38 | Elevation: func(todayData sampa.SunPosition) float64 { 39 | a := getAsrCoefficient(cfg.AsrConvention) 40 | b := math.Abs(todayData.TopocentricDeclination - cfg.Latitude) 41 | elevation := acot(a + math.Tan(degToRad(b))) 42 | return radToDeg(elevation) 43 | }, 44 | }} 45 | 46 | // Calculate schedules for each day in a year. 47 | start := time.Date(year, 1, 1, 0, 0, 0, 0, cfg.Timezone) 48 | limit := start.AddDate(1, 0, 0) 49 | nDays := int(limit.Sub(start).Hours() / 24) 50 | 51 | // Create slice to contain result 52 | schedules := make([]Schedule, nDays) 53 | 54 | // Calculate each day 55 | var idx int 56 | var nAbnormal int 57 | for dt := start; dt.Before(limit); dt = dt.AddDate(0, 0, 1) { 58 | // Calculate the events 59 | e, _ := sampa.GetSunEvents(dt, location, nil, customEvents...) 60 | 61 | // Create the prayer schedule 62 | s := Schedule{ 63 | Date: dt.Format("2006-01-02"), 64 | Fajr: e.Others["fajr"].DateTime, 65 | Sunrise: e.Sunrise.DateTime, 66 | Zuhr: e.Transit.DateTime, 67 | Asr: e.Others["asr"].DateTime, 68 | Maghrib: e.Sunset.DateTime, 69 | Isha: e.Others["isha"].DateTime, 70 | } 71 | 72 | // Check if schedule is normal 73 | dawn := e.Others["dawn"].DateTime 74 | dusk := e.Others["dusk"].DateTime 75 | hasNight := !e.Sunrise.IsZero() && !e.Sunset.IsZero() 76 | hasTwilight := !dawn.IsZero() && !dusk.IsZero() 77 | s.IsNormal = hasNight && hasTwilight 78 | 79 | // Save the schedule 80 | schedules[idx] = s 81 | if !s.IsNormal { 82 | nAbnormal++ 83 | } 84 | idx++ 85 | } 86 | 87 | return schedules, nAbnormal 88 | } 89 | 90 | func radToDeg(rad float64) float64 { 91 | return rad * 180 / math.Pi 92 | } 93 | 94 | func degToRad(deg float64) float64 { 95 | return deg * math.Pi / 180 96 | } 97 | 98 | func acot(cotValue float64) float64 { 99 | return math.Atan(1 / cotValue) 100 | } 101 | -------------------------------------------------------------------------------- /0-root_test.go: -------------------------------------------------------------------------------- 1 | package prayer_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/hablullah/go-prayer" 9 | "github.com/hablullah/go-prayer/internal/datatest" 10 | ) 11 | 12 | func TestCalculate(t *testing.T) { 13 | testCalculate(t, datatest.Tromso) // North Frigid 14 | testCalculate(t, datatest.London) // North Temperate 15 | testCalculate(t, datatest.Jakarta) // Torrid 16 | testCalculate(t, datatest.Wellington) // South Temperate 17 | } 18 | 19 | func testCalculate(t *testing.T, td datatest.TestData) { 20 | // Calculate schedules 21 | schedules, err := prayer.Calculate(prayer.Config{ 22 | Latitude: td.Latitude, 23 | Longitude: td.Longitude, 24 | Timezone: td.Timezone, 25 | TwilightConvention: prayer.AstronomicalTwilight(), 26 | AsrConvention: prayer.Shafii, 27 | HighLatitudeAdapter: prayer.NearestLatitude(), 28 | PreciseToSeconds: true, 29 | }, 2023) 30 | 31 | msg := fmt.Sprintf("schedule in %s has error: %v", td.Name, err) 32 | assertNil(t, err, msg) 33 | 34 | nExpected, nResult := len(td.Schedules), len(schedules) 35 | msg = fmt.Sprintf("%s schedule size: want %d got %d", td.Name, nExpected, nResult) 36 | assertEqual(t, nExpected, nResult, msg) 37 | 38 | for i := range schedules { 39 | result := schedules[i] 40 | expected := td.Schedules[i] 41 | assertSchedule(t, td, expected, result) 42 | } 43 | } 44 | 45 | func assertSchedule(t *testing.T, td datatest.TestData, e, r prayer.Schedule) { 46 | // Calculate diff 47 | diffFajr := e.Fajr.Sub(r.Fajr).Abs() 48 | diffSunrise := e.Sunrise.Sub(r.Sunrise).Abs() 49 | diffZuhr := e.Zuhr.Sub(r.Zuhr).Abs() 50 | diffAsr := e.Asr.Sub(r.Asr).Abs() 51 | diffMaghrib := e.Maghrib.Sub(r.Maghrib).Abs() 52 | diffIsha := e.Isha.Sub(r.Isha).Abs() 53 | 54 | // Prepare log message 55 | msgFormat := "%s, %s => want %q got %q (%v)" 56 | fajrMsg := fmt.Sprintf(msgFormat, td.Name, "Fajr", e.Fajr, r.Fajr, diffFajr) 57 | sunriseMsg := fmt.Sprintf(msgFormat, td.Name, "Sunrise", e.Sunrise, r.Sunrise, diffSunrise) 58 | zuhrMsg := fmt.Sprintf(msgFormat, td.Name, "Zuhr", e.Zuhr, r.Zuhr, diffZuhr) 59 | asrMsg := fmt.Sprintf(msgFormat, td.Name, "Asr", e.Asr, r.Asr, diffAsr) 60 | maghribMsg := fmt.Sprintf(msgFormat, td.Name, "Maghrib", e.Maghrib, r.Maghrib, diffMaghrib) 61 | ishaMsg := fmt.Sprintf(msgFormat, td.Name, "Isha", e.Isha, r.Isha, diffIsha) 62 | 63 | // Diff only allowed up to 5 seconds 64 | maxDiff := 5 * time.Second 65 | assertLTE(t, diffFajr, maxDiff, fajrMsg) 66 | assertLTE(t, diffSunrise, maxDiff, sunriseMsg) 67 | assertLTE(t, diffZuhr, maxDiff, zuhrMsg) 68 | assertLTE(t, diffAsr, maxDiff, asrMsg) 69 | assertLTE(t, diffMaghrib, maxDiff, maghribMsg) 70 | assertLTE(t, diffIsha, maxDiff, ishaMsg) 71 | } 72 | 73 | func assertNil(t *testing.T, v any, msg string) { 74 | if v != nil { 75 | t.Error(msg) 76 | } 77 | } 78 | 79 | func assertEqual[T comparable](t *testing.T, a T, b T, msg string) { 80 | if a != b { 81 | t.Error(msg) 82 | } 83 | } 84 | 85 | func assertLTE[T int | float64 | time.Duration](t *testing.T, a T, b T, msg string) { 86 | if a > b { 87 | t.Error(msg) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /scripts/test-gen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/format" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | // Clean up dst dir 14 | dstDir := "internal/datatest" 15 | os.RemoveAll(dstDir) 16 | os.MkdirAll(dstDir, os.ModePerm) 17 | 18 | // Generate common files 19 | err := genCommonFiles(dstDir) 20 | checkError(err) 21 | 22 | // Generate test data for each location 23 | for _, location := range testLocations { 24 | err = genTestData(location, dstDir) 25 | checkError(err) 26 | } 27 | } 28 | 29 | func genCommonFiles(dstDir string) error { 30 | // Write package header and imports 31 | var sb strings.Builder 32 | sb.WriteString("package datatest\n") 33 | sb.WriteString(`import ( 34 | "time" 35 | "regexp" 36 | "strconv" 37 | 38 | "github.com/hablullah/go-prayer" 39 | )` + "\n\n") 40 | 41 | sb.WriteString("var rxDT = regexp.MustCompile(`" + 42 | `(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})` + 43 | "`)\n\n") 44 | 45 | // Put struct for test data 46 | sb.WriteString(`type TestData struct { 47 | Name string 48 | Latitude float64 49 | Longitude float64 50 | Timezone *time.Location 51 | Schedules []prayer.Schedule 52 | }` + "\n\n") 53 | 54 | // Put helper function 55 | sb.WriteString(`func schedule(date string, fajr, sunrise, zuhr, asr, maghrib, isha string, tz *time.Location) prayer.Schedule { 56 | return prayer.Schedule { 57 | Date: date, 58 | Fajr: st(fajr, tz), 59 | Sunrise: st(sunrise, tz), 60 | Zuhr: st(zuhr, tz), 61 | Asr: st(asr, tz), 62 | Maghrib: st(maghrib, tz), 63 | Isha: st(isha, tz), 64 | } 65 | }` + "\n\n") 66 | 67 | sb.WriteString(` 68 | func st(s string, tz *time.Location) time.Time { 69 | parts := rxDT.FindStringSubmatch(s) 70 | if len(parts) != 7 { 71 | return time.Time{} 72 | } 73 | 74 | year, _ := strconv.Atoi(parts[1]) 75 | month, _ := strconv.Atoi(parts[2]) 76 | day, _ := strconv.Atoi(parts[3]) 77 | hour, _ := strconv.Atoi(parts[4]) 78 | minute, _ := strconv.Atoi(parts[5]) 79 | second, _ := strconv.Atoi(parts[6]) 80 | return time.Date(year, time.Month(month), day, hour, minute, second, 0, tz) 81 | }` + "\n\n") 82 | 83 | // Format code 84 | bt, err := format.Source([]byte(sb.String())) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | // Save to file 90 | dstPath := filepath.Join(dstDir, "common.go") 91 | return os.WriteFile(dstPath, bt, os.ModePerm) 92 | } 93 | 94 | func genTestData(loc Location, dstDir string) error { 95 | // Write package header and imports 96 | var sb strings.Builder 97 | sb.WriteString("package datatest\n") 98 | sb.WriteString(`import ( 99 | "time" 100 | 101 | "github.com/hablullah/go-prayer" 102 | )` + "\n") 103 | 104 | // Put the variable for timezone 105 | tzName := fmt.Sprintf("tz%s", loc.Name) 106 | sb.WriteString(fmt.Sprintf( 107 | "var %s, _ = time.LoadLocation(%q)\n\n", 108 | tzName, loc.Timezone)) 109 | 110 | // Put the variable for location 111 | sb.WriteString(fmt.Sprintf(""+ 112 | "var %s = TestData {\n"+ 113 | "Name: %q,\n"+ 114 | "Latitude: %f,\n"+ 115 | "Longitude: %f,\n"+ 116 | "Timezone: %s,\n", 117 | loc.Name, loc.Name, loc.Latitude, loc.Longitude, tzName)) 118 | 119 | // Calculate and put schedules 120 | sb.WriteString("Schedules: []prayer.Schedule{\n") 121 | for _, s := range getSchedules(loc) { 122 | sb.WriteString(fmt.Sprintf( 123 | "schedule(%q,%q,%q,%q,%q,%q,%q,%s),\n", 124 | s.Date, 125 | strTime(s.Fajr), 126 | strTime(s.Sunrise), 127 | strTime(s.Zuhr), 128 | strTime(s.Asr), 129 | strTime(s.Maghrib), 130 | strTime(s.Isha), 131 | tzName, 132 | )) 133 | } 134 | sb.WriteString("},\n") 135 | sb.WriteString("}\n") 136 | 137 | // Format code 138 | bt, err := format.Source([]byte(sb.String())) 139 | if err != nil { 140 | return err 141 | } 142 | 143 | // Save to file 144 | dstPath := filepath.Join(dstDir, strings.ToLower(loc.Name)+".go") 145 | return os.WriteFile(dstPath, bt, os.ModePerm) 146 | } 147 | 148 | func strTime(t time.Time) string { 149 | if t.IsZero() { 150 | return strings.Repeat(" ", 19) 151 | } else { 152 | return t.Format("2006-01-02 15:04:05") 153 | } 154 | } 155 | 156 | func checkError(err error) { 157 | if err != nil { 158 | panic(err) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /1-twilight.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import "time" 4 | 5 | // AstronomicalTwilight is moment when Sun is 18 degrees below horizon. At this point 6 | // most stars and other celestial objects still can be seen, however astronomers may 7 | // be unable to observe some of the fainter stars and galaxies, hence the name of this 8 | // twilight phase. This is the default twilight convention for this package. 9 | func AstronomicalTwilight() *TwilightConvention { 10 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 18} 11 | } 12 | 13 | // MWL is calculation method from Muslim World League with Fajr at 18° and Isha at 17°. 14 | // Usually used in Europe, Far East and parts of America. 15 | func MWL() *TwilightConvention { 16 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 17} 17 | } 18 | 19 | // ISNA is calculation method from Islamic Society of North America with both Fajr 20 | // and Isha at 15°. Used in North America i.e US and Canada. 21 | func ISNA() *TwilightConvention { 22 | return &TwilightConvention{FajrAngle: 15, IshaAngle: 15} 23 | } 24 | 25 | // UmmAlQura is calculation method from Umm al-Qura University in Makkah which used 26 | // in Saudi Arabia. Fajr at 18.5° and Isha fixed at 90 minutes after Maghrib. 27 | func UmmAlQura() *TwilightConvention { 28 | return &TwilightConvention{ 29 | FajrAngle: 18.5, 30 | IshaAngle: 18.5, 31 | MaghribDuration: 90 * time.Minute} 32 | } 33 | 34 | // Gulf is calculation method that often used by countries in Gulf region like UAE 35 | // and Kuwait. Fajr at 19.5° and Isha fixed at 90 minutes after Maghrib. 36 | func Gulf() *TwilightConvention { 37 | return &TwilightConvention{ 38 | FajrAngle: 19.5, 39 | IshaAngle: 19.5, 40 | MaghribDuration: 90 * time.Minute} 41 | } 42 | 43 | // Algerian is calculation method from Algerian Ministry of Religious Affairs and 44 | // Wakfs. Fajr at 18° and Isha at 17°. 45 | func Algerian() *TwilightConvention { 46 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 17} 47 | } 48 | 49 | // Karachi is calculation method from University of Islamic Sciences, Karachi, with 50 | // both Fajr and Isha at 18°. Used in Pakistan, Afganistan, Bangladesh and India. 51 | func Karachi() *TwilightConvention { 52 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 18} 53 | } 54 | 55 | // Diyanet is calculation method from Turkey's Diyanet İşleri Başkanlığı. 56 | // It has the same value as MWL with Fajr at 18° and Isha at 17°. 57 | func Diyanet() *TwilightConvention { 58 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 17} 59 | } 60 | 61 | // Egypt is calculation method from Egyptian General Authority of Survey with Fajr 62 | // at 19.5° and Isha at 17.5°. Used in Africa, Syria and Lebanon. 63 | func Egypt() *TwilightConvention { 64 | return &TwilightConvention{FajrAngle: 19.5, IshaAngle: 17.5} 65 | } 66 | 67 | // EgyptBis is another version of calculation method from Egyptian General Authority 68 | // of Survey. Fajr at 20° and Isha at 18°. 69 | func EgyptBis() *TwilightConvention { 70 | return &TwilightConvention{FajrAngle: 20, IshaAngle: 18} 71 | } 72 | 73 | // Kemenag is calculation method from Kementerian Agama Republik Indonesia. Fajr at 74 | // 20° and Isha at 18°. 75 | func Kemenag() *TwilightConvention { 76 | return &TwilightConvention{FajrAngle: 20, IshaAngle: 18} 77 | } 78 | 79 | // MUIS is calculation method from Majlis Ugama Islam Singapura. Fajr at 20° and 80 | // Isha at 18°. 81 | func MUIS() *TwilightConvention { 82 | return &TwilightConvention{FajrAngle: 20, IshaAngle: 18} 83 | } 84 | 85 | // JAKIM is calculation method from Jabatan Kemajuan Islam Malaysia. Fajr at 20° and 86 | // Isha at 18°. 87 | func JAKIM() *TwilightConvention { 88 | return &TwilightConvention{FajrAngle: 20, IshaAngle: 18} 89 | } 90 | 91 | // UOIF is calculation method from Union Des Organisations Islamiques De France. 92 | // Fajr and Isha both at 12°. 93 | func UOIF() *TwilightConvention { 94 | return &TwilightConvention{FajrAngle: 12, IshaAngle: 12} 95 | } 96 | 97 | // France15 is calculation method for France region with Fajr and Isha both at 15°. 98 | func France15() *TwilightConvention { 99 | return &TwilightConvention{FajrAngle: 15, IshaAngle: 15} 100 | } 101 | 102 | // France18 is calculation method for France region with Fajr and Isha both at 18°. 103 | func France18() *TwilightConvention { 104 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 18} 105 | } 106 | 107 | // Tunisia is calculation method from Tunisian Ministry of Religious Affairs. 108 | // Fajr and Isha both at 18°. 109 | func Tunisia() *TwilightConvention { 110 | return &TwilightConvention{FajrAngle: 18, IshaAngle: 18} 111 | } 112 | 113 | // Tehran is calculation method from Institute of Geophysics at University of Tehran. 114 | // Fajr at 17.7° and Isha at 14°. 115 | func Tehran() *TwilightConvention { 116 | return &TwilightConvention{FajrAngle: 17.7, IshaAngle: 14} 117 | } 118 | 119 | // Jafari is calculation method from Shia Ithna Ashari that used in some Shia 120 | // communities worldwide. Fajr at 16° and Isha at 14°. 121 | func Jafari() *TwilightConvention { 122 | return &TwilightConvention{FajrAngle: 16, IshaAngle: 14} 123 | } 124 | -------------------------------------------------------------------------------- /0-root.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Schedule is the time of each prayer (and related events) on a day. 8 | type Schedule struct { 9 | // Date is the ISO date, useful for logging. 10 | Date string 11 | 12 | // Fajr is the time when the sky begins to lighten (dawn) after previously 13 | // completely dark. 14 | Fajr time.Time 15 | 16 | // Sunrise is the moment when the upper limb of the Sun appears on the horizon 17 | // in the morning. 18 | Sunrise time.Time 19 | 20 | // Zuhr is the time when the Sun begins to decline after reaching the highest 21 | // point in the sky, so a bit after solar noon. 22 | Zuhr time.Time 23 | 24 | // Asr is the time when the length of any object's shadow reaches a factor of 25 | // the length of the object itself plus the length of that object's shadow at 26 | // noon. 27 | Asr time.Time 28 | 29 | // Maghrib is sunset, i.e. the time when the upper limb of the Sun disappears 30 | // below the horizon. 31 | Maghrib time.Time 32 | 33 | // Isha is the time when darkness falls and after this point the sky is no longer 34 | // illuminated (dusk). 35 | Isha time.Time 36 | 37 | // IsNormal specify whether the day have a normal day night period or not. It 38 | // will be false in area with higher latitude, when Sun never rise or set in 39 | // extreme periods. 40 | IsNormal bool 41 | } 42 | 43 | // ScheduleCorrections is correction for each prayer time. 44 | type ScheduleCorrections struct { 45 | Fajr time.Duration 46 | Sunrise time.Duration 47 | Zuhr time.Duration 48 | Asr time.Duration 49 | Maghrib time.Duration 50 | Isha time.Duration 51 | } 52 | 53 | // TwilightConvention is the convention that specifies time for Fajr (dawn) and Isha 54 | // (dusk). Most of the conventions use Solar angle elevation for both dawn and dusk 55 | // time, however there are several convention where dusk times depends on sunset 56 | // (Maghrib) times. 57 | type TwilightConvention struct { 58 | FajrAngle float64 59 | IshaAngle float64 60 | MaghribDuration time.Duration 61 | } 62 | 63 | // HighLatitudeAdapter is function for calculating prayer times in area with latitude 64 | // >45 degrees. Check out https://www.prayertimes.dk/story.html for why this is needed. 65 | type HighLatitudeAdapter func(cfg Config, year int, currentSchedules []Schedule) []Schedule 66 | 67 | // Config is configuration that used to calculate the prayer times. 68 | type Config struct { 69 | // Latitude is the latitude of the location. Positive for north area and negative 70 | // for south area. 71 | Latitude float64 72 | 73 | // Longitude is the longitude of the location. Positive for east area and negative 74 | // for west area. 75 | Longitude float64 76 | 77 | // Elevation is the elevation of the location above sea level. It's used to 78 | // improve calculation for sunrise and sunset by factoring the value of 79 | // atmospheric refraction. However, apparently most of the prayer time 80 | // calculator doesn't use it so it's fine to omit it. 81 | Elevation float64 82 | 83 | // Timezone is the time zone of the location specified above. If not specified, 84 | // it will use UTC. 85 | Timezone *time.Location 86 | 87 | // TwilightConvention is the convention that used to specify time for Fajr and 88 | // Isha. By default it will use `AstronomicalTwilight`. 89 | TwilightConvention *TwilightConvention 90 | 91 | // AsrConvention is the convention that used for calculating Asr time. There are 92 | // two conventions, Shafii and Hanafi. By default it will use Shafii. 93 | AsrConvention AsrConvention 94 | 95 | // HighLatitudeAdapter is the function for adjusting prayer times in area with 96 | // high latitude (>=45 degrees). If not specified, it will not calculate the 97 | // adjustment for higher latitude and instead will return the schedule as it is. 98 | // For area in high or extreme latitude, it might return zero for Fajr, Sunrise, 99 | // Maghrib and Isha. 100 | HighLatitudeAdapter HighLatitudeAdapter 101 | 102 | // Corrections is used to corrects calculated time for each specified prayer. 103 | Corrections ScheduleCorrections 104 | 105 | // PreciseToSeconds specify whether output time will omit the seconds or not. 106 | PreciseToSeconds bool 107 | } 108 | 109 | // Calculate calculates the prayer time for the entire year with specified configuration. 110 | func Calculate(cfg Config, year int) ([]Schedule, error) { 111 | // Apply default config 112 | if cfg.Timezone == nil { 113 | cfg.Timezone = time.UTC 114 | } 115 | 116 | if cfg.TwilightConvention == nil { 117 | cfg.TwilightConvention = AstronomicalTwilight() 118 | } 119 | 120 | // Calculate the schedules 121 | schedules, nAbnormal := calcNormal(cfg, year) 122 | 123 | // Apply high latitude adapter 124 | if nAbnormal > 0 && cfg.HighLatitudeAdapter != nil { 125 | schedules = cfg.HighLatitudeAdapter(cfg, year, schedules) 126 | } 127 | 128 | // Final check 129 | fixedMaghribDuration := cfg.TwilightConvention.MaghribDuration 130 | for i, s := range schedules { 131 | // Apply Isha times for convention where Isha time is fixed after Maghrib 132 | if fixedMaghribDuration > 0 { 133 | s.Isha = s.Maghrib.Add(fixedMaghribDuration) 134 | } 135 | 136 | // Apply time correction 137 | s.Fajr = applyCorrection(s.Fajr, cfg.Corrections.Fajr) 138 | s.Sunrise = applyCorrection(s.Sunrise, cfg.Corrections.Sunrise) 139 | s.Zuhr = applyCorrection(s.Zuhr, cfg.Corrections.Zuhr) 140 | s.Asr = applyCorrection(s.Asr, cfg.Corrections.Asr) 141 | s.Maghrib = applyCorrection(s.Maghrib, cfg.Corrections.Maghrib) 142 | s.Isha = applyCorrection(s.Isha, cfg.Corrections.Isha) 143 | 144 | // If needed round the time to minute 145 | if !cfg.PreciseToSeconds { 146 | s.Fajr = s.Fajr.Round(time.Minute) 147 | s.Sunrise = s.Sunrise.Round(time.Minute) 148 | s.Zuhr = s.Zuhr.Round(time.Minute) 149 | s.Asr = s.Asr.Round(time.Minute) 150 | s.Maghrib = s.Maghrib.Round(time.Minute) 151 | s.Isha = s.Isha.Round(time.Minute) 152 | } 153 | 154 | schedules[i] = s 155 | } 156 | 157 | return schedules, nil 158 | } 159 | 160 | func applyCorrection(t time.Time, d time.Duration) time.Time { 161 | if !t.IsZero() { 162 | t = t.Add(d) 163 | } 164 | return t 165 | } 166 | -------------------------------------------------------------------------------- /5-high-lat-local-relative.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // LocalRelativeEstimation is adapter using method that created by cooperation between 8 | // Fiqh Council of Muslim World League and Islamic Crescents' Observation Project (ICOP). 9 | // In short, this method uses average percentage to calculate Fajr and Isha time for 10 | // abnormal times. 11 | // 12 | // This adapter only estimates time for Isha and Fajr and require sunrise and sunset 13 | // time. Therefore it's not suitable for area in extreme latitude (>=65 degrees). 14 | // 15 | // Reference: https://www.astronomycenter.net/latitude.html?l=en 16 | func LocalRelativeEstimation() HighLatitudeAdapter { 17 | return highLatLocalRelativeEstimation 18 | } 19 | 20 | func highLatLocalRelativeEstimation(cfg Config, year int, schedules []Schedule) []Schedule { 21 | var ( 22 | nFajrSample int 23 | nIshaSample int 24 | sumFajrPercents float64 25 | sumIshaPercents float64 26 | ) 27 | 28 | for _, s := range schedules { 29 | // This conventions only works if daytime exists (in other words, sunrise 30 | // and Maghrib must exist). So if there are days where those time don't 31 | // exist, stop and just return the schedule as it is. 32 | // TODO: maybe put some warning log later. 33 | if s.Sunrise.IsZero() || s.Maghrib.IsZero() { 34 | return schedules 35 | } 36 | 37 | // Calculate percentage in normal days 38 | if s.IsNormal { 39 | // Calculate day and night 40 | dayDuration := s.Maghrib.Sub(s.Sunrise).Seconds() 41 | nightDuration := 24*60*60 - dayDuration 42 | 43 | // Calculate Fajr percentage 44 | if !s.Fajr.IsZero() { 45 | fajrDuration := s.Sunrise.Sub(s.Fajr).Seconds() 46 | sumFajrPercents += fajrDuration / nightDuration 47 | nFajrSample++ 48 | } 49 | 50 | // Calculate Isha percentage 51 | if !s.Isha.IsZero() { 52 | ishaDuration := s.Isha.Sub(s.Maghrib).Seconds() 53 | sumIshaPercents += ishaDuration / nightDuration 54 | nIshaSample++ 55 | } 56 | } 57 | } 58 | 59 | // Calculate average percentage 60 | avgFajrPercents := sumFajrPercents / float64(nFajrSample) 61 | avgIshaPercents := sumIshaPercents / float64(nIshaSample) 62 | 63 | // Extract abnormal schedules 64 | abnormalSummer, abnormalWinter := extractAbnormalSchedules(schedules) 65 | 66 | // Fix Fajr and Isha times in abnormal days 67 | for _, as := range []abnormalRange{abnormalSummer, abnormalWinter} { 68 | for _, i := range as.Indexes { 69 | s := schedules[i] 70 | dayDuration := s.Maghrib.Sub(s.Sunrise).Seconds() 71 | nightDuration := 24*60*60 - dayDuration 72 | 73 | if !s.IsNormal { 74 | fajrDuration := nightDuration * avgFajrPercents * float64(time.Second) 75 | schedules[i].Fajr = s.Sunrise.Add(-time.Duration(fajrDuration)) 76 | 77 | ishaDuration := nightDuration * avgIshaPercents * float64(time.Second) 78 | schedules[i].Isha = s.Maghrib.Add(time.Duration(ishaDuration)) 79 | } 80 | } 81 | } 82 | 83 | schedules = applyLocalRelativeTransition(schedules, abnormalSummer) 84 | schedules = applyLocalRelativeTransition(schedules, abnormalWinter) 85 | return schedules 86 | } 87 | 88 | func applyLocalRelativeTransition(schedules []Schedule, abnormalPeriod abnormalRange) []Schedule { 89 | // If there are no abnormality, return as it is 90 | if abnormalPeriod.IsEmpty() { 91 | return schedules 92 | } 93 | 94 | // Split the abnormal period into two 95 | nAbnormalDays := len(abnormalPeriod.Indexes) 96 | maxTransitionDays := nAbnormalDays / 2 97 | firstHalf := abnormalPeriod.Indexes[:maxTransitionDays] 98 | secondHalf := abnormalPeriod.Indexes[nAbnormalDays-maxTransitionDays:] 99 | 100 | // Fix the time in first half 101 | for _, idx := range firstHalf { 102 | today := sliceAt(schedules, idx) 103 | yesterday := sliceAt(schedules, idx-1) 104 | 105 | // If idx is zero, it means today is the first day of the year. 106 | // Therefore, yesterday is occured last year. 107 | if idx == 0 { 108 | yesterday.Fajr = yesterday.Fajr.AddDate(-1, 0, 0) 109 | yesterday.Isha = yesterday.Isha.AddDate(-1, 0, 0) 110 | } 111 | 112 | var fajrChanged, ishaChanged bool 113 | schedules[idx].Fajr, fajrChanged = applyLocalRelativeTransitionTime(yesterday.Fajr, today.Fajr) 114 | schedules[idx].Isha, ishaChanged = applyLocalRelativeTransitionTime(yesterday.Isha, today.Isha) 115 | if !fajrChanged && !ishaChanged { 116 | break 117 | } 118 | } 119 | 120 | // Fix the time in second half, do it backward 121 | for i := len(secondHalf) - 1; i >= 0; i-- { 122 | idx := secondHalf[i] 123 | today := sliceAt(schedules, idx) 124 | tomorrow := sliceAt(schedules, idx+1) 125 | 126 | // If idx is last, it means today is the last day of the year. 127 | // Therefore, tomorrow will occur next year. 128 | if idx == len(schedules)-1 { 129 | tomorrow.Fajr = tomorrow.Fajr.AddDate(1, 0, 0) 130 | tomorrow.Isha = tomorrow.Isha.AddDate(1, 0, 0) 131 | } 132 | 133 | var fajrChanged, ishaChanged bool 134 | schedules[idx].Fajr, fajrChanged = applyLocalRelativeTransitionTime(tomorrow.Fajr, today.Fajr) 135 | schedules[idx].Isha, ishaChanged = applyLocalRelativeTransitionTime(tomorrow.Isha, today.Isha) 136 | if !fajrChanged && !ishaChanged { 137 | break 138 | } 139 | } 140 | 141 | return schedules 142 | } 143 | 144 | func applyLocalRelativeTransitionTime(reference, today time.Time) (time.Time, bool) { 145 | // Calculate diff between today and reference 146 | var diff time.Duration 147 | var referenceIsForward bool 148 | if today.After(reference) { 149 | diff = today.Sub(reference) 150 | referenceIsForward = false 151 | } else { 152 | diff = reference.Sub(today) 153 | referenceIsForward = true 154 | } 155 | 156 | // Limit the difference 157 | maxDiff := 24*time.Hour + 5*time.Minute 158 | minDiff := 24*time.Hour - 5*time.Minute 159 | 160 | if diff > maxDiff { 161 | diff = maxDiff 162 | } else if diff < minDiff { 163 | diff = minDiff 164 | } else { 165 | return today, false // the diff is within limit, nothing to change 166 | } 167 | 168 | // Adjust the time 169 | var newTime time.Time 170 | if referenceIsForward { 171 | newTime = reference.Add(-diff) 172 | } else { 173 | newTime = reference.Add(diff) 174 | } 175 | 176 | // Fix the year 177 | if todayYear := today.Year(); newTime.Year() != todayYear { 178 | newTime = time.Date(todayYear, newTime.Month(), newTime.Day(), 179 | newTime.Hour(), newTime.Minute(), newTime.Second(), newTime.Nanosecond(), 180 | newTime.Location()) 181 | } 182 | 183 | return newTime, true 184 | } 185 | -------------------------------------------------------------------------------- /5-high-lat-mecca.go: -------------------------------------------------------------------------------- 1 | package prayer 2 | 3 | import ( 4 | "math" 5 | "time" 6 | ) 7 | 8 | // Mecca is adapter based on Fatwa from Dar Al Iftah Al Misrriyah number 2806 dated 9 | // at 2010-08-08. They propose that area with higher latitude to follows the schedule 10 | // in Mecca when abnormal days occured, using transit time as the common point. Here 11 | // the day is considered "abnormal" when there are no true night, or the day length is 12 | // less than 4 hours. 13 | // 14 | // To prevent sudden schedule changes, this method uses transition period for maximum 15 | // one month before and after the abnormal periods. 16 | // 17 | // This adapter doesn't require the sunrise and sunset to be exist in a day, so it's 18 | // usable for area in extreme latitudes (>=65 degrees). 19 | // 20 | // Reference: https://www.prayertimes.dk/fatawa.html 21 | func Mecca() HighLatitudeAdapter { 22 | return highLatMecca 23 | } 24 | 25 | func highLatMecca(cfg Config, year int, schedules []Schedule) []Schedule { 26 | // Additional rule: day is normal if daylength is more than 4 hour 27 | for i, s := range schedules { 28 | if s.IsNormal { 29 | var dayLength time.Duration 30 | if !s.Maghrib.IsZero() && !s.Sunrise.IsZero() { 31 | dayLength = s.Maghrib.Sub(s.Sunrise) 32 | } 33 | schedules[i].IsNormal = dayLength >= 4*time.Hour 34 | } 35 | } 36 | 37 | // Extract abnormal schedules 38 | abnormalSummer, abnormalWinter := extractAbnormalSchedules(schedules) 39 | 40 | // Calculate schedule for Mecca 41 | meccaTz, _ := time.LoadLocation("Asia/Riyadh") 42 | meccaCfg := Config{ 43 | Latitude: 21.425506007708996, 44 | Longitude: 39.8254579358597, 45 | Timezone: meccaTz, 46 | TwilightConvention: cfg.TwilightConvention, 47 | AsrConvention: cfg.AsrConvention} 48 | meccaSchedules, _ := calcNormal(meccaCfg, year) 49 | 50 | // Apply Mecca schedules in abnormal period by matching it with duration 51 | // in Mecca using transit time (noon) as the base. 52 | for _, as := range []abnormalRange{abnormalSummer, abnormalWinter} { 53 | for _, i := range as.Indexes { 54 | // Calculate duration from Mecca schedule 55 | ms := meccaSchedules[i] 56 | msFajrTransit := ms.Zuhr.Sub(ms.Fajr) 57 | msRiseTransit := ms.Zuhr.Sub(ms.Sunrise) 58 | msTransitAsr := ms.Asr.Sub(ms.Zuhr) 59 | msTransitMaghrib := ms.Maghrib.Sub(ms.Zuhr) 60 | msTransitIsha := ms.Isha.Sub(ms.Zuhr) 61 | 62 | // Apply Mecca duration 63 | s := schedules[i] 64 | s.Fajr = s.Zuhr.Add(-msFajrTransit) 65 | s.Sunrise = s.Zuhr.Add(-msRiseTransit) 66 | s.Asr = s.Zuhr.Add(msTransitAsr) 67 | s.Maghrib = s.Zuhr.Add(msTransitMaghrib) 68 | s.Isha = s.Zuhr.Add(msTransitIsha) 69 | schedules[i] = s 70 | } 71 | } 72 | 73 | schedules = applyMeccaTransition(schedules, abnormalSummer, abnormalWinter) 74 | return schedules 75 | } 76 | 77 | func applyMeccaTransition(schedules []Schedule, abnormalSummer, abnormalWinter abnormalRange) []Schedule { 78 | // If there are no abnormality, return as it is 79 | if abnormalSummer.IsEmpty() && abnormalWinter.IsEmpty() { 80 | return schedules 81 | } 82 | 83 | // Split schedules for each time 84 | nSchedules := len(schedules) 85 | fajrTimes := make([]time.Time, nSchedules) 86 | sunriseTimes := make([]time.Time, nSchedules) 87 | asrTimes := make([]time.Time, nSchedules) 88 | maghribTimes := make([]time.Time, nSchedules) 89 | ishaTimes := make([]time.Time, nSchedules) 90 | 91 | for idx, s := range schedules { 92 | fajrTimes[idx] = s.Fajr 93 | sunriseTimes[idx] = s.Sunrise 94 | asrTimes[idx] = s.Asr 95 | maghribTimes[idx] = s.Maghrib 96 | ishaTimes[idx] = s.Isha 97 | } 98 | 99 | // Check if there is only one abnormal period 100 | onlySummer := abnormalWinter.IsEmpty() && !abnormalSummer.IsEmpty() 101 | onlyWinter := abnormalSummer.IsEmpty() && !abnormalWinter.IsEmpty() 102 | if onlySummer || onlyWinter { 103 | // Merge into one abnormal period 104 | abnormalPeriod := abnormalSummer 105 | if abnormalPeriod.IsEmpty() { 106 | abnormalPeriod = abnormalWinter 107 | } 108 | 109 | // Calculate transition duration from leftover days 110 | leftoverDays := len(schedules) - len(abnormalPeriod.Indexes) 111 | nTransitionDays := leftoverDays / 2 112 | 113 | // Apply transition times 114 | fajrTimes = createMeccaPreTransition(fajrTimes, abnormalPeriod, nTransitionDays) 115 | fajrTimes = createMeccaPostTransition(fajrTimes, abnormalPeriod, nTransitionDays) 116 | sunriseTimes = createMeccaPreTransition(sunriseTimes, abnormalPeriod, nTransitionDays) 117 | sunriseTimes = createMeccaPostTransition(sunriseTimes, abnormalPeriod, nTransitionDays) 118 | asrTimes = createMeccaPreTransition(asrTimes, abnormalPeriod, nTransitionDays) 119 | asrTimes = createMeccaPostTransition(asrTimes, abnormalPeriod, nTransitionDays) 120 | maghribTimes = createMeccaPreTransition(maghribTimes, abnormalPeriod, nTransitionDays) 121 | maghribTimes = createMeccaPostTransition(maghribTimes, abnormalPeriod, nTransitionDays) 122 | ishaTimes = createMeccaPreTransition(ishaTimes, abnormalPeriod, nTransitionDays) 123 | ishaTimes = createMeccaPostTransition(ishaTimes, abnormalPeriod, nTransitionDays) 124 | } else if !abnormalSummer.IsEmpty() && !abnormalWinter.IsEmpty() { 125 | // Fetch indexes 126 | summerIdxStart, _ := firstSliceItem(abnormalSummer.Indexes) 127 | summerIdxEnd, _ := lastSliceItem(abnormalSummer.Indexes) 128 | winterIdxStart, _ := firstSliceItem(abnormalWinter.Indexes) 129 | winterIdxEnd, _ := lastSliceItem(abnormalWinter.Indexes) 130 | 131 | // Calculate gap between period 132 | winterSummerGap := int(math.Abs(float64(summerIdxStart-winterIdxEnd))) - 1 // after winter end, before summer start 133 | summerWinterGap := int(math.Abs(float64(winterIdxStart-summerIdxEnd))) - 1 // after summer end, before winter start 134 | 135 | // Calculate transition duration 136 | winterSummerTransitionDays := winterSummerGap / 2 // for post-winter and pre-summer 137 | summerWinterTransitionDays := summerWinterGap / 2 // for pre-winter and post-summer 138 | 139 | preWinterTransitionDays := summerWinterTransitionDays 140 | postWinterTransitionDays := winterSummerTransitionDays 141 | preSummerTransitionDays := winterSummerTransitionDays 142 | postSummerTransitionDays := summerWinterTransitionDays 143 | 144 | // Create winter transition 145 | fajrTimes = createMeccaPreTransition(fajrTimes, abnormalWinter, preWinterTransitionDays) 146 | fajrTimes = createMeccaPostTransition(fajrTimes, abnormalWinter, postWinterTransitionDays) 147 | sunriseTimes = createMeccaPreTransition(sunriseTimes, abnormalWinter, preWinterTransitionDays) 148 | sunriseTimes = createMeccaPostTransition(sunriseTimes, abnormalWinter, postWinterTransitionDays) 149 | asrTimes = createMeccaPreTransition(asrTimes, abnormalWinter, preWinterTransitionDays) 150 | asrTimes = createMeccaPostTransition(asrTimes, abnormalWinter, postWinterTransitionDays) 151 | maghribTimes = createMeccaPreTransition(maghribTimes, abnormalWinter, preWinterTransitionDays) 152 | maghribTimes = createMeccaPostTransition(maghribTimes, abnormalWinter, postWinterTransitionDays) 153 | ishaTimes = createMeccaPreTransition(ishaTimes, abnormalWinter, preWinterTransitionDays) 154 | ishaTimes = createMeccaPostTransition(ishaTimes, abnormalWinter, postWinterTransitionDays) 155 | 156 | // Create summer transition 157 | fajrTimes = createMeccaPreTransition(fajrTimes, abnormalSummer, preSummerTransitionDays) 158 | fajrTimes = createMeccaPostTransition(fajrTimes, abnormalSummer, postSummerTransitionDays) 159 | sunriseTimes = createMeccaPreTransition(sunriseTimes, abnormalSummer, preSummerTransitionDays) 160 | sunriseTimes = createMeccaPostTransition(sunriseTimes, abnormalSummer, postSummerTransitionDays) 161 | asrTimes = createMeccaPreTransition(asrTimes, abnormalSummer, preSummerTransitionDays) 162 | asrTimes = createMeccaPostTransition(asrTimes, abnormalSummer, postSummerTransitionDays) 163 | maghribTimes = createMeccaPreTransition(maghribTimes, abnormalSummer, preSummerTransitionDays) 164 | maghribTimes = createMeccaPostTransition(maghribTimes, abnormalSummer, postSummerTransitionDays) 165 | ishaTimes = createMeccaPreTransition(ishaTimes, abnormalSummer, preSummerTransitionDays) 166 | ishaTimes = createMeccaPostTransition(ishaTimes, abnormalSummer, postSummerTransitionDays) 167 | } 168 | 169 | // Put back times to schedule 170 | for idx, s := range schedules { 171 | s.Fajr = fajrTimes[idx] 172 | s.Sunrise = sunriseTimes[idx] 173 | s.Asr = asrTimes[idx] 174 | s.Maghrib = maghribTimes[idx] 175 | s.Isha = ishaTimes[idx] 176 | schedules[idx] = s 177 | } 178 | 179 | return schedules 180 | } 181 | 182 | func createMeccaPreTransition(times []time.Time, abnormalPeriod abnormalRange, nTransitionDays int) []time.Time { 183 | // Fix transition days 184 | if nTransitionDays > 30 { 185 | nTransitionDays = 30 186 | } 187 | 188 | // Get data where transition end, i.e. when abnormality start 189 | endIdx, _ := firstSliceItem(abnormalPeriod.Indexes) 190 | endTime := times[endIdx] 191 | 192 | // Get data where transition begin 193 | startIdx := sliceRealIdx(times, endIdx-nTransitionDays) 194 | startTime := times[startIdx] 195 | if startTime.After(endTime) { 196 | startTime = startTime.AddDate(-1, 0, 0) 197 | } 198 | 199 | // Calculate duration step 200 | durationDiff := endTime.Sub(startTime) 201 | diffStep := durationDiff / time.Duration(nTransitionDays) 202 | 203 | // Apply transition time 204 | ci, ct := endIdx, endTime 205 | for i := nTransitionDays - 1; i > 0; i-- { // minus 1 to exclude `startIdx` 206 | ci = sliceRealIdx(times, ci-1) 207 | ct = ct.Add(-diffStep) 208 | times[ci] = ct 209 | } 210 | 211 | return times 212 | } 213 | 214 | func createMeccaPostTransition(times []time.Time, abnormalPeriod abnormalRange, nTransitionDays int) []time.Time { 215 | // Fix transition days 216 | if nTransitionDays > 30 { 217 | nTransitionDays = 30 218 | } 219 | 220 | // Get data where transition start, i.e. when abnormality end 221 | startIdx, _ := lastSliceItem(abnormalPeriod.Indexes) 222 | startTime := times[startIdx] 223 | 224 | // Get data where transition end 225 | endIdx := sliceRealIdx(times, startIdx+nTransitionDays) 226 | endTime := times[endIdx] 227 | if endTime.Before(startTime) { 228 | endTime = endTime.AddDate(1, 0, 0) 229 | } 230 | 231 | // Calculate duration step 232 | durationDiff := endTime.Sub(startTime) 233 | diffStep := durationDiff / time.Duration(nTransitionDays) 234 | 235 | // Apply transition time 236 | ci, ct := startIdx, startTime 237 | for i := 1; i < nTransitionDays; i++ { 238 | ci = sliceRealIdx(times, ci+1) 239 | ct = ct.Add(diffStep) 240 | times[ci] = ct 241 | } 242 | 243 | return times 244 | } 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Prayer [![Go Reference][doc-pkg-badge]][doc-pkg-url] [![Classic Go Reference][doc-godocs-badge]][doc-godocs-url] 2 | 3 | Go Prayer is a Go package for calculating prayer/salah times for an entire year in the specified location. It uses [SPA][spa] algorithm from [`go-sampa`][go-sampa] package to calculate the Sun events which used to determine the prayer times. 4 | 5 | ## Table of Contents 6 | 7 | - [Table of Contents](#table-of-contents) 8 | - [Installation](#installation) 9 | - [Features](#features) 10 | - [API](#api) 11 | - [Calculation Result](#calculation-result) 12 | - [Fajr and Isha Conventions](#fajr-and-isha-conventions) 13 | - [Asr Conventions](#asr-conventions) 14 | - [Higher Latitude Conventions](#higher-latitude-conventions) 15 | - [FAQ](#faq) 16 | - [License](#license) 17 | 18 | ## Installation 19 | 20 | To use this package, make sure your project use Go 1.20 or above, then run the following command via terminal: 21 | 22 | ``` 23 | go get -u -v github.com/hablullah/go-prayer 24 | ``` 25 | 26 | ## Features 27 | 28 | - Seamlessly handle DST times. 29 | - Should be mathematically accurate thanks to `go-sampa` package. 30 | - Provides several twilight conventions for calculating Fajr and Isha time. 31 | - Provides several adapter to calculate prayer times in area with higher latitude (>45°) where Sun may not rise or set for the entire day. 32 | 33 | ## API 34 | 35 | You can check the Go documentations to see the available APIs. However, the main interest in this package is `Calculate` function, which calculate the prayer schedule for entire year. 36 | 37 | For [example](example/main.go), here we want to get prayer times in Jakarta for 2023: 38 | 39 | ```go 40 | package main 41 | 42 | import ( 43 | "time" 44 | 45 | "github.com/hablullah/go-prayer" 46 | ) 47 | 48 | func main() { 49 | // Calculate prayer schedule in Jakarta for 2023. 50 | asiaJakarta, _ := time.LoadLocation("Asia/Jakarta") 51 | jakartaSchedules, _ := prayer.Calculate(prayer.Config{ 52 | Latitude: -6.14, 53 | Longitude: 106.81, 54 | Timezone: asiaJakarta, 55 | TwilightConvention: prayer.Kemenag(), 56 | AsrConvention: prayer.Shafii, 57 | PreciseToSeconds: true, 58 | }, 2023) 59 | 60 | // Calculate prayer schedule in London for 2023. 61 | // Since London in higher latitude, make sure to enable the adapter. 62 | europeLondon, _ := time.LoadLocation("Europe/London") 63 | londonSchedules, _ := prayer.Calculate(prayer.Config{ 64 | Latitude: 51.507222, 65 | Longitude: -0.1275, 66 | Timezone: europeLondon, 67 | TwilightConvention: prayer.ISNA(), 68 | AsrConvention: prayer.Shafii, 69 | HighLatitudeAdapter: prayer.NearestLatitude(), 70 | PreciseToSeconds: true, 71 | }, 2023) 72 | } 73 | ``` 74 | 75 | You can also adjust the calculation result by specifying it in `Corrections` field in `Configuration`. 76 | 77 | ## Calculation Result 78 | 79 | There are five times that will be calculated by this package: 80 | 81 | 1. **Fajr** is the time when the sky begins to lighten (dawn) after previously completely dark. The exact time is different between several conventions, however all of them agree that it occured within astronomical twilight when the Sun is between 12 degrees and 18 degrees below the horizon. 82 | 83 | 2. **Sunrise** is the moment when the upper limb of the Sun appears on the horizon in the morning. In theory, the sunrise time is affected by the elevation of a location. However, the change is quite neglible, only around 1 minute for every 1.5 km. Because of this, most calculators will ignore the elevation and treat the earth as a simple spherical ball. 84 | 85 | 3. **Zuhr** is the time when the Sun begins to decline after reaching the highest point in the sky, so a bit after solar noon. However, there are some difference opinions on when azan for Zuhr should be commenced. 86 | 87 | There is a hadith that forbade Muslim to pray exactly at the solar noon, and instead we should wait until the Sun has descended a bit to the west. From this, there are two different opinion on when azan should be announced. First, the azan should be announced after the Sun has descended a bit (noon + 1-2 minute). Second, the azan is announced right on solar noon since the prayer will be done later anyway (after iqamah). 88 | 89 | This package by default will use the second opinion. However, you can adjust the time by specifying it in `Corrections` field in `Configuration`. 90 | 91 | 4. **Asr** is the time when the length of any object's shadow reaches a factor of the length of the object itself plus the length of that object's shadow at noon. With that said, Asr time is calculated by measuring the length of shadow of an object, relative to the height of the object itself. 92 | 93 | 5. **Maghrib** is the time when the upper limb of the Sun disappears below the horizon, so Maghrib is equal with sunset time. Like sunrise, the time for Maghrib might be affected by the elevation of a location. However, since the change is neglible most calculators will ignore the elevation and treat the earth as a simple spherical ball. 94 | 95 | 6. **Isha** is the time at which darkness falls and after this point the sky is no longer illuminated. The exact time is different between several conventions. Most of them agree that it occured within astronomical twilight when the Sun is between 12 degrees and 18 degrees below the horizon. However there are also some conventions where the Isha time is started after fixed Maghrib duration. 96 | 97 | ## Fajr and Isha Conventions 98 | 99 | Since there are so many Muslim from different cultures and locations, there are several conventions for calculating prayer times. For Fajr and Isha, all conventions agree that they occured within astronomical twilight, however there are differences in the value of Sun altitude. Special case for Isha, there are some conventions that uses fixed duration after Maghrib. 100 | 101 | For these conventions, there is something called _Fajr angle_ and _Isha angle_ which basically the value of Sun altitude **below** the horizon. So, if Fajr angle is 18 degrees, then it means the Sun altitude is -18 degrees. 102 | 103 | | No | Name | Fajr Angle | Isha Angle | Maghrib Duration | Description | 104 | | :-: | :---------: | :--------: | :--------: | :--------------: | :------------------------------------------------------------------------------------------------------------------------------: | 105 | | 1 | MWL | 18 | 17 | | Calculation method from Muslim World League, usually used in Europe, Far East and parts of America. Default in most calculators. | 106 | | 2 | ISNA | 15 | 15 | | Calculation method from Islamic Society of North America, used in Canada and USA. | 107 | | 3 | Umm al-Qura | 18.5 | | 90 minutes | Calculation method from Umm al-Qura University in Makkah which used in Saudi Arabia. | 108 | | 4 | Gulf | 19.5 | | 90 minutes | Calculation method that often used by countries in Gulf region like UAE and Kuwait. | 109 | | 5 | Algerian | 18 | 17 | | Calculation method from Algerian Ministry of Religious Affairs and Wakfs. | 110 | | 6 | Karachi | 18 | 18 | | Calculation method from University of Islamic Sciences, Karachi. | 111 | | 7 | Diyanet | 18 | 17 | | Calculation method from Turkey's Diyanet İşleri Başkanlığı. | 112 | | 8 | Egypt | 19.5 | 17.5 | | Calculation method from Egyptian General Authority of Survey. | 113 | | 9 | Egypt Bis | 20 | 18 | | Another calculation method from Egyptian General Authority of Survey. | 114 | | 10 | Kemenag | 20 | 18 | | Calculation method from Kementerian Agama Republik Indonesia. | 115 | | 11 | MUIS | 20 | 18 | | Calculation method from Majlis Ugama Islam Singapura. | 116 | | 12 | JAKIM | 20 | 18 | | Calculation method from Jabatan Kemajuan Islam Malaysia. | 117 | | 13 | UOIF | 12 | 12 | | Calculation method from Union Des Organisations Islamiques De France. | 118 | | 14 | France15 | 15 | 15 | | Calculation method for France region with Fajr and Isha both at 15°. | 119 | | 15 | France18 | 18 | 18 | | Another calculation method for France region with Fajr and Isha both at 18°. | 120 | | 16 | Tunisia | 18 | 18 | | Calculation method from Tunisian Ministry of Religious Affairs. | 121 | | 17 | Tehran | 17.7 | 14 | | Calculation method from Institute of Geophysics at University of Tehran. | 122 | | 18 | Jafari | 16 | 14 | | Calculation method from Shia Ithna Ashari that used in some Shia communities worldwide. | 123 | 124 | These conventions are gatehered from various sources: 125 | 126 | - [PrayTimes.org][angle-praytimes] 127 | - [IslamicFinder.us][angle-islamicfinder] 128 | - [MuslimPro.com][angle-muslimpro] 129 | 130 | ## Asr Conventions 131 | 132 | As mentioned before, Asr time is determined by the length of shadow of an object. However there are different opinions on how long the shadow should be: 133 | 134 | - In Hanafi school, Asr started when shadow length is **twice** the length of object + shadow length at noon. 135 | - In Shafi'i school, Asr started when shadow length is **equal** the length of object + shadow length at noon. 136 | 137 | ## Higher Latitude Conventions 138 | 139 | In locations at higher latitude, Sun might never rise or set for an entire day. In these abnormal periods, the determination of Fajr, Maghrib and Isha is not possible to calculate using the normal methods. This problem has been explained in detail by [PrayerTimes.dk][high-lat-introduction]. 140 | 141 | To overcome this issue, several solutions have been proposed by Muslim scholars: 142 | 143 | 1. **Follow schedules in Mecca** 144 | 145 | This convention based on Fatwa from Dar Al Iftah Al Misrriyah number 2806 dated at 2010-08-08. They propose that area with higher latitude to follows the schedule in Mecca when abnormal days occured, using transit time as the common point. Here the day is considered "abnormal" when there are no true night, or the day length is less than 4 hours. 146 | 147 | To prevent sudden schedule changes, this method uses transition period for maximum one month before and after the abnormal periods. 148 | 149 | This method doesn't require the sunrise and sunset to be exist in a day, so it's usable for area in extreme latitudes (>=65 degrees). 150 | 151 | For more detail, check out [PrayerTimes.dk][high-lat-mecca]. If you want to use this convention, you can do so by using `Mecca()` or `AlwaysMecca()` as `HighLatitudeAdapter` in config. 152 | 153 | 2. **Local Relative Estimation** 154 | 155 | "Local Relative Estimation" is method that created by cooperation between Fiqh Council of Muslim World League and Islamic Crescents' Observation Project (ICOP). In short, this method uses average percentage to calculate Fajr and Isha time for abnormal times. 156 | 157 | This method only estimates time for Isha and Fajr and require sunrise and sunset time. Therefore it's not suitable for area in extreme latitude (>=65 degrees). 158 | 159 | For more detail, check out [ICOP's site][high-lat-local-relative]. If you want to use this convention, you can do so by using `LocalRelativeEstimation()` as `HighLatitudeAdapter` in config. 160 | 161 | 3. **Use the schedule of last normal day before abnormal periods** 162 | 163 | In this method, the schedule for "abnormal" days will be taken from the schedule of the last "normal" day. This adapter doesn't require the sunrise and sunset to be exist in a day, so it's usable for area in extreme latitudes (>=65 degrees). 164 | 165 | For more detail, check out this [paper][high-lat-nearest-day]. If you want to use this convention, you can do so by using `NearestDay()` as `HighLatitudeAdapter` in config. 166 | 167 | 4. **Follow schedules in nearest latitude** 168 | 169 | In this method, the schedules will be estimated using percentage of schedule in location at the nearest 45 degrees latitude. For example, Amsterdam is located at 52°22'N / 4°54'E. Using this method, the schedule will be estimated using location at 45°00'N / 4°54'E. This method will change the schedule for entire year to prevent sudden changes in fasting time. 170 | 171 | This adapter only estimates time for Isha and Fajr and require sunrise and sunset time, therefore it's not suitable for area in extreme latitude (>=65 degrees). For those area, instead of using percentage, this method recommends to use schedule from the nearest latitude as it is without any change. 172 | 173 | For more detail, check out this article from [IslamOnline.net][high-lat-nearest-latitude]. This method also briefly mentioned in Islamicity's [paper][high-lat-nearest-day]. 174 | 175 | If you want to use this convention, you can do so by using `NearestLatitude()` or `NearestLatitudeAsIs()` as `HighLatitudeAdapter` in config. 176 | 177 | Another alternative of this method is [proposed][high-lat-shari-normal-day] by Mohamed Nabeel Tarabishy, Ph.D. He proposes that a normal day is defined as day when the fasting period is between 10h17m and 17h36m. If the day is "abnormal" then the schedule is calculated using location at the nearest 45 degrees latitude. 178 | 179 | However, using his method there will be sudden changes in prayer schedules. To avoid this issue, the author has given suggestion to just use the schedule from 45° for entire year as has explained before. 180 | 181 | So, following that suggestion, we don't recommend you to use his method. If you still want to try, you can do so by using `ShariNormalDay()` as `HighLatitudeAdapter` in config. 182 | 183 | 5. **Isha and Fajr calculated using angle-based method** 184 | 185 | In this method, the night period is divided into several parts, depending on the value of twilight angle for Fajr and Isha. For example, let a be the twilight angle for Isha, and let t = a/60. The period between sunset and sunrise is divided into t parts. Isha begins after the first part. So, if the twilight angle for Isha is 15, then Isha begins at the end of the first quarter (15/60) of the night. Time for Fajr is calculated similarly. 186 | 187 | This adapter depends on sunrise and sunset time, so it might not be suitable for area in extreme latitudes (>=65 degrees). 188 | 189 | For more detail, check out this article by [PrayTimes.org][high-lat-angle-based]. If you want to use this convention, you can do so by using `AngleBased()` as `HighLatitudeAdapter` in config. 190 | 191 | 6. **Isha and Fajr at one-seventh of the night** 192 | 193 | In this method, the night period is divided into seven parts. Isha starts when the first seventh part ends, and Fajr starts when the last seventh part starts. 194 | 195 | This adapter depends on sunrise and sunset time, so it might not be suitable for area in extreme latitudes (>=65 degrees). 196 | 197 | For more detail, check out this article by [PrayTimes.org][high-lat-angle-based]. If you want to use this convention, you can do so by using `OneSeventhNight()` as `HighLatitudeAdapter` in config. 198 | 199 | 7. **Isha and Fajr in the middle of the night** 200 | 201 | In this method, the night period is divided into two halves. The first half is considered to be the "night" and the other half as "day break". Fajr and Isha in this method are assumed to be at mid-night during the abnormal periods. 202 | 203 | This adapter depends on sunrise and sunset time, so it might not be suitable for area in extreme latitudes (>=65 degrees). 204 | 205 | For more detail, check out this article by [PrayTimes.org][high-lat-angle-based]. If you want to use this convention, you can do so by using `MiddleNight()` as `HighLatitudeAdapter` in config. 206 | 207 | ## FAQ 208 | 209 | 1. **Does the elevation affects calculation result?** 210 | 211 | Yes, it will affect the result for sunrise and Maghrib time. If the elevation is very high, it can affect the times by a couple of minutes thanks to atmospheric refraction. However, most apps that I know prefer to set elevation to zero, which means every locations will be treated as located in sea level. 212 | 213 | 2. **Are the calculation results are really accurate up to seconds?** 214 | 215 | While the results of this package are in seconds, it's better to not expect it to be exactly accurate to seconds and instead treat it as minute rounding suggestions. 216 | 217 | 3. **Why are the Fajr, sunrise, Maghrib and Isha times occured in different day?** 218 | 219 | In this package, every times are connected to transit time (the time when Sun reach meridian). However, in area with higher latitude sometime the Sun will never rise nor set for the entire day. In this case, Fajr and sunrise might occur yesterday and the Maghrib and Isha might occur tomorrow. 220 | 221 | 4. **All of schedules are consistently missed by several minutes!** 222 | 223 | This package calculates the prayer times by utilizing Go SAMPA package to calculate Sun events in a day. That package uses several mathematic and astronomy formula, and has been tested with several astronomy applications and we found that it's pretty accurate within a minute. With that said, we hope the prayer times that calculated by this package should be mathematically accurate. 224 | 225 | However, in some locations the local scholar usually will adjust the schedule forward or backward for a few minutes. This is done for safety, to prevent the azan or prayer commenced before the actual time begin. And as mentioned before, in some country azan for Zuhr will be delayed for several minutes to follow the hadith that prohibit prayer when Sun reach its meridian. 226 | 227 | In case like this, you can easily adjust the time using `Corrections` field in configuration. 228 | 229 | 5. **I live in area with higher latitude, and no conventions provided in this package matches with the official schedule used in my area!** 230 | 231 | Since prayer in higher latitude is a matter of _ijtihad_, there are no definitive final texts pertaining to it. Therefore it's allowed for local Islamic bodies to specify their own conventions in order to save the Muslims living in that area from inconvenience and difficulty. Thanks to this, it's possible the convention that used in your area is not provided by this package. 232 | 233 | Fortunately, `HighLatitudeAdapter` is simply a function that defined like this: 234 | 235 | ```go 236 | type HighLatitudeAdapter func(cfg Config, year int, currentSchedules []Schedule) []Schedule 237 | ``` 238 | 239 | So, if the convention is not available in this package but you know how the convention works, you can simply define it on your own. It would be even better if you open PR to add it to this package. 240 | 241 | If you know how the convention works but don't want to code it yourself, feel free to open an issue so we could add it to this package. 242 | 243 | ## License 244 | 245 | Go-Prayer is distributed using [MIT] license. 246 | 247 | [doc-pkg-badge]: https://img.shields.io/badge/-pkg.go-007d9c?logo=go&labelColor=gray&logoColor=white 248 | [doc-pkg-url]: https://pkg.go.dev/github.com/hablullah/go-prayer 249 | [doc-godocs-badge]: https://img.shields.io/badge/-godocs-375eab?logo=go&labelColor=gray&logoColor=white 250 | [doc-godocs-url]: https://godocs.io/github.com/hablullah/go-prayer 251 | [spa]: https://midcdmz.nrel.gov/spa/ 252 | [go-sampa]: https://github.com/hablullah/go-sampa 253 | [angle-praytimes]: http://praytimes.org/wiki/Calculation_Methods 254 | [angle-islamicfinder]: http://www.islamicfinder.us/index.php/api/index 255 | [angle-muslimpro]: https://www.muslimpro.com/en/prayer-times 256 | [high-lat-introduction]: https://www.prayertimes.dk/story.html 257 | [high-lat-mecca]: https://www.prayertimes.dk/fatawa.html 258 | [high-lat-local-relative]: https://www.astronomycenter.net/latitude.html?l=en 259 | [high-lat-nearest-day]: https://www.islamicity.com/prayertimes/Salat.pdf 260 | [high-lat-nearest-latitude]: https://fiqh.islamonline.net/en/praying-and-fasting-at-high-latitudes/ 261 | [high-lat-shari-normal-day]: https://www.astronomycenter.net/pdf/tarabishyshigh_2014.pdf 262 | [high-lat-angle-based]: http://praytimes.org/calculation 263 | [mit]: http://choosealicense.com/licenses/mit/ 264 | -------------------------------------------------------------------------------- /internal/datatest/tromso.go: -------------------------------------------------------------------------------- 1 | package datatest 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hablullah/go-prayer" 7 | ) 8 | 9 | var tzTromso, _ = time.LoadLocation("CET") 10 | 11 | var Tromso = TestData{ 12 | Name: "Tromso", 13 | Latitude: 69.682778, 14 | Longitude: 18.942778, 15 | Timezone: tzTromso, 16 | Schedules: []prayer.Schedule{ 17 | schedule("2023-01-01", "2023-01-01 06:29:10", " ", "2023-01-01 11:47:38", "2023-01-01 12:19:44", " ", "2023-01-01 17:06:31", tzTromso), 18 | schedule("2023-01-02", "2023-01-02 06:28:41", " ", "2023-01-02 11:48:06", "2023-01-02 12:19:48", " ", "2023-01-02 17:07:59", tzTromso), 19 | schedule("2023-01-03", "2023-01-03 06:28:07", " ", "2023-01-03 11:48:34", "2023-01-03 12:19:49", " ", "2023-01-03 17:09:31", tzTromso), 20 | schedule("2023-01-04", "2023-01-04 06:27:27", " ", "2023-01-04 11:49:01", "2023-01-04 12:19:46", " ", "2023-01-04 17:11:07", tzTromso), 21 | schedule("2023-01-05", "2023-01-05 06:26:42", " ", "2023-01-05 11:49:28", "2023-01-05 12:19:41", " ", "2023-01-05 17:12:49", tzTromso), 22 | schedule("2023-01-06", "2023-01-06 06:25:52", " ", "2023-01-06 11:49:55", "2023-01-06 12:19:34", " ", "2023-01-06 17:14:34", tzTromso), 23 | schedule("2023-01-07", "2023-01-07 06:24:56", " ", "2023-01-07 11:50:21", "2023-01-07 12:19:25", " ", "2023-01-07 17:16:24", tzTromso), 24 | schedule("2023-01-08", "2023-01-08 06:23:55", " ", "2023-01-08 11:50:46", "2023-01-08 12:19:15", " ", "2023-01-08 17:18:18", tzTromso), 25 | schedule("2023-01-09", "2023-01-09 06:22:49", " ", "2023-01-09 11:51:11", "2023-01-09 12:19:04", " ", "2023-01-09 17:20:17", tzTromso), 26 | schedule("2023-01-10", "2023-01-10 06:21:38", " ", "2023-01-10 11:51:36", "2023-01-10 12:18:53", " ", "2023-01-10 17:22:19", tzTromso), 27 | schedule("2023-01-11", "2023-01-11 06:20:22", " ", "2023-01-11 11:52:00", "2023-01-11 12:18:42", " ", "2023-01-11 17:24:26", tzTromso), 28 | schedule("2023-01-12", "2023-01-12 06:19:01", " ", "2023-01-12 11:52:23", "2023-01-12 12:18:34", " ", "2023-01-12 17:26:36", tzTromso), 29 | schedule("2023-01-13", "2023-01-13 06:17:34", " ", "2023-01-13 11:52:46", "2023-01-13 12:18:27", " ", "2023-01-13 17:28:50", tzTromso), 30 | schedule("2023-01-14", "2023-01-14 06:16:03", " ", "2023-01-14 11:53:08", "2023-01-14 12:18:25", " ", "2023-01-14 17:31:08", tzTromso), 31 | schedule("2023-01-15", "2023-01-15 06:14:27", " ", "2023-01-15 11:53:30", "2023-01-15 12:18:27", " ", "2023-01-15 17:33:30", tzTromso), 32 | schedule("2023-01-16", "2023-01-16 06:12:46", "2023-01-16 11:19:49", "2023-01-16 11:53:51", "2023-01-16 12:18:34", "2023-01-16 12:28:38", "2023-01-16 17:35:55", tzTromso), 33 | schedule("2023-01-17", "2023-01-17 06:11:00", "2023-01-17 11:06:48", "2023-01-17 11:54:11", "2023-01-17 12:18:48", "2023-01-17 12:42:21", "2023-01-17 17:38:23", tzTromso), 34 | schedule("2023-01-18", "2023-01-18 06:09:10", "2023-01-18 10:56:26", "2023-01-18 11:54:31", "2023-01-18 12:19:10", "2023-01-18 12:53:24", "2023-01-18 17:40:55", tzTromso), 35 | schedule("2023-01-19", "2023-01-19 06:07:15", "2023-01-19 10:47:27", "2023-01-19 11:54:49", "2023-01-19 12:19:41", "2023-01-19 13:03:02", "2023-01-19 17:43:31", tzTromso), 36 | schedule("2023-01-20", "2023-01-20 06:05:15", "2023-01-20 10:39:20", "2023-01-20 11:55:08", "2023-01-20 12:20:20", "2023-01-20 13:11:46", "2023-01-20 17:46:09", tzTromso), 37 | schedule("2023-01-21", "2023-01-21 06:03:10", "2023-01-21 10:31:50", "2023-01-21 11:55:25", "2023-01-21 12:21:07", "2023-01-21 13:19:53", "2023-01-21 17:48:50", tzTromso), 38 | schedule("2023-01-22", "2023-01-22 06:01:02", "2023-01-22 10:24:47", "2023-01-22 11:55:42", "2023-01-22 12:22:04", "2023-01-22 13:27:30", "2023-01-22 17:51:35", tzTromso), 39 | schedule("2023-01-23", "2023-01-23 05:58:48", "2023-01-23 10:18:05", "2023-01-23 11:55:57", "2023-01-23 12:23:11", "2023-01-23 13:34:46", "2023-01-23 17:54:22", tzTromso), 40 | schedule("2023-01-24", "2023-01-24 05:56:30", "2023-01-24 10:11:40", "2023-01-24 11:56:13", "2023-01-24 12:24:27", "2023-01-24 13:41:43", "2023-01-24 17:57:13", tzTromso), 41 | schedule("2023-01-25", "2023-01-25 05:54:08", "2023-01-25 10:05:28", "2023-01-25 11:56:27", "2023-01-25 12:25:51", "2023-01-25 13:48:25", "2023-01-25 18:00:06", tzTromso), 42 | schedule("2023-01-26", "2023-01-26 05:51:42", "2023-01-26 09:59:27", "2023-01-26 11:56:40", "2023-01-26 12:27:24", "2023-01-26 13:54:54", "2023-01-26 18:03:02", tzTromso), 43 | schedule("2023-01-27", "2023-01-27 05:49:11", "2023-01-27 09:53:36", "2023-01-27 11:56:53", "2023-01-27 12:29:04", "2023-01-27 14:01:12", "2023-01-27 18:06:00", tzTromso), 44 | schedule("2023-01-28", "2023-01-28 05:46:36", "2023-01-28 09:47:53", "2023-01-28 11:57:05", "2023-01-28 12:30:52", "2023-01-28 14:07:19", "2023-01-28 18:09:01", tzTromso), 45 | schedule("2023-01-29", "2023-01-29 05:43:57", "2023-01-29 09:42:18", "2023-01-29 11:57:16", "2023-01-29 12:32:45", "2023-01-29 14:13:19", "2023-01-29 18:12:05", tzTromso), 46 | schedule("2023-01-30", "2023-01-30 05:41:13", "2023-01-30 09:36:48", "2023-01-30 11:57:26", "2023-01-30 12:34:44", "2023-01-30 14:19:10", "2023-01-30 18:15:11", tzTromso), 47 | schedule("2023-01-31", "2023-01-31 05:38:26", "2023-01-31 09:31:24", "2023-01-31 11:57:35", "2023-01-31 12:36:48", "2023-01-31 14:24:54", "2023-01-31 18:18:20", tzTromso), 48 | schedule("2023-02-01", "2023-02-01 05:35:34", "2023-02-01 09:26:05", "2023-02-01 11:57:44", "2023-02-01 12:38:57", "2023-02-01 14:30:32", "2023-02-01 18:21:31", tzTromso), 49 | schedule("2023-02-02", "2023-02-02 05:32:38", "2023-02-02 09:20:50", "2023-02-02 11:57:51", "2023-02-02 12:41:09", "2023-02-02 14:36:03", "2023-02-02 18:24:44", tzTromso), 50 | schedule("2023-02-03", "2023-02-03 05:29:39", "2023-02-03 09:15:39", "2023-02-03 11:57:58", "2023-02-03 12:43:26", "2023-02-03 14:41:29", "2023-02-03 18:28:00", tzTromso), 51 | schedule("2023-02-04", "2023-02-04 05:26:35", "2023-02-04 09:10:31", "2023-02-04 11:58:04", "2023-02-04 12:45:46", "2023-02-04 14:46:51", "2023-02-04 18:31:18", tzTromso), 52 | schedule("2023-02-05", "2023-02-05 05:23:28", "2023-02-05 09:05:26", "2023-02-05 11:58:09", "2023-02-05 12:48:08", "2023-02-05 14:52:07", "2023-02-05 18:34:39", tzTromso), 53 | schedule("2023-02-06", "2023-02-06 05:20:16", "2023-02-06 09:00:25", "2023-02-06 11:58:14", "2023-02-06 12:50:33", "2023-02-06 14:57:19", "2023-02-06 18:38:02", tzTromso), 54 | schedule("2023-02-07", "2023-02-07 05:17:01", "2023-02-07 08:55:26", "2023-02-07 11:58:17", "2023-02-07 12:53:01", "2023-02-07 15:02:26", "2023-02-07 18:41:27", tzTromso), 55 | schedule("2023-02-08", "2023-02-08 05:13:42", "2023-02-08 08:50:29", "2023-02-08 11:58:20", "2023-02-08 12:55:30", "2023-02-08 15:07:30", "2023-02-08 18:44:55", tzTromso), 56 | schedule("2023-02-09", "2023-02-09 05:10:18", "2023-02-09 08:45:34", "2023-02-09 11:58:22", "2023-02-09 12:58:01", "2023-02-09 15:12:30", "2023-02-09 18:48:25", tzTromso), 57 | schedule("2023-02-10", "2023-02-10 05:06:51", "2023-02-10 08:40:41", "2023-02-10 11:58:24", "2023-02-10 13:00:34", "2023-02-10 15:17:27", "2023-02-10 18:51:57", tzTromso), 58 | schedule("2023-02-11", "2023-02-11 05:03:20", "2023-02-11 08:35:50", "2023-02-11 11:58:24", "2023-02-11 13:03:09", "2023-02-11 15:22:20", "2023-02-11 18:55:32", tzTromso), 59 | schedule("2023-02-12", "2023-02-12 04:59:45", "2023-02-12 08:31:01", "2023-02-12 11:58:24", "2023-02-12 13:05:44", "2023-02-12 15:27:10", "2023-02-12 18:59:09", tzTromso), 60 | schedule("2023-02-13", "2023-02-13 04:56:07", "2023-02-13 08:26:13", "2023-02-13 11:58:23", "2023-02-13 13:08:20", "2023-02-13 15:31:57", "2023-02-13 19:02:49", tzTromso), 61 | schedule("2023-02-14", "2023-02-14 04:52:24", "2023-02-14 08:21:27", "2023-02-14 11:58:21", "2023-02-14 13:10:58", "2023-02-14 15:36:42", "2023-02-14 19:06:32", tzTromso), 62 | schedule("2023-02-15", "2023-02-15 04:48:37", "2023-02-15 08:16:41", "2023-02-15 11:58:19", "2023-02-15 13:13:36", "2023-02-15 15:41:23", "2023-02-15 19:10:17", tzTromso), 63 | schedule("2023-02-16", "2023-02-16 04:44:46", "2023-02-16 08:11:57", "2023-02-16 11:58:16", "2023-02-16 13:16:14", "2023-02-16 15:46:02", "2023-02-16 19:14:04", tzTromso), 64 | schedule("2023-02-17", "2023-02-17 04:40:51", "2023-02-17 08:07:14", "2023-02-17 11:58:12", "2023-02-17 13:18:53", "2023-02-17 15:50:39", "2023-02-17 19:17:55", tzTromso), 65 | schedule("2023-02-18", "2023-02-18 04:36:53", "2023-02-18 08:02:33", "2023-02-18 11:58:07", "2023-02-18 13:21:33", "2023-02-18 15:55:13", "2023-02-18 19:21:48", tzTromso), 66 | schedule("2023-02-19", "2023-02-19 04:32:50", "2023-02-19 07:57:52", "2023-02-19 11:58:02", "2023-02-19 13:24:13", "2023-02-19 15:59:45", "2023-02-19 19:25:44", tzTromso), 67 | schedule("2023-02-20", "2023-02-20 04:28:42", "2023-02-20 07:53:11", "2023-02-20 11:57:56", "2023-02-20 13:26:52", "2023-02-20 16:04:15", "2023-02-20 19:29:44", tzTromso), 68 | schedule("2023-02-21", "2023-02-21 04:24:31", "2023-02-21 07:48:32", "2023-02-21 11:57:50", "2023-02-21 13:29:32", "2023-02-21 16:08:42", "2023-02-21 19:33:46", tzTromso), 69 | schedule("2023-02-22", "2023-02-22 04:20:15", "2023-02-22 07:43:54", "2023-02-22 11:57:43", "2023-02-22 13:32:12", "2023-02-22 16:13:08", "2023-02-22 19:37:51", tzTromso), 70 | schedule("2023-02-23", "2023-02-23 04:15:54", "2023-02-23 07:39:16", "2023-02-23 11:57:35", "2023-02-23 13:34:52", "2023-02-23 16:17:31", "2023-02-23 19:42:00", tzTromso), 71 | schedule("2023-02-24", "2023-02-24 04:11:29", "2023-02-24 07:34:38", "2023-02-24 11:57:26", "2023-02-24 13:37:31", "2023-02-24 16:21:53", "2023-02-24 19:46:13", tzTromso), 72 | schedule("2023-02-25", "2023-02-25 04:06:59", "2023-02-25 07:30:02", "2023-02-25 11:57:17", "2023-02-25 13:40:10", "2023-02-25 16:26:13", "2023-02-25 19:50:29", tzTromso), 73 | schedule("2023-02-26", "2023-02-26 04:02:25", "2023-02-26 07:25:25", "2023-02-26 11:57:08", "2023-02-26 13:42:49", "2023-02-26 16:30:31", "2023-02-26 19:54:49", tzTromso), 74 | schedule("2023-02-27", "2023-02-27 03:57:45", "2023-02-27 07:20:50", "2023-02-27 11:56:57", "2023-02-27 13:45:28", "2023-02-27 16:34:47", "2023-02-27 19:59:13", tzTromso), 75 | schedule("2023-02-28", "2023-02-28 03:53:00", "2023-02-28 07:16:15", "2023-02-28 11:56:47", "2023-02-28 13:48:06", "2023-02-28 16:39:02", "2023-02-28 20:03:41", tzTromso), 76 | schedule("2023-03-01", "2023-03-01 03:48:10", "2023-03-01 07:11:40", "2023-03-01 11:56:35", "2023-03-01 13:50:43", "2023-03-01 16:43:16", "2023-03-01 20:08:14", tzTromso), 77 | schedule("2023-03-02", "2023-03-02 03:43:14", "2023-03-02 07:07:05", "2023-03-02 11:56:24", "2023-03-02 13:53:20", "2023-03-02 16:47:28", "2023-03-02 20:12:52", tzTromso), 78 | schedule("2023-03-03", "2023-03-03 03:38:13", "2023-03-03 07:02:31", "2023-03-03 11:56:11", "2023-03-03 13:55:57", "2023-03-03 16:51:39", "2023-03-03 20:17:35", tzTromso), 79 | schedule("2023-03-04", "2023-03-04 03:33:05", "2023-03-04 06:57:57", "2023-03-04 11:55:58", "2023-03-04 13:58:32", "2023-03-04 16:55:48", "2023-03-04 20:22:23", tzTromso), 80 | schedule("2023-03-05", "2023-03-05 03:27:50", "2023-03-05 06:53:24", "2023-03-05 11:55:45", "2023-03-05 14:01:07", "2023-03-05 16:59:56", "2023-03-05 20:27:18", tzTromso), 81 | schedule("2023-03-06", "2023-03-06 03:22:29", "2023-03-06 06:48:51", "2023-03-06 11:55:31", "2023-03-06 14:03:42", "2023-03-06 17:04:03", "2023-03-06 20:32:19", tzTromso), 82 | schedule("2023-03-07", "2023-03-07 03:17:01", "2023-03-07 06:44:17", "2023-03-07 11:55:17", "2023-03-07 14:06:16", "2023-03-07 17:08:10", "2023-03-07 20:37:26", tzTromso), 83 | schedule("2023-03-08", "2023-03-08 03:11:25", "2023-03-08 06:39:45", "2023-03-08 11:55:03", "2023-03-08 14:08:49", "2023-03-08 17:12:15", "2023-03-08 20:42:42", tzTromso), 84 | schedule("2023-03-09", "2023-03-09 03:05:40", "2023-03-09 06:35:12", "2023-03-09 11:54:48", "2023-03-09 14:11:21", "2023-03-09 17:16:19", "2023-03-09 20:48:06", tzTromso), 85 | schedule("2023-03-10", "2023-03-10 02:59:47", "2023-03-10 06:30:39", "2023-03-10 11:54:33", "2023-03-10 14:13:52", "2023-03-10 17:20:23", "2023-03-10 20:53:38", tzTromso), 86 | schedule("2023-03-11", "2023-03-11 02:53:43", "2023-03-11 06:26:07", "2023-03-11 11:54:17", "2023-03-11 14:16:23", "2023-03-11 17:24:25", "2023-03-11 20:59:21", tzTromso), 87 | schedule("2023-03-12", "2023-03-12 02:47:29", "2023-03-12 06:21:34", "2023-03-12 11:54:01", "2023-03-12 14:18:53", "2023-03-12 17:28:28", "2023-03-12 21:05:15", tzTromso), 88 | schedule("2023-03-13", "2023-03-13 02:41:04", "2023-03-13 06:17:01", "2023-03-13 11:53:45", "2023-03-13 14:21:22", "2023-03-13 17:32:29", "2023-03-13 21:11:21", tzTromso), 89 | schedule("2023-03-14", "2023-03-14 02:34:26", "2023-03-14 06:12:29", "2023-03-14 11:53:29", "2023-03-14 14:23:51", "2023-03-14 17:36:30", "2023-03-14 21:17:41", tzTromso), 90 | schedule("2023-03-15", "2023-03-15 02:27:33", "2023-03-15 06:07:56", "2023-03-15 11:53:12", "2023-03-15 14:26:18", "2023-03-15 17:40:31", "2023-03-15 21:24:16", tzTromso), 91 | schedule("2023-03-16", "2023-03-16 02:20:24", "2023-03-16 06:03:24", "2023-03-16 11:52:55", "2023-03-16 14:28:45", "2023-03-16 17:44:31", "2023-03-16 21:31:10", tzTromso), 92 | schedule("2023-03-17", "2023-03-17 02:12:57", "2023-03-17 05:58:51", "2023-03-17 11:52:38", "2023-03-17 14:31:11", "2023-03-17 17:48:32", "2023-03-17 21:38:25", tzTromso), 93 | schedule("2023-03-18", "2023-03-18 02:05:08", "2023-03-18 05:54:18", "2023-03-18 11:52:21", "2023-03-18 14:33:36", "2023-03-18 17:52:31", "2023-03-18 21:46:04", tzTromso), 94 | schedule("2023-03-19", "2023-03-19 01:56:55", "2023-03-19 05:49:45", "2023-03-19 11:52:04", "2023-03-19 14:36:00", "2023-03-19 17:56:31", "2023-03-19 21:54:14", tzTromso), 95 | schedule("2023-03-20", "2023-03-20 01:48:11", "2023-03-20 05:45:12", "2023-03-20 11:51:46", "2023-03-20 14:38:23", "2023-03-20 18:00:31", "2023-03-20 22:02:59", tzTromso), 96 | schedule("2023-03-21", "2023-03-21 01:38:50", "2023-03-21 05:40:39", "2023-03-21 11:51:28", "2023-03-21 14:40:45", "2023-03-21 18:04:30", "2023-03-21 22:12:32", tzTromso), 97 | schedule("2023-03-22", "2023-03-22 01:28:43", "2023-03-22 05:36:05", "2023-03-22 11:51:11", "2023-03-22 14:43:07", "2023-03-22 18:08:30", "2023-03-22 22:23:08", tzTromso), 98 | schedule("2023-03-23", "2023-03-23 01:17:32", "2023-03-23 05:31:32", "2023-03-23 11:50:53", "2023-03-23 14:45:27", "2023-03-23 18:12:30", "2023-03-23 22:35:13", tzTromso), 99 | schedule("2023-03-24", "2023-03-24 01:04:51", "2023-03-24 05:26:58", "2023-03-24 11:50:35", "2023-03-24 14:47:47", "2023-03-24 18:16:29", "2023-03-24 22:49:43", tzTromso), 100 | schedule("2023-03-25", "2023-03-25 00:49:45", "2023-03-25 05:22:23", "2023-03-25 11:50:17", "2023-03-25 14:50:05", "2023-03-25 18:20:29", "2023-03-25 23:09:14", tzTromso), 101 | schedule("2023-03-26", "2023-03-26 00:29:40", "2023-03-26 06:17:49", "2023-03-26 12:49:55", "2023-03-26 15:52:11", "2023-03-26 19:24:16", "2023-03-27 00:18:37", tzTromso), 102 | schedule("2023-03-27", " ", "2023-03-27 06:13:14", "2023-03-27 12:49:40", "2023-03-27 15:54:45", "2023-03-27 19:28:29", " ", tzTromso), 103 | schedule("2023-03-28", " ", "2023-03-28 06:08:38", "2023-03-28 12:49:23", "2023-03-28 15:57:03", "2023-03-28 19:32:31", " ", tzTromso), 104 | schedule("2023-03-29", " ", "2023-03-29 06:04:02", "2023-03-29 12:49:05", "2023-03-29 15:59:18", "2023-03-29 19:36:33", " ", tzTromso), 105 | schedule("2023-03-30", " ", "2023-03-30 05:59:26", "2023-03-30 12:48:47", "2023-03-30 16:01:31", "2023-03-30 19:40:35", " ", tzTromso), 106 | schedule("2023-03-31", " ", "2023-03-31 05:54:49", "2023-03-31 12:48:29", "2023-03-31 16:03:44", "2023-03-31 19:44:38", " ", tzTromso), 107 | schedule("2023-04-01", " ", "2023-04-01 05:50:12", "2023-04-01 12:48:11", "2023-04-01 16:05:55", "2023-04-01 19:48:41", " ", tzTromso), 108 | schedule("2023-04-02", " ", "2023-04-02 05:45:34", "2023-04-02 12:47:53", "2023-04-02 16:08:06", "2023-04-02 19:52:45", " ", tzTromso), 109 | schedule("2023-04-03", " ", "2023-04-03 05:40:56", "2023-04-03 12:47:35", "2023-04-03 16:10:15", "2023-04-03 19:56:51", " ", tzTromso), 110 | schedule("2023-04-04", " ", "2023-04-04 05:36:17", "2023-04-04 12:47:18", "2023-04-04 16:12:24", "2023-04-04 20:00:57", " ", tzTromso), 111 | schedule("2023-04-05", " ", "2023-04-05 05:31:37", "2023-04-05 12:47:00", "2023-04-05 16:14:32", "2023-04-05 20:05:04", " ", tzTromso), 112 | schedule("2023-04-06", " ", "2023-04-06 05:26:56", "2023-04-06 12:46:43", "2023-04-06 16:16:39", "2023-04-06 20:09:12", " ", tzTromso), 113 | schedule("2023-04-07", " ", "2023-04-07 05:22:15", "2023-04-07 12:46:26", "2023-04-07 16:18:45", "2023-04-07 20:13:22", " ", tzTromso), 114 | schedule("2023-04-08", " ", "2023-04-08 05:17:33", "2023-04-08 12:46:09", "2023-04-08 16:20:50", "2023-04-08 20:17:33", " ", tzTromso), 115 | schedule("2023-04-09", " ", "2023-04-09 05:12:50", "2023-04-09 12:45:53", "2023-04-09 16:22:54", "2023-04-09 20:21:45", " ", tzTromso), 116 | schedule("2023-04-10", " ", "2023-04-10 05:08:06", "2023-04-10 12:45:37", "2023-04-10 16:24:57", "2023-04-10 20:25:59", " ", tzTromso), 117 | schedule("2023-04-11", " ", "2023-04-11 05:03:21", "2023-04-11 12:45:21", "2023-04-11 16:26:59", "2023-04-11 20:30:15", " ", tzTromso), 118 | schedule("2023-04-12", " ", "2023-04-12 04:58:35", "2023-04-12 12:45:05", "2023-04-12 16:29:00", "2023-04-12 20:34:32", " ", tzTromso), 119 | schedule("2023-04-13", " ", "2023-04-13 04:53:47", "2023-04-13 12:44:49", "2023-04-13 16:31:00", "2023-04-13 20:38:52", " ", tzTromso), 120 | schedule("2023-04-14", " ", "2023-04-14 04:48:59", "2023-04-14 12:44:34", "2023-04-14 16:33:00", "2023-04-14 20:43:13", " ", tzTromso), 121 | schedule("2023-04-15", " ", "2023-04-15 04:44:09", "2023-04-15 12:44:20", "2023-04-15 16:34:58", "2023-04-15 20:47:37", " ", tzTromso), 122 | schedule("2023-04-16", " ", "2023-04-16 04:39:17", "2023-04-16 12:44:06", "2023-04-16 16:36:56", "2023-04-16 20:52:03", " ", tzTromso), 123 | schedule("2023-04-17", " ", "2023-04-17 04:34:24", "2023-04-17 12:43:52", "2023-04-17 16:38:52", "2023-04-17 20:56:31", " ", tzTromso), 124 | schedule("2023-04-18", " ", "2023-04-18 04:29:30", "2023-04-18 12:43:38", "2023-04-18 16:40:48", "2023-04-18 21:01:02", " ", tzTromso), 125 | schedule("2023-04-19", " ", "2023-04-19 04:24:33", "2023-04-19 12:43:25", "2023-04-19 16:42:43", "2023-04-19 21:05:35", " ", tzTromso), 126 | schedule("2023-04-20", " ", "2023-04-20 04:19:35", "2023-04-20 12:43:12", "2023-04-20 16:44:36", "2023-04-20 21:10:12", " ", tzTromso), 127 | schedule("2023-04-21", " ", "2023-04-21 04:14:35", "2023-04-21 12:43:00", "2023-04-21 16:46:29", "2023-04-21 21:14:51", " ", tzTromso), 128 | schedule("2023-04-22", " ", "2023-04-22 04:09:33", "2023-04-22 12:42:48", "2023-04-22 16:48:21", "2023-04-22 21:19:34", " ", tzTromso), 129 | schedule("2023-04-23", " ", "2023-04-23 04:04:28", "2023-04-23 12:42:37", "2023-04-23 16:50:12", "2023-04-23 21:24:20", " ", tzTromso), 130 | schedule("2023-04-24", " ", "2023-04-24 03:59:20", "2023-04-24 12:42:26", "2023-04-24 16:52:01", "2023-04-24 21:29:10", " ", tzTromso), 131 | schedule("2023-04-25", " ", "2023-04-25 03:54:10", "2023-04-25 12:42:15", "2023-04-25 16:53:50", "2023-04-25 21:34:04", " ", tzTromso), 132 | schedule("2023-04-26", " ", "2023-04-26 03:48:57", "2023-04-26 12:42:05", "2023-04-26 16:55:38", "2023-04-26 21:39:02", " ", tzTromso), 133 | schedule("2023-04-27", " ", "2023-04-27 03:43:41", "2023-04-27 12:41:56", "2023-04-27 16:57:24", "2023-04-27 21:44:04", " ", tzTromso), 134 | schedule("2023-04-28", " ", "2023-04-28 03:38:21", "2023-04-28 12:41:47", "2023-04-28 16:59:09", "2023-04-28 21:49:11", " ", tzTromso), 135 | schedule("2023-04-29", " ", "2023-04-29 03:32:57", "2023-04-29 12:41:38", "2023-04-29 17:00:54", "2023-04-29 21:54:24", " ", tzTromso), 136 | schedule("2023-04-30", " ", "2023-04-30 03:27:29", "2023-04-30 12:41:30", "2023-04-30 17:02:37", "2023-04-30 21:59:42", " ", tzTromso), 137 | schedule("2023-05-01", " ", "2023-05-01 03:21:57", "2023-05-01 12:41:22", "2023-05-01 17:04:19", "2023-05-01 22:05:07", " ", tzTromso), 138 | schedule("2023-05-02", " ", "2023-05-02 03:16:19", "2023-05-02 12:41:15", "2023-05-02 17:06:00", "2023-05-02 22:10:38", " ", tzTromso), 139 | schedule("2023-05-03", " ", "2023-05-03 03:10:35", "2023-05-03 12:41:09", "2023-05-03 17:07:40", "2023-05-03 22:16:18", " ", tzTromso), 140 | schedule("2023-05-04", " ", "2023-05-04 03:04:44", "2023-05-04 12:41:03", "2023-05-04 17:09:19", "2023-05-04 22:22:05", " ", tzTromso), 141 | schedule("2023-05-05", " ", "2023-05-05 02:58:46", "2023-05-05 12:40:58", "2023-05-05 17:10:57", "2023-05-05 22:28:03", " ", tzTromso), 142 | schedule("2023-05-06", " ", "2023-05-06 02:52:40", "2023-05-06 12:40:53", "2023-05-06 17:12:33", "2023-05-06 22:34:11", " ", tzTromso), 143 | schedule("2023-05-07", " ", "2023-05-07 02:46:24", "2023-05-07 12:40:48", "2023-05-07 17:14:08", "2023-05-07 22:40:31", " ", tzTromso), 144 | schedule("2023-05-08", " ", "2023-05-08 02:39:57", "2023-05-08 12:40:45", "2023-05-08 17:15:42", "2023-05-08 22:47:06", " ", tzTromso), 145 | schedule("2023-05-09", " ", "2023-05-09 02:33:16", "2023-05-09 12:40:42", "2023-05-09 17:17:15", "2023-05-09 22:53:58", " ", tzTromso), 146 | schedule("2023-05-10", " ", "2023-05-10 02:26:20", "2023-05-10 12:40:39", "2023-05-10 17:18:47", "2023-05-10 23:01:10", " ", tzTromso), 147 | schedule("2023-05-11", " ", "2023-05-11 02:19:05", "2023-05-11 12:40:37", "2023-05-11 17:20:17", "2023-05-11 23:08:47", " ", tzTromso), 148 | schedule("2023-05-12", " ", "2023-05-12 02:11:26", "2023-05-12 12:40:36", "2023-05-12 17:21:47", "2023-05-12 23:16:55", " ", tzTromso), 149 | schedule("2023-05-13", " ", "2023-05-13 02:03:17", "2023-05-13 12:40:35", "2023-05-13 17:23:14", "2023-05-13 23:25:45", " ", tzTromso), 150 | schedule("2023-05-14", " ", "2023-05-14 01:54:27", "2023-05-14 12:40:35", "2023-05-14 17:24:41", "2023-05-14 23:35:33", " ", tzTromso), 151 | schedule("2023-05-15", " ", "2023-05-15 01:44:41", "2023-05-15 12:40:35", "2023-05-15 17:26:06", "2023-05-15 23:46:50", " ", tzTromso), 152 | schedule("2023-05-16", " ", "2023-05-16 01:33:26", "2023-05-16 12:40:36", "2023-05-16 17:27:30", "2023-05-17 00:00:52", " ", tzTromso), 153 | schedule("2023-05-17", " ", "2023-05-17 01:19:28", "2023-05-17 12:40:38", "2023-05-17 17:28:53", "2023-05-18 00:23:29", " ", tzTromso), 154 | schedule("2023-05-18", " ", "2023-05-18 00:56:56", "2023-05-18 12:40:40", "2023-05-18 17:30:14", "2023-05-19 00:48:38", " ", tzTromso), 155 | schedule("2023-05-19", " ", " ", "2023-05-19 12:40:42", "2023-05-19 17:31:33", " ", " ", tzTromso), 156 | schedule("2023-05-20", " ", " ", "2023-05-20 12:40:46", "2023-05-20 17:32:51", " ", " ", tzTromso), 157 | schedule("2023-05-21", " ", " ", "2023-05-21 12:40:49", "2023-05-21 17:34:08", " ", " ", tzTromso), 158 | schedule("2023-05-22", " ", " ", "2023-05-22 12:40:54", "2023-05-22 17:35:23", " ", " ", tzTromso), 159 | schedule("2023-05-23", " ", " ", "2023-05-23 12:40:59", "2023-05-23 17:36:36", " ", " ", tzTromso), 160 | schedule("2023-05-24", " ", " ", "2023-05-24 12:41:04", "2023-05-24 17:37:48", " ", " ", tzTromso), 161 | schedule("2023-05-25", " ", " ", "2023-05-25 12:41:10", "2023-05-25 17:38:58", " ", " ", tzTromso), 162 | schedule("2023-05-26", " ", " ", "2023-05-26 12:41:16", "2023-05-26 17:40:06", " ", " ", tzTromso), 163 | schedule("2023-05-27", " ", " ", "2023-05-27 12:41:23", "2023-05-27 17:41:12", " ", " ", tzTromso), 164 | schedule("2023-05-28", " ", " ", "2023-05-28 12:41:30", "2023-05-28 17:42:17", " ", " ", tzTromso), 165 | schedule("2023-05-29", " ", " ", "2023-05-29 12:41:38", "2023-05-29 17:43:20", " ", " ", tzTromso), 166 | schedule("2023-05-30", " ", " ", "2023-05-30 12:41:46", "2023-05-30 17:44:21", " ", " ", tzTromso), 167 | schedule("2023-05-31", " ", " ", "2023-05-31 12:41:54", "2023-05-31 17:45:20", " ", " ", tzTromso), 168 | schedule("2023-06-01", " ", " ", "2023-06-01 12:42:03", "2023-06-01 17:46:18", " ", " ", tzTromso), 169 | schedule("2023-06-02", " ", " ", "2023-06-02 12:42:12", "2023-06-02 17:47:13", " ", " ", tzTromso), 170 | schedule("2023-06-03", " ", " ", "2023-06-03 12:42:22", "2023-06-03 17:48:06", " ", " ", tzTromso), 171 | schedule("2023-06-04", " ", " ", "2023-06-04 12:42:32", "2023-06-04 17:48:58", " ", " ", tzTromso), 172 | schedule("2023-06-05", " ", " ", "2023-06-05 12:42:42", "2023-06-05 17:49:47", " ", " ", tzTromso), 173 | schedule("2023-06-06", " ", " ", "2023-06-06 12:42:53", "2023-06-06 17:50:34", " ", " ", tzTromso), 174 | schedule("2023-06-07", " ", " ", "2023-06-07 12:43:04", "2023-06-07 17:51:20", " ", " ", tzTromso), 175 | schedule("2023-06-08", " ", " ", "2023-06-08 12:43:15", "2023-06-08 17:52:03", " ", " ", tzTromso), 176 | schedule("2023-06-09", " ", " ", "2023-06-09 12:43:27", "2023-06-09 17:52:44", " ", " ", tzTromso), 177 | schedule("2023-06-10", " ", " ", "2023-06-10 12:43:39", "2023-06-10 17:53:23", " ", " ", tzTromso), 178 | schedule("2023-06-11", " ", " ", "2023-06-11 12:43:51", "2023-06-11 17:53:59", " ", " ", tzTromso), 179 | schedule("2023-06-12", " ", " ", "2023-06-12 12:44:03", "2023-06-12 17:54:34", " ", " ", tzTromso), 180 | schedule("2023-06-13", " ", " ", "2023-06-13 12:44:16", "2023-06-13 17:55:06", " ", " ", tzTromso), 181 | schedule("2023-06-14", " ", " ", "2023-06-14 12:44:28", "2023-06-14 17:55:36", " ", " ", tzTromso), 182 | schedule("2023-06-15", " ", " ", "2023-06-15 12:44:41", "2023-06-15 17:56:03", " ", " ", tzTromso), 183 | schedule("2023-06-16", " ", " ", "2023-06-16 12:44:54", "2023-06-16 17:56:28", " ", " ", tzTromso), 184 | schedule("2023-06-17", " ", " ", "2023-06-17 12:45:07", "2023-06-17 17:56:51", " ", " ", tzTromso), 185 | schedule("2023-06-18", " ", " ", "2023-06-18 12:45:20", "2023-06-18 17:57:11", " ", " ", tzTromso), 186 | schedule("2023-06-19", " ", " ", "2023-06-19 12:45:33", "2023-06-19 17:57:29", " ", " ", tzTromso), 187 | schedule("2023-06-20", " ", " ", "2023-06-20 12:45:47", "2023-06-20 17:57:45", " ", " ", tzTromso), 188 | schedule("2023-06-21", " ", " ", "2023-06-21 12:46:00", "2023-06-21 17:57:58", " ", " ", tzTromso), 189 | schedule("2023-06-22", " ", " ", "2023-06-22 12:46:13", "2023-06-22 17:58:08", " ", " ", tzTromso), 190 | schedule("2023-06-23", " ", " ", "2023-06-23 12:46:26", "2023-06-23 17:58:16", " ", " ", tzTromso), 191 | schedule("2023-06-24", " ", " ", "2023-06-24 12:46:39", "2023-06-24 17:58:21", " ", " ", tzTromso), 192 | schedule("2023-06-25", " ", " ", "2023-06-25 12:46:52", "2023-06-25 17:58:23", " ", " ", tzTromso), 193 | schedule("2023-06-26", " ", " ", "2023-06-26 12:47:04", "2023-06-26 17:58:23", " ", " ", tzTromso), 194 | schedule("2023-06-27", " ", " ", "2023-06-27 12:47:17", "2023-06-27 17:58:21", " ", " ", tzTromso), 195 | schedule("2023-06-28", " ", " ", "2023-06-28 12:47:29", "2023-06-28 17:58:15", " ", " ", tzTromso), 196 | schedule("2023-06-29", " ", " ", "2023-06-29 12:47:42", "2023-06-29 17:58:07", " ", " ", tzTromso), 197 | schedule("2023-06-30", " ", " ", "2023-06-30 12:47:53", "2023-06-30 17:57:57", " ", " ", tzTromso), 198 | schedule("2023-07-01", " ", " ", "2023-07-01 12:48:05", "2023-07-01 17:57:43", " ", " ", tzTromso), 199 | schedule("2023-07-02", " ", " ", "2023-07-02 12:48:17", "2023-07-02 17:57:27", " ", " ", tzTromso), 200 | schedule("2023-07-03", " ", " ", "2023-07-03 12:48:28", "2023-07-03 17:57:08", " ", " ", tzTromso), 201 | schedule("2023-07-04", " ", " ", "2023-07-04 12:48:38", "2023-07-04 17:56:47", " ", " ", tzTromso), 202 | schedule("2023-07-05", " ", " ", "2023-07-05 12:48:49", "2023-07-05 17:56:23", " ", " ", tzTromso), 203 | schedule("2023-07-06", " ", " ", "2023-07-06 12:48:59", "2023-07-06 17:55:56", " ", " ", tzTromso), 204 | schedule("2023-07-07", " ", " ", "2023-07-07 12:49:09", "2023-07-07 17:55:26", " ", " ", tzTromso), 205 | schedule("2023-07-08", " ", " ", "2023-07-08 12:49:18", "2023-07-08 17:54:54", " ", " ", tzTromso), 206 | schedule("2023-07-09", " ", " ", "2023-07-09 12:49:27", "2023-07-09 17:54:19", " ", " ", tzTromso), 207 | schedule("2023-07-10", " ", " ", "2023-07-10 12:49:36", "2023-07-10 17:53:42", " ", " ", tzTromso), 208 | schedule("2023-07-11", " ", " ", "2023-07-11 12:49:44", "2023-07-11 17:53:01", " ", " ", tzTromso), 209 | schedule("2023-07-12", " ", " ", "2023-07-12 12:49:52", "2023-07-12 17:52:18", " ", " ", tzTromso), 210 | schedule("2023-07-13", " ", " ", "2023-07-13 12:50:00", "2023-07-13 17:51:33", " ", " ", tzTromso), 211 | schedule("2023-07-14", " ", " ", "2023-07-14 12:50:07", "2023-07-14 17:50:44", " ", " ", tzTromso), 212 | schedule("2023-07-15", " ", " ", "2023-07-15 12:50:13", "2023-07-15 17:49:53", " ", " ", tzTromso), 213 | schedule("2023-07-16", " ", " ", "2023-07-16 12:50:19", "2023-07-16 17:48:59", " ", " ", tzTromso), 214 | schedule("2023-07-17", " ", " ", "2023-07-17 12:50:25", "2023-07-17 17:48:03", " ", " ", tzTromso), 215 | schedule("2023-07-18", " ", " ", "2023-07-18 12:50:29", "2023-07-18 17:47:04", " ", " ", tzTromso), 216 | schedule("2023-07-19", " ", " ", "2023-07-19 12:50:34", "2023-07-19 17:46:02", " ", " ", tzTromso), 217 | schedule("2023-07-20", " ", " ", "2023-07-20 12:50:38", "2023-07-20 17:44:57", " ", " ", tzTromso), 218 | schedule("2023-07-21", " ", " ", "2023-07-21 12:50:41", "2023-07-21 17:43:50", " ", " ", tzTromso), 219 | schedule("2023-07-22", " ", " ", "2023-07-22 12:50:44", "2023-07-22 17:42:41", " ", " ", tzTromso), 220 | schedule("2023-07-23", " ", " ", "2023-07-23 12:50:46", "2023-07-23 17:41:28", " ", " ", tzTromso), 221 | schedule("2023-07-24", " ", " ", "2023-07-24 12:50:47", "2023-07-24 17:40:13", " ", " ", tzTromso), 222 | schedule("2023-07-25", " ", " ", "2023-07-25 12:50:48", "2023-07-25 17:38:56", " ", " ", tzTromso), 223 | schedule("2023-07-26", " ", " ", "2023-07-26 12:50:48", "2023-07-26 17:37:36", " ", " ", tzTromso), 224 | schedule("2023-07-27", " ", "2023-07-27 01:21:09", "2023-07-27 12:50:48", "2023-07-27 17:36:13", "2023-07-28 00:04:44", " ", tzTromso), 225 | schedule("2023-07-28", " ", "2023-07-28 01:37:45", "2023-07-28 12:50:47", "2023-07-28 17:34:48", "2023-07-28 23:52:24", " ", tzTromso), 226 | schedule("2023-07-29", " ", "2023-07-29 01:50:04", "2023-07-29 12:50:45", "2023-07-29 17:33:20", "2023-07-29 23:41:59", " ", tzTromso), 227 | schedule("2023-07-30", " ", "2023-07-30 02:00:26", "2023-07-30 12:50:43", "2023-07-30 17:31:50", "2023-07-30 23:32:45", " ", tzTromso), 228 | schedule("2023-07-31", " ", "2023-07-31 02:09:36", "2023-07-31 12:50:40", "2023-07-31 17:30:17", "2023-07-31 23:24:18", " ", tzTromso), 229 | schedule("2023-08-01", " ", "2023-08-01 02:17:59", "2023-08-01 12:50:37", "2023-08-01 17:28:42", "2023-08-01 23:16:25", " ", tzTromso), 230 | schedule("2023-08-02", " ", "2023-08-02 02:25:45", "2023-08-02 12:50:33", "2023-08-02 17:27:05", "2023-08-02 23:08:59", " ", tzTromso), 231 | schedule("2023-08-03", " ", "2023-08-03 02:33:03", "2023-08-03 12:50:28", "2023-08-03 17:25:25", "2023-08-03 23:01:54", " ", tzTromso), 232 | schedule("2023-08-04", " ", "2023-08-04 02:40:00", "2023-08-04 12:50:23", "2023-08-04 17:23:43", "2023-08-04 22:55:07", " ", tzTromso), 233 | schedule("2023-08-05", " ", "2023-08-05 02:46:37", "2023-08-05 12:50:17", "2023-08-05 17:21:59", "2023-08-05 22:48:33", " ", tzTromso), 234 | schedule("2023-08-06", " ", "2023-08-06 02:53:00", "2023-08-06 12:50:11", "2023-08-06 17:20:12", "2023-08-06 22:42:12", " ", tzTromso), 235 | schedule("2023-08-07", " ", "2023-08-07 02:59:09", "2023-08-07 12:50:04", "2023-08-07 17:18:23", "2023-08-07 22:36:01", " ", tzTromso), 236 | schedule("2023-08-08", " ", "2023-08-08 03:05:06", "2023-08-08 12:49:56", "2023-08-08 17:16:32", "2023-08-08 22:30:00", " ", tzTromso), 237 | schedule("2023-08-09", " ", "2023-08-09 03:10:53", "2023-08-09 12:49:48", "2023-08-09 17:14:38", "2023-08-09 22:24:06", " ", tzTromso), 238 | schedule("2023-08-10", " ", "2023-08-10 03:16:31", "2023-08-10 12:49:39", "2023-08-10 17:12:42", "2023-08-10 22:18:19", " ", tzTromso), 239 | schedule("2023-08-11", " ", "2023-08-11 03:22:01", "2023-08-11 12:49:30", "2023-08-11 17:10:44", "2023-08-11 22:12:38", " ", tzTromso), 240 | schedule("2023-08-12", " ", "2023-08-12 03:27:24", "2023-08-12 12:49:20", "2023-08-12 17:08:44", "2023-08-12 22:07:03", " ", tzTromso), 241 | schedule("2023-08-13", " ", "2023-08-13 03:32:40", "2023-08-13 12:49:10", "2023-08-13 17:06:42", "2023-08-13 22:01:33", " ", tzTromso), 242 | schedule("2023-08-14", " ", "2023-08-14 03:37:51", "2023-08-14 12:48:59", "2023-08-14 17:04:38", "2023-08-14 21:56:07", " ", tzTromso), 243 | schedule("2023-08-15", " ", "2023-08-15 03:42:55", "2023-08-15 12:48:48", "2023-08-15 17:02:32", "2023-08-15 21:50:46", " ", tzTromso), 244 | schedule("2023-08-16", " ", "2023-08-16 03:47:54", "2023-08-16 12:48:36", "2023-08-16 17:00:23", "2023-08-16 21:45:28", " ", tzTromso), 245 | schedule("2023-08-17", " ", "2023-08-17 03:52:49", "2023-08-17 12:48:23", "2023-08-17 16:58:13", "2023-08-17 21:40:13", " ", tzTromso), 246 | schedule("2023-08-18", " ", "2023-08-18 03:57:39", "2023-08-18 12:48:10", "2023-08-18 16:56:01", "2023-08-18 21:35:02", " ", tzTromso), 247 | schedule("2023-08-19", " ", "2023-08-19 04:02:25", "2023-08-19 12:47:57", "2023-08-19 16:53:46", "2023-08-19 21:29:54", " ", tzTromso), 248 | schedule("2023-08-20", " ", "2023-08-20 04:07:07", "2023-08-20 12:47:43", "2023-08-20 16:51:30", "2023-08-20 21:24:48", " ", tzTromso), 249 | schedule("2023-08-21", " ", "2023-08-21 04:11:45", "2023-08-21 12:47:28", "2023-08-21 16:49:12", "2023-08-21 21:19:44", " ", tzTromso), 250 | schedule("2023-08-22", " ", "2023-08-22 04:16:21", "2023-08-22 12:47:13", "2023-08-22 16:46:52", "2023-08-22 21:14:43", " ", tzTromso), 251 | schedule("2023-08-23", " ", "2023-08-23 04:20:52", "2023-08-23 12:46:58", "2023-08-23 16:44:30", "2023-08-23 21:09:44", " ", tzTromso), 252 | schedule("2023-08-24", " ", "2023-08-24 04:25:21", "2023-08-24 12:46:42", "2023-08-24 16:42:06", "2023-08-24 21:04:47", " ", tzTromso), 253 | schedule("2023-08-25", " ", "2023-08-25 04:29:47", "2023-08-25 12:46:26", "2023-08-25 16:39:41", "2023-08-25 20:59:52", " ", tzTromso), 254 | schedule("2023-08-26", " ", "2023-08-26 04:34:10", "2023-08-26 12:46:09", "2023-08-26 16:37:14", "2023-08-26 20:54:59", " ", tzTromso), 255 | schedule("2023-08-27", " ", "2023-08-27 04:38:31", "2023-08-27 12:45:52", "2023-08-27 16:34:45", "2023-08-27 20:50:07", " ", tzTromso), 256 | schedule("2023-08-28", " ", "2023-08-28 04:42:49", "2023-08-28 12:45:34", "2023-08-28 16:32:14", "2023-08-28 20:45:16", " ", tzTromso), 257 | schedule("2023-08-29", " ", "2023-08-29 04:47:05", "2023-08-29 12:45:16", "2023-08-29 16:29:42", "2023-08-29 20:40:27", " ", tzTromso), 258 | schedule("2023-08-30", " ", "2023-08-30 04:51:19", "2023-08-30 12:44:58", "2023-08-30 16:27:08", "2023-08-30 20:35:39", " ", tzTromso), 259 | schedule("2023-08-31", " ", "2023-08-31 04:55:31", "2023-08-31 12:44:39", "2023-08-31 16:24:32", "2023-08-31 20:30:53", " ", tzTromso), 260 | schedule("2023-09-01", " ", "2023-09-01 04:59:41", "2023-09-01 12:44:20", "2023-09-01 16:21:55", "2023-09-01 20:26:08", " ", tzTromso), 261 | schedule("2023-09-02", " ", "2023-09-02 05:03:49", "2023-09-02 12:44:01", "2023-09-02 16:19:17", "2023-09-02 20:21:23", " ", tzTromso), 262 | schedule("2023-09-03", " ", "2023-09-03 05:07:56", "2023-09-03 12:43:41", "2023-09-03 16:16:36", "2023-09-03 20:16:40", " ", tzTromso), 263 | schedule("2023-09-04", " ", "2023-09-04 05:12:01", "2023-09-04 12:43:22", "2023-09-04 16:13:55", "2023-09-04 20:11:58", " ", tzTromso), 264 | schedule("2023-09-05", " ", "2023-09-05 05:16:05", "2023-09-05 12:43:02", "2023-09-05 16:11:12", "2023-09-05 20:07:16", " ", tzTromso), 265 | schedule("2023-09-06", " ", "2023-09-06 05:20:08", "2023-09-06 12:42:42", "2023-09-06 16:08:27", "2023-09-06 20:02:36", " ", tzTromso), 266 | schedule("2023-09-07", " ", "2023-09-07 05:24:09", "2023-09-07 12:42:21", "2023-09-07 16:05:42", "2023-09-07 19:57:56", " ", tzTromso), 267 | schedule("2023-09-08", " ", "2023-09-08 05:28:09", "2023-09-08 12:42:01", "2023-09-08 16:02:54", "2023-09-08 19:53:16", " ", tzTromso), 268 | schedule("2023-09-09", " ", "2023-09-09 05:32:08", "2023-09-09 12:41:40", "2023-09-09 16:00:06", "2023-09-09 19:48:38", " ", tzTromso), 269 | schedule("2023-09-10", " ", "2023-09-10 05:36:06", "2023-09-10 12:41:19", "2023-09-10 15:57:16", "2023-09-10 19:44:00", " ", tzTromso), 270 | schedule("2023-09-11", " ", "2023-09-11 05:40:04", "2023-09-11 12:40:58", "2023-09-11 15:54:25", "2023-09-11 19:39:23", " ", tzTromso), 271 | schedule("2023-09-12", " ", "2023-09-12 05:44:00", "2023-09-12 12:40:37", "2023-09-12 15:51:33", "2023-09-12 19:34:46", " ", tzTromso), 272 | schedule("2023-09-13", " ", "2023-09-13 05:47:56", "2023-09-13 12:40:16", "2023-09-13 15:48:39", "2023-09-13 19:30:10", " ", tzTromso), 273 | schedule("2023-09-14", " ", "2023-09-14 05:51:51", "2023-09-14 12:39:54", "2023-09-14 15:45:45", "2023-09-14 19:25:34", " ", tzTromso), 274 | schedule("2023-09-15", " ", "2023-09-15 05:55:45", "2023-09-15 12:39:33", "2023-09-15 15:42:49", "2023-09-15 19:20:59", " ", tzTromso), 275 | schedule("2023-09-16", " ", "2023-09-16 05:59:39", "2023-09-16 12:39:12", "2023-09-16 15:39:52", "2023-09-16 19:16:24", " ", tzTromso), 276 | schedule("2023-09-17", " ", "2023-09-17 06:03:32", "2023-09-17 12:38:50", "2023-09-17 15:36:54", "2023-09-17 19:11:49", " ", tzTromso), 277 | schedule("2023-09-18", "2023-09-18 01:14:22", "2023-09-18 06:07:25", "2023-09-18 12:38:29", "2023-09-18 15:33:56", "2023-09-18 19:07:15", "2023-09-18 23:42:36", tzTromso), 278 | schedule("2023-09-19", "2023-09-19 01:35:22", "2023-09-19 06:11:18", "2023-09-19 12:38:08", "2023-09-19 15:30:56", "2023-09-19 19:02:41", "2023-09-19 23:26:56", tzTromso), 279 | schedule("2023-09-20", "2023-09-20 01:50:20", "2023-09-20 06:15:11", "2023-09-20 12:37:46", "2023-09-20 15:27:55", "2023-09-20 18:58:08", "2023-09-20 23:13:56", tzTromso), 280 | schedule("2023-09-21", "2023-09-21 02:02:37", "2023-09-21 06:19:03", "2023-09-21 12:37:25", "2023-09-21 15:24:53", "2023-09-21 18:53:35", "2023-09-21 23:02:33", tzTromso), 281 | schedule("2023-09-22", "2023-09-22 02:13:18", "2023-09-22 06:22:55", "2023-09-22 12:37:04", "2023-09-22 15:21:50", "2023-09-22 18:49:02", "2023-09-22 22:52:17", tzTromso), 282 | schedule("2023-09-23", "2023-09-23 02:22:53", "2023-09-23 06:26:47", "2023-09-23 12:36:43", "2023-09-23 15:18:47", "2023-09-23 18:44:29", "2023-09-23 22:42:49", tzTromso), 283 | schedule("2023-09-24", "2023-09-24 02:31:38", "2023-09-24 06:30:39", "2023-09-24 12:36:22", "2023-09-24 15:15:43", "2023-09-24 18:39:56", "2023-09-24 22:34:00", tzTromso), 284 | schedule("2023-09-25", "2023-09-25 02:39:46", "2023-09-25 06:34:31", "2023-09-25 12:36:01", "2023-09-25 15:12:37", "2023-09-25 18:35:24", "2023-09-25 22:25:42", tzTromso), 285 | schedule("2023-09-26", "2023-09-26 02:47:23", "2023-09-26 06:38:23", "2023-09-26 12:35:40", "2023-09-26 15:09:32", "2023-09-26 18:30:52", "2023-09-26 22:17:49", tzTromso), 286 | schedule("2023-09-27", "2023-09-27 02:54:34", "2023-09-27 06:42:16", "2023-09-27 12:35:19", "2023-09-27 15:06:25", "2023-09-27 18:26:20", "2023-09-27 22:10:19", tzTromso), 287 | schedule("2023-09-28", "2023-09-28 03:01:24", "2023-09-28 06:46:08", "2023-09-28 12:34:59", "2023-09-28 15:03:18", "2023-09-28 18:21:48", "2023-09-28 22:03:07", tzTromso), 288 | schedule("2023-09-29", "2023-09-29 03:07:56", "2023-09-29 06:50:01", "2023-09-29 12:34:39", "2023-09-29 15:00:10", "2023-09-29 18:17:16", "2023-09-29 21:56:11", tzTromso), 289 | schedule("2023-09-30", "2023-09-30 03:14:12", "2023-09-30 06:53:55", "2023-09-30 12:34:19", "2023-09-30 14:57:01", "2023-09-30 18:12:44", "2023-09-30 21:49:30", tzTromso), 290 | schedule("2023-10-01", "2023-10-01 03:20:14", "2023-10-01 06:57:49", "2023-10-01 12:33:59", "2023-10-01 14:53:52", "2023-10-01 18:08:12", "2023-10-01 21:43:02", tzTromso), 291 | schedule("2023-10-02", "2023-10-02 03:26:03", "2023-10-02 07:01:43", "2023-10-02 12:33:40", "2023-10-02 14:50:43", "2023-10-02 18:03:40", "2023-10-02 21:36:45", tzTromso), 292 | schedule("2023-10-03", "2023-10-03 03:31:42", "2023-10-03 07:05:38", "2023-10-03 12:33:21", "2023-10-03 14:47:33", "2023-10-03 17:59:08", "2023-10-03 21:30:40", tzTromso), 293 | schedule("2023-10-04", "2023-10-04 03:37:10", "2023-10-04 07:09:34", "2023-10-04 12:33:02", "2023-10-04 14:44:22", "2023-10-04 17:54:36", "2023-10-04 21:24:44", tzTromso), 294 | schedule("2023-10-05", "2023-10-05 03:42:29", "2023-10-05 07:13:31", "2023-10-05 12:32:44", "2023-10-05 14:41:11", "2023-10-05 17:50:03", "2023-10-05 21:18:57", tzTromso), 295 | schedule("2023-10-06", "2023-10-06 03:47:40", "2023-10-06 07:17:29", "2023-10-06 12:32:26", "2023-10-06 14:38:00", "2023-10-06 17:45:31", "2023-10-06 21:13:18", tzTromso), 296 | schedule("2023-10-07", "2023-10-07 03:52:44", "2023-10-07 07:21:28", "2023-10-07 12:32:08", "2023-10-07 14:34:49", "2023-10-07 17:40:59", "2023-10-07 21:07:47", tzTromso), 297 | schedule("2023-10-08", "2023-10-08 03:57:40", "2023-10-08 07:25:27", "2023-10-08 12:31:51", "2023-10-08 14:31:37", "2023-10-08 17:36:26", "2023-10-08 21:02:23", tzTromso), 298 | schedule("2023-10-09", "2023-10-09 04:02:30", "2023-10-09 07:29:28", "2023-10-09 12:31:34", "2023-10-09 14:28:25", "2023-10-09 17:31:53", "2023-10-09 20:57:07", tzTromso), 299 | schedule("2023-10-10", "2023-10-10 04:07:14", "2023-10-10 07:33:30", "2023-10-10 12:31:18", "2023-10-10 14:25:12", "2023-10-10 17:27:20", "2023-10-10 20:51:56", tzTromso), 300 | schedule("2023-10-11", "2023-10-11 04:11:53", "2023-10-11 07:37:33", "2023-10-11 12:31:02", "2023-10-11 14:22:00", "2023-10-11 17:22:47", "2023-10-11 20:46:52", tzTromso), 301 | schedule("2023-10-12", "2023-10-12 04:16:26", "2023-10-12 07:41:37", "2023-10-12 12:30:47", "2023-10-12 14:18:47", "2023-10-12 17:18:13", "2023-10-12 20:41:54", tzTromso), 302 | schedule("2023-10-13", "2023-10-13 04:20:55", "2023-10-13 07:45:43", "2023-10-13 12:30:32", "2023-10-13 14:15:34", "2023-10-13 17:13:39", "2023-10-13 20:37:01", tzTromso), 303 | schedule("2023-10-14", "2023-10-14 04:25:19", "2023-10-14 07:49:50", "2023-10-14 12:30:18", "2023-10-14 14:12:22", "2023-10-14 17:09:04", "2023-10-14 20:32:14", tzTromso), 304 | schedule("2023-10-15", "2023-10-15 04:29:38", "2023-10-15 07:53:59", "2023-10-15 12:30:04", "2023-10-15 14:09:09", "2023-10-15 17:04:29", "2023-10-15 20:27:32", tzTromso), 305 | schedule("2023-10-16", "2023-10-16 04:33:54", "2023-10-16 07:58:09", "2023-10-16 12:29:51", "2023-10-16 14:05:56", "2023-10-16 16:59:54", "2023-10-16 20:22:55", tzTromso), 306 | schedule("2023-10-17", "2023-10-17 04:38:05", "2023-10-17 08:02:21", "2023-10-17 12:29:39", "2023-10-17 14:02:43", "2023-10-17 16:55:18", "2023-10-17 20:18:22", tzTromso), 307 | schedule("2023-10-18", "2023-10-18 04:42:13", "2023-10-18 08:06:35", "2023-10-18 12:29:27", "2023-10-18 13:59:31", "2023-10-18 16:50:42", "2023-10-18 20:13:55", tzTromso), 308 | schedule("2023-10-19", "2023-10-19 04:46:18", "2023-10-19 08:10:50", "2023-10-19 12:29:15", "2023-10-19 13:56:18", "2023-10-19 16:46:05", "2023-10-19 20:09:32", tzTromso), 309 | schedule("2023-10-20", "2023-10-20 04:50:19", "2023-10-20 08:15:07", "2023-10-20 12:29:05", "2023-10-20 13:53:06", "2023-10-20 16:41:28", "2023-10-20 20:05:13", tzTromso), 310 | schedule("2023-10-21", "2023-10-21 04:54:16", "2023-10-21 08:19:27", "2023-10-21 12:28:54", "2023-10-21 13:49:54", "2023-10-21 16:36:49", "2023-10-21 20:00:59", tzTromso), 311 | schedule("2023-10-22", "2023-10-22 04:58:11", "2023-10-22 08:23:48", "2023-10-22 12:28:45", "2023-10-22 13:46:41", "2023-10-22 16:32:10", "2023-10-22 19:56:49", tzTromso), 312 | schedule("2023-10-23", "2023-10-23 05:02:03", "2023-10-23 08:28:11", "2023-10-23 12:28:36", "2023-10-23 13:43:30", "2023-10-23 16:27:31", "2023-10-23 19:52:43", tzTromso), 313 | schedule("2023-10-24", "2023-10-24 05:05:52", "2023-10-24 08:32:36", "2023-10-24 12:28:28", "2023-10-24 13:40:18", "2023-10-24 16:22:50", "2023-10-24 19:48:41", tzTromso), 314 | schedule("2023-10-25", "2023-10-25 05:09:38", "2023-10-25 08:37:04", "2023-10-25 12:28:20", "2023-10-25 13:37:06", "2023-10-25 16:18:09", "2023-10-25 19:44:43", tzTromso), 315 | schedule("2023-10-26", "2023-10-26 05:13:21", "2023-10-26 08:41:34", "2023-10-26 12:28:14", "2023-10-26 13:33:55", "2023-10-26 16:13:26", "2023-10-26 19:40:49", tzTromso), 316 | schedule("2023-10-27", "2023-10-27 05:17:02", "2023-10-27 08:46:07", "2023-10-27 12:28:08", "2023-10-27 13:30:43", "2023-10-27 16:08:42", "2023-10-27 19:36:59", tzTromso), 317 | schedule("2023-10-28", "2023-10-28 05:20:41", "2023-10-28 08:50:42", "2023-10-28 12:28:02", "2023-10-28 13:27:32", "2023-10-28 16:03:58", "2023-10-28 19:33:13", tzTromso), 318 | schedule("2023-10-29", "2023-10-29 04:24:19", "2023-10-29 07:55:26", "2023-10-29 11:28:02", "2023-10-29 12:24:08", "2023-10-29 14:59:10", "2023-10-29 18:29:31", tzTromso), 319 | schedule("2023-10-30", "2023-10-30 04:27:52", "2023-10-30 08:00:04", "2023-10-30 11:27:55", "2023-10-30 12:21:38", "2023-10-30 14:54:24", "2023-10-30 18:25:53", tzTromso), 320 | schedule("2023-10-31", "2023-10-31 04:31:21", "2023-10-31 08:04:46", "2023-10-31 11:27:51", "2023-10-31 12:18:32", "2023-10-31 14:49:35", "2023-10-31 18:22:18", tzTromso), 321 | schedule("2023-11-01", "2023-11-01 04:34:50", "2023-11-01 08:09:33", "2023-11-01 11:27:49", "2023-11-01 12:15:21", "2023-11-01 14:44:44", "2023-11-01 18:18:48", tzTromso), 322 | schedule("2023-11-02", "2023-11-02 04:38:17", "2023-11-02 08:14:24", "2023-11-02 11:27:47", "2023-11-02 12:12:10", "2023-11-02 14:39:52", "2023-11-02 18:15:21", tzTromso), 323 | schedule("2023-11-03", "2023-11-03 04:41:42", "2023-11-03 08:19:18", "2023-11-03 11:27:47", "2023-11-03 12:08:57", "2023-11-03 14:34:58", "2023-11-03 18:11:58", tzTromso), 324 | schedule("2023-11-04", "2023-11-04 04:45:04", "2023-11-04 08:24:17", "2023-11-04 11:27:47", "2023-11-04 12:05:43", "2023-11-04 14:30:01", "2023-11-04 18:08:38", tzTromso), 325 | schedule("2023-11-05", "2023-11-05 04:48:24", "2023-11-05 08:29:19", "2023-11-05 11:27:48", "2023-11-05 12:02:26", "2023-11-05 14:25:02", "2023-11-05 18:05:23", tzTromso), 326 | schedule("2023-11-06", "2023-11-06 04:51:42", "2023-11-06 08:34:25", "2023-11-06 11:27:50", "2023-11-06 11:59:06", "2023-11-06 14:20:01", "2023-11-06 18:02:11", tzTromso), 327 | schedule("2023-11-07", "2023-11-07 04:54:58", "2023-11-07 08:39:36", "2023-11-07 11:27:53", "2023-11-07 11:55:39", "2023-11-07 14:14:57", "2023-11-07 17:59:04", tzTromso), 328 | schedule("2023-11-08", "2023-11-08 04:58:11", "2023-11-08 08:44:52", "2023-11-08 11:27:56", "2023-11-08 11:52:04", "2023-11-08 14:09:50", "2023-11-08 17:56:00", tzTromso), 329 | schedule("2023-11-09", "2023-11-09 05:01:23", "2023-11-09 08:50:13", "2023-11-09 11:28:01", "2023-11-09 11:48:15", "2023-11-09 14:04:39", "2023-11-09 17:53:00", tzTromso), 330 | schedule("2023-11-10", "2023-11-10 05:04:32", "2023-11-10 08:55:39", "2023-11-10 11:28:06", "2023-11-10 11:44:01", "2023-11-10 13:59:24", "2023-11-10 17:50:04", tzTromso), 331 | schedule("2023-11-11", "2023-11-11 05:07:38", "2023-11-11 09:01:12", "2023-11-11 11:28:12", "2023-11-11 11:38:51", "2023-11-11 13:54:06", "2023-11-11 17:47:12", tzTromso), 332 | schedule("2023-11-12", "2023-11-12 05:10:43", "2023-11-12 09:06:51", "2023-11-12 11:28:19", "2023-11-12 11:30:03", "2023-11-12 13:48:42", "2023-11-12 17:44:24", tzTromso), 333 | schedule("2023-11-13", "2023-11-13 05:13:45", "2023-11-13 09:12:37", "2023-11-13 11:28:27", "2023-11-13 11:37:32", "2023-11-13 13:43:13", "2023-11-13 17:41:40", tzTromso), 334 | schedule("2023-11-14", "2023-11-14 05:16:45", "2023-11-14 09:18:31", "2023-11-14 11:28:36", "2023-11-14 11:33:51", "2023-11-14 13:37:38", "2023-11-14 17:39:00", tzTromso), 335 | schedule("2023-11-15", "2023-11-15 05:19:42", "2023-11-15 09:24:33", "2023-11-15 11:28:46", "2023-11-15 11:29:55", "2023-11-15 13:31:56", "2023-11-15 17:36:25", tzTromso), 336 | schedule("2023-11-16", "2023-11-16 05:22:37", "2023-11-16 09:30:46", "2023-11-16 11:28:56", "2023-11-16 11:45:54", "2023-11-16 13:26:06", "2023-11-16 17:33:53", tzTromso), 337 | schedule("2023-11-17", "2023-11-17 05:25:29", "2023-11-17 09:37:09", "2023-11-17 11:29:07", "2023-11-17 11:43:45", "2023-11-17 13:20:07", "2023-11-17 17:31:26", tzTromso), 338 | schedule("2023-11-18", "2023-11-18 05:28:19", "2023-11-18 09:43:46", "2023-11-18 11:29:19", "2023-11-18 11:41:41", "2023-11-18 13:13:56", "2023-11-18 17:29:03", tzTromso), 339 | schedule("2023-11-19", "2023-11-19 05:31:05", "2023-11-19 09:50:37", "2023-11-19 11:29:32", "2023-11-19 11:39:41", "2023-11-19 13:07:32", "2023-11-19 17:26:44", tzTromso), 340 | schedule("2023-11-20", "2023-11-20 05:33:49", "2023-11-20 09:57:46", "2023-11-20 11:29:46", "2023-11-20 11:37:49", "2023-11-20 13:00:52", "2023-11-20 17:24:30", tzTromso), 341 | schedule("2023-11-21", "2023-11-21 05:36:31", "2023-11-21 10:05:17", "2023-11-21 11:30:00", "2023-11-21 11:36:05", "2023-11-21 12:53:51", "2023-11-21 17:22:20", tzTromso), 342 | schedule("2023-11-22", "2023-11-22 05:39:09", "2023-11-22 10:13:16", "2023-11-22 11:30:16", "2023-11-22 11:34:40", "2023-11-22 12:46:24", "2023-11-22 17:20:14", tzTromso), 343 | schedule("2023-11-23", "2023-11-23 05:41:44", "2023-11-23 10:21:53", "2023-11-23 11:30:32", "2023-11-23 11:33:53", "2023-11-23 12:38:22", "2023-11-23 17:18:13", tzTromso), 344 | schedule("2023-11-24", "2023-11-24 05:44:17", "2023-11-24 10:31:21", "2023-11-24 11:30:49", "2023-11-24 11:34:16", "2023-11-24 12:29:29", "2023-11-24 17:16:17", tzTromso), 345 | schedule("2023-11-25", "2023-11-25 05:46:46", "2023-11-25 10:42:09", "2023-11-25 11:31:06", "2023-11-25 11:35:41", "2023-11-25 12:19:17", "2023-11-25 17:14:25", tzTromso), 346 | schedule("2023-11-26", "2023-11-26 05:49:12", "2023-11-26 10:55:28", "2023-11-26 11:31:25", "2023-11-26 11:37:32", "2023-11-26 12:06:36", "2023-11-26 17:12:38", tzTromso), 347 | schedule("2023-11-27", "2023-11-27 05:51:34", "2023-11-27 11:16:54", "2023-11-27 11:31:44", "2023-11-27 11:39:31", "2023-11-27 11:45:50", "2023-11-27 17:10:56", tzTromso), 348 | schedule("2023-11-28", "2023-11-28 05:53:54", " ", "2023-11-28 11:32:03", "2023-11-28 11:41:34", " ", "2023-11-28 17:09:19", tzTromso), 349 | schedule("2023-11-29", "2023-11-29 05:56:09", " ", "2023-11-29 11:32:24", "2023-11-29 11:43:36", " ", "2023-11-29 17:07:46", tzTromso), 350 | schedule("2023-11-30", "2023-11-30 05:58:22", " ", "2023-11-30 11:32:45", "2023-11-30 11:45:37", " ", "2023-11-30 17:06:18", tzTromso), 351 | schedule("2023-12-01", "2023-12-01 06:00:30", " ", "2023-12-01 11:33:07", "2023-12-01 11:47:36", " ", "2023-12-01 17:04:56", tzTromso), 352 | schedule("2023-12-02", "2023-12-02 06:02:35", " ", "2023-12-02 11:33:29", "2023-12-02 11:36:21", " ", "2023-12-02 17:03:38", tzTromso), 353 | schedule("2023-12-03", "2023-12-03 06:04:37", " ", "2023-12-03 11:33:53", "2023-12-03 11:39:54", " ", "2023-12-03 17:02:26", tzTromso), 354 | schedule("2023-12-04", "2023-12-04 06:06:34", " ", "2023-12-04 11:34:16", "2023-12-04 11:37:35", " ", "2023-12-04 17:01:18", tzTromso), 355 | schedule("2023-12-05", "2023-12-05 06:08:27", " ", "2023-12-05 11:34:41", "2023-12-05 11:42:06", " ", "2023-12-05 17:00:16", tzTromso), 356 | schedule("2023-12-06", "2023-12-06 06:10:16", " ", "2023-12-06 11:35:06", "2023-12-06 11:46:25", " ", "2023-12-06 16:59:19", tzTromso), 357 | schedule("2023-12-07", "2023-12-07 06:12:01", " ", "2023-12-07 11:35:31", "2023-12-07 11:49:45", " ", "2023-12-07 16:58:27", tzTromso), 358 | schedule("2023-12-08", "2023-12-08 06:13:42", " ", "2023-12-08 11:35:57", "2023-12-08 11:52:36", " ", "2023-12-08 16:57:41", tzTromso), 359 | schedule("2023-12-09", "2023-12-09 06:15:18", " ", "2023-12-09 11:36:24", "2023-12-09 11:55:08", " ", "2023-12-09 16:57:00", tzTromso), 360 | schedule("2023-12-10", "2023-12-10 06:16:50", " ", "2023-12-10 11:36:51", "2023-12-10 11:57:26", " ", "2023-12-10 16:56:25", tzTromso), 361 | schedule("2023-12-11", "2023-12-11 06:18:17", " ", "2023-12-11 11:37:18", "2023-12-11 11:59:34", " ", "2023-12-11 16:55:54", tzTromso), 362 | schedule("2023-12-12", "2023-12-12 06:19:40", " ", "2023-12-12 11:37:46", "2023-12-12 12:01:32", " ", "2023-12-12 16:55:30", tzTromso), 363 | schedule("2023-12-13", "2023-12-13 06:20:58", " ", "2023-12-13 11:38:14", "2023-12-13 12:03:22", " ", "2023-12-13 16:55:11", tzTromso), 364 | schedule("2023-12-14", "2023-12-14 06:22:11", " ", "2023-12-14 11:38:43", "2023-12-14 12:05:04", " ", "2023-12-14 16:54:57", tzTromso), 365 | schedule("2023-12-15", "2023-12-15 06:23:19", " ", "2023-12-15 11:39:12", "2023-12-15 12:06:40", " ", "2023-12-15 16:54:49", tzTromso), 366 | schedule("2023-12-16", "2023-12-16 06:24:22", " ", "2023-12-16 11:39:41", "2023-12-16 12:08:09", " ", "2023-12-16 16:54:46", tzTromso), 367 | schedule("2023-12-17", "2023-12-17 06:25:20", " ", "2023-12-17 11:40:10", "2023-12-17 12:09:32", " ", "2023-12-17 16:54:49", tzTromso), 368 | schedule("2023-12-18", "2023-12-18 06:26:13", " ", "2023-12-18 11:40:39", "2023-12-18 12:10:49", " ", "2023-12-18 16:54:57", tzTromso), 369 | schedule("2023-12-19", "2023-12-19 06:27:01", " ", "2023-12-19 11:41:09", "2023-12-19 12:12:00", " ", "2023-12-19 16:55:10", tzTromso), 370 | schedule("2023-12-20", "2023-12-20 06:27:44", " ", "2023-12-20 11:41:39", "2023-12-20 12:13:05", " ", "2023-12-20 16:55:30", tzTromso), 371 | schedule("2023-12-21", "2023-12-21 06:28:21", " ", "2023-12-21 11:42:08", "2023-12-21 12:14:06", " ", "2023-12-21 16:55:54", tzTromso), 372 | schedule("2023-12-22", "2023-12-22 06:28:53", " ", "2023-12-22 11:42:38", "2023-12-22 12:15:00", " ", "2023-12-22 16:56:24", tzTromso), 373 | schedule("2023-12-23", "2023-12-23 06:29:20", " ", "2023-12-23 11:43:08", "2023-12-23 12:15:50", " ", "2023-12-23 16:56:59", tzTromso), 374 | schedule("2023-12-24", "2023-12-24 06:29:41", " ", "2023-12-24 11:43:38", "2023-12-24 12:16:34", " ", "2023-12-24 16:57:40", tzTromso), 375 | schedule("2023-12-25", "2023-12-25 06:29:57", " ", "2023-12-25 11:44:07", "2023-12-25 12:17:14", " ", "2023-12-25 16:58:26", tzTromso), 376 | schedule("2023-12-26", "2023-12-26 06:30:07", " ", "2023-12-26 11:44:37", "2023-12-26 12:17:48", " ", "2023-12-26 16:59:17", tzTromso), 377 | schedule("2023-12-27", "2023-12-27 06:30:12", " ", "2023-12-27 11:45:07", "2023-12-27 12:18:18", " ", "2023-12-27 17:00:13", tzTromso), 378 | schedule("2023-12-28", "2023-12-28 06:30:12", " ", "2023-12-28 11:45:36", "2023-12-28 12:18:43", " ", "2023-12-28 17:01:15", tzTromso), 379 | schedule("2023-12-29", "2023-12-29 06:30:06", " ", "2023-12-29 11:46:05", "2023-12-29 12:19:04", " ", "2023-12-29 17:02:21", tzTromso), 380 | schedule("2023-12-30", "2023-12-30 06:29:55", " ", "2023-12-30 11:46:34", "2023-12-30 12:19:21", " ", "2023-12-30 17:03:33", tzTromso), 381 | schedule("2023-12-31", "2023-12-31 06:29:38", " ", "2023-12-31 11:47:03", "2023-12-31 12:19:33", " ", "2023-12-31 17:04:49", tzTromso), 382 | }, 383 | } 384 | -------------------------------------------------------------------------------- /internal/datatest/london.go: -------------------------------------------------------------------------------- 1 | package datatest 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hablullah/go-prayer" 7 | ) 8 | 9 | var tzLondon, _ = time.LoadLocation("Europe/London") 10 | 11 | var London = TestData{ 12 | Name: "London", 13 | Latitude: 51.507222, 14 | Longitude: -0.127500, 15 | Timezone: tzLondon, 16 | Schedules: []prayer.Schedule{ 17 | schedule("2023-01-01", "2023-01-01 06:13:22", "2023-01-01 08:06:11", "2023-01-01 12:03:56", "2023-01-01 13:45:45", "2023-01-01 16:01:54", "2023-01-01 17:54:43", tzLondon), 18 | schedule("2023-01-02", "2023-01-02 06:13:24", "2023-01-02 08:06:04", "2023-01-02 12:04:25", "2023-01-02 13:46:43", "2023-01-02 16:02:57", "2023-01-02 17:55:38", tzLondon), 19 | schedule("2023-01-03", "2023-01-03 06:13:22", "2023-01-03 08:05:54", "2023-01-03 12:04:52", "2023-01-03 13:47:43", "2023-01-03 16:04:04", "2023-01-03 17:56:36", tzLondon), 20 | schedule("2023-01-04", "2023-01-04 06:13:18", "2023-01-04 08:05:40", "2023-01-04 12:05:20", "2023-01-04 13:48:45", "2023-01-04 16:05:13", "2023-01-04 17:57:35", tzLondon), 21 | schedule("2023-01-05", "2023-01-05 06:13:11", "2023-01-05 08:05:23", "2023-01-05 12:05:47", "2023-01-05 13:49:49", "2023-01-05 16:06:25", "2023-01-05 17:58:37", tzLondon), 22 | schedule("2023-01-06", "2023-01-06 06:13:01", "2023-01-06 08:05:03", "2023-01-06 12:06:13", "2023-01-06 13:50:54", "2023-01-06 16:07:39", "2023-01-06 17:59:40", tzLondon), 23 | schedule("2023-01-07", "2023-01-07 06:12:50", "2023-01-07 08:04:40", "2023-01-07 12:06:39", "2023-01-07 13:52:01", "2023-01-07 16:08:55", "2023-01-07 18:00:45", tzLondon), 24 | schedule("2023-01-08", "2023-01-08 06:12:35", "2023-01-08 08:04:13", "2023-01-08 12:07:05", "2023-01-08 13:53:10", "2023-01-08 16:10:14", "2023-01-08 18:01:52", tzLondon), 25 | schedule("2023-01-09", "2023-01-09 06:12:18", "2023-01-09 08:03:44", "2023-01-09 12:07:30", "2023-01-09 13:54:20", "2023-01-09 16:11:35", "2023-01-09 18:03:01", tzLondon), 26 | schedule("2023-01-10", "2023-01-10 06:11:59", "2023-01-10 08:03:11", "2023-01-10 12:07:54", "2023-01-10 13:55:32", "2023-01-10 16:12:58", "2023-01-10 18:04:11", tzLondon), 27 | schedule("2023-01-11", "2023-01-11 06:11:35", "2023-01-11 08:02:34", "2023-01-11 12:08:18", "2023-01-11 13:56:45", "2023-01-11 16:14:23", "2023-01-11 18:05:22", tzLondon), 28 | schedule("2023-01-12", "2023-01-12 06:11:11", "2023-01-12 08:01:55", "2023-01-12 12:08:41", "2023-01-12 13:57:59", "2023-01-12 16:15:50", "2023-01-12 18:06:35", tzLondon), 29 | schedule("2023-01-13", "2023-01-13 06:10:42", "2023-01-13 08:01:13", "2023-01-13 12:09:04", "2023-01-13 13:59:15", "2023-01-13 16:17:18", "2023-01-13 18:07:50", tzLondon), 30 | schedule("2023-01-14", "2023-01-14 06:10:12", "2023-01-14 08:00:28", "2023-01-14 12:09:26", "2023-01-14 14:00:32", "2023-01-14 16:18:49", "2023-01-14 18:09:06", tzLondon), 31 | schedule("2023-01-15", "2023-01-15 06:09:39", "2023-01-15 07:59:40", "2023-01-15 12:09:48", "2023-01-15 14:01:50", "2023-01-15 16:20:21", "2023-01-15 18:10:23", tzLondon), 32 | schedule("2023-01-16", "2023-01-16 06:09:03", "2023-01-16 07:58:48", "2023-01-16 12:10:09", "2023-01-16 14:03:09", "2023-01-16 16:21:55", "2023-01-16 18:11:42", tzLondon), 33 | schedule("2023-01-17", "2023-01-17 06:08:25", "2023-01-17 07:57:54", "2023-01-17 12:10:29", "2023-01-17 14:04:29", "2023-01-17 16:23:30", "2023-01-17 18:13:00", tzLondon), 34 | schedule("2023-01-18", "2023-01-18 06:07:45", "2023-01-18 07:56:58", "2023-01-18 12:10:48", "2023-01-18 14:05:51", "2023-01-18 16:25:07", "2023-01-18 18:14:22", tzLondon), 35 | schedule("2023-01-19", "2023-01-19 06:07:01", "2023-01-19 07:55:58", "2023-01-19 12:11:07", "2023-01-19 14:07:13", "2023-01-19 16:26:45", "2023-01-19 18:15:43", tzLondon), 36 | schedule("2023-01-20", "2023-01-20 06:06:15", "2023-01-20 07:54:56", "2023-01-20 12:11:25", "2023-01-20 14:08:35", "2023-01-20 16:28:24", "2023-01-20 18:17:06", tzLondon), 37 | schedule("2023-01-21", "2023-01-21 06:05:27", "2023-01-21 07:53:51", "2023-01-21 12:11:43", "2023-01-21 14:09:59", "2023-01-21 16:30:05", "2023-01-21 18:18:31", tzLondon), 38 | schedule("2023-01-22", "2023-01-22 06:04:36", "2023-01-22 07:52:43", "2023-01-22 12:11:59", "2023-01-22 14:11:23", "2023-01-22 16:31:46", "2023-01-22 18:19:55", tzLondon), 39 | schedule("2023-01-23", "2023-01-23 06:03:43", "2023-01-23 07:51:33", "2023-01-23 12:12:15", "2023-01-23 14:12:48", "2023-01-23 16:33:29", "2023-01-23 18:21:21", tzLondon), 40 | schedule("2023-01-24", "2023-01-24 06:02:48", "2023-01-24 07:50:21", "2023-01-24 12:12:30", "2023-01-24 14:14:13", "2023-01-24 16:35:12", "2023-01-24 18:22:47", tzLondon), 41 | schedule("2023-01-25", "2023-01-25 06:01:49", "2023-01-25 07:49:06", "2023-01-25 12:12:44", "2023-01-25 14:15:39", "2023-01-25 16:36:57", "2023-01-25 18:24:15", tzLondon), 42 | schedule("2023-01-26", "2023-01-26 06:00:49", "2023-01-26 07:47:48", "2023-01-26 12:12:58", "2023-01-26 14:17:05", "2023-01-26 16:38:42", "2023-01-26 18:25:43", tzLondon), 43 | schedule("2023-01-27", "2023-01-27 05:59:46", "2023-01-27 07:46:28", "2023-01-27 12:13:10", "2023-01-27 14:18:31", "2023-01-27 16:40:28", "2023-01-27 18:27:12", tzLondon), 44 | schedule("2023-01-28", "2023-01-28 05:58:41", "2023-01-28 07:45:06", "2023-01-28 12:13:22", "2023-01-28 14:19:58", "2023-01-28 16:42:14", "2023-01-28 18:28:41", tzLondon), 45 | schedule("2023-01-29", "2023-01-29 05:57:35", "2023-01-29 07:43:42", "2023-01-29 12:13:33", "2023-01-29 14:21:25", "2023-01-29 16:44:01", "2023-01-29 18:30:11", tzLondon), 46 | schedule("2023-01-30", "2023-01-30 05:56:25", "2023-01-30 07:42:15", "2023-01-30 12:13:43", "2023-01-30 14:22:52", "2023-01-30 16:45:49", "2023-01-30 18:31:42", tzLondon), 47 | schedule("2023-01-31", "2023-01-31 05:55:14", "2023-01-31 07:40:46", "2023-01-31 12:13:53", "2023-01-31 14:24:20", "2023-01-31 16:47:37", "2023-01-31 18:33:13", tzLondon), 48 | schedule("2023-02-01", "2023-02-01 05:54:00", "2023-02-01 07:39:16", "2023-02-01 12:14:01", "2023-02-01 14:25:47", "2023-02-01 16:49:25", "2023-02-01 18:34:45", tzLondon), 49 | schedule("2023-02-02", "2023-02-02 05:52:44", "2023-02-02 07:37:43", "2023-02-02 12:14:09", "2023-02-02 14:27:14", "2023-02-02 16:51:14", "2023-02-02 18:36:17", tzLondon), 50 | schedule("2023-02-03", "2023-02-03 05:51:26", "2023-02-03 07:36:08", "2023-02-03 12:14:15", "2023-02-03 14:28:41", "2023-02-03 16:53:03", "2023-02-03 18:37:50", tzLondon), 51 | schedule("2023-02-04", "2023-02-04 05:50:06", "2023-02-04 07:34:31", "2023-02-04 12:14:21", "2023-02-04 14:30:09", "2023-02-04 16:54:52", "2023-02-04 18:39:21", tzLondon), 52 | schedule("2023-02-05", "2023-02-05 05:48:44", "2023-02-05 07:32:53", "2023-02-05 12:14:27", "2023-02-05 14:31:36", "2023-02-05 16:56:41", "2023-02-05 18:40:55", tzLondon), 53 | schedule("2023-02-06", "2023-02-06 05:47:20", "2023-02-06 07:31:13", "2023-02-06 12:14:31", "2023-02-06 14:33:03", "2023-02-06 16:58:31", "2023-02-06 18:42:29", tzLondon), 54 | schedule("2023-02-07", "2023-02-07 05:45:54", "2023-02-07 07:29:31", "2023-02-07 12:14:35", "2023-02-07 14:34:29", "2023-02-07 17:00:21", "2023-02-07 18:44:04", tzLondon), 55 | schedule("2023-02-08", "2023-02-08 05:44:26", "2023-02-08 07:27:47", "2023-02-08 12:14:37", "2023-02-08 14:35:56", "2023-02-08 17:02:10", "2023-02-08 18:45:38", tzLondon), 56 | schedule("2023-02-09", "2023-02-09 05:42:56", "2023-02-09 07:26:02", "2023-02-09 12:14:39", "2023-02-09 14:37:22", "2023-02-09 17:04:00", "2023-02-09 18:47:12", tzLondon), 57 | schedule("2023-02-10", "2023-02-10 05:41:23", "2023-02-10 07:24:15", "2023-02-10 12:14:40", "2023-02-10 14:38:48", "2023-02-10 17:05:50", "2023-02-10 18:48:47", tzLondon), 58 | schedule("2023-02-11", "2023-02-11 05:39:50", "2023-02-11 07:22:26", "2023-02-11 12:14:41", "2023-02-11 14:40:14", "2023-02-11 17:07:40", "2023-02-11 18:50:23", tzLondon), 59 | schedule("2023-02-12", "2023-02-12 05:38:14", "2023-02-12 07:20:36", "2023-02-12 12:14:41", "2023-02-12 14:41:39", "2023-02-12 17:09:30", "2023-02-12 18:51:58", tzLondon), 60 | schedule("2023-02-13", "2023-02-13 05:36:37", "2023-02-13 07:18:45", "2023-02-13 12:14:40", "2023-02-13 14:43:04", "2023-02-13 17:11:20", "2023-02-13 18:53:34", tzLondon), 61 | schedule("2023-02-14", "2023-02-14 05:34:59", "2023-02-14 07:16:52", "2023-02-14 12:14:38", "2023-02-14 14:44:29", "2023-02-14 17:13:10", "2023-02-14 18:55:10", tzLondon), 62 | schedule("2023-02-15", "2023-02-15 05:33:18", "2023-02-15 07:14:58", "2023-02-15 12:14:35", "2023-02-15 14:45:53", "2023-02-15 17:14:59", "2023-02-15 18:56:46", tzLondon), 63 | schedule("2023-02-16", "2023-02-16 05:31:37", "2023-02-16 07:13:03", "2023-02-16 12:14:32", "2023-02-16 14:47:17", "2023-02-16 17:16:49", "2023-02-16 18:58:24", tzLondon), 64 | schedule("2023-02-17", "2023-02-17 05:29:51", "2023-02-17 07:11:06", "2023-02-17 12:14:28", "2023-02-17 14:48:40", "2023-02-17 17:18:38", "2023-02-17 19:00:00", tzLondon), 65 | schedule("2023-02-18", "2023-02-18 05:28:07", "2023-02-18 07:09:08", "2023-02-18 12:14:24", "2023-02-18 14:50:03", "2023-02-18 17:20:28", "2023-02-18 19:01:38", tzLondon), 66 | schedule("2023-02-19", "2023-02-19 05:26:19", "2023-02-19 07:07:09", "2023-02-19 12:14:19", "2023-02-19 14:51:25", "2023-02-19 17:22:17", "2023-02-19 19:03:14", tzLondon), 67 | schedule("2023-02-20", "2023-02-20 05:24:31", "2023-02-20 07:05:09", "2023-02-20 12:14:13", "2023-02-20 14:52:46", "2023-02-20 17:24:06", "2023-02-20 19:04:52", tzLondon), 68 | schedule("2023-02-21", "2023-02-21 05:22:41", "2023-02-21 07:03:08", "2023-02-21 12:14:06", "2023-02-21 14:54:07", "2023-02-21 17:25:54", "2023-02-21 19:06:30", tzLondon), 69 | schedule("2023-02-22", "2023-02-22 05:20:50", "2023-02-22 07:01:06", "2023-02-22 12:13:59", "2023-02-22 14:55:28", "2023-02-22 17:27:42", "2023-02-22 19:08:08", tzLondon), 70 | schedule("2023-02-23", "2023-02-23 05:18:57", "2023-02-23 06:59:03", "2023-02-23 12:13:51", "2023-02-23 14:56:47", "2023-02-23 17:29:31", "2023-02-23 19:09:47", tzLondon), 71 | schedule("2023-02-24", "2023-02-24 05:17:02", "2023-02-24 06:56:58", "2023-02-24 12:13:43", "2023-02-24 14:58:07", "2023-02-24 17:31:18", "2023-02-24 19:11:23", tzLondon), 72 | schedule("2023-02-25", "2023-02-25 05:15:06", "2023-02-25 06:54:53", "2023-02-25 12:13:34", "2023-02-25 14:59:25", "2023-02-25 17:33:06", "2023-02-25 19:13:03", tzLondon), 73 | schedule("2023-02-26", "2023-02-26 05:13:09", "2023-02-26 06:52:47", "2023-02-26 12:13:24", "2023-02-26 15:00:43", "2023-02-26 17:34:53", "2023-02-26 19:14:41", tzLondon), 74 | schedule("2023-02-27", "2023-02-27 05:11:11", "2023-02-27 06:50:40", "2023-02-27 12:13:14", "2023-02-27 15:02:00", "2023-02-27 17:36:40", "2023-02-27 19:16:19", tzLondon), 75 | schedule("2023-02-28", "2023-02-28 05:09:11", "2023-02-28 06:48:32", "2023-02-28 12:13:03", "2023-02-28 15:03:16", "2023-02-28 17:38:27", "2023-02-28 19:17:58", tzLondon), 76 | schedule("2023-03-01", "2023-03-01 05:07:11", "2023-03-01 06:46:24", "2023-03-01 12:12:52", "2023-03-01 15:04:31", "2023-03-01 17:40:13", "2023-03-01 19:19:39", tzLondon), 77 | schedule("2023-03-02", "2023-03-02 05:05:08", "2023-03-02 06:44:15", "2023-03-02 12:12:40", "2023-03-02 15:05:46", "2023-03-02 17:41:59", "2023-03-02 19:21:17", tzLondon), 78 | schedule("2023-03-03", "2023-03-03 05:03:04", "2023-03-03 06:42:05", "2023-03-03 12:12:27", "2023-03-03 15:07:00", "2023-03-03 17:43:44", "2023-03-03 19:22:56", tzLondon), 79 | schedule("2023-03-04", "2023-03-04 05:01:00", "2023-03-04 06:39:54", "2023-03-04 12:12:15", "2023-03-04 15:08:13", "2023-03-04 17:45:30", "2023-03-04 19:24:36", tzLondon), 80 | schedule("2023-03-05", "2023-03-05 04:58:53", "2023-03-05 06:37:43", "2023-03-05 12:12:01", "2023-03-05 15:09:26", "2023-03-05 17:47:15", "2023-03-05 19:26:17", tzLondon), 81 | schedule("2023-03-06", "2023-03-06 04:56:47", "2023-03-06 06:35:31", "2023-03-06 12:11:48", "2023-03-06 15:10:38", "2023-03-06 17:49:00", "2023-03-06 19:27:56", tzLondon), 82 | schedule("2023-03-07", "2023-03-07 04:54:38", "2023-03-07 06:33:18", "2023-03-07 12:11:33", "2023-03-07 15:11:49", "2023-03-07 17:50:44", "2023-03-07 19:29:36", tzLondon), 83 | schedule("2023-03-08", "2023-03-08 04:52:29", "2023-03-08 06:31:05", "2023-03-08 12:11:19", "2023-03-08 15:12:59", "2023-03-08 17:52:28", "2023-03-08 19:31:18", tzLondon), 84 | schedule("2023-03-09", "2023-03-09 04:50:19", "2023-03-09 06:28:52", "2023-03-09 12:11:04", "2023-03-09 15:14:09", "2023-03-09 17:54:12", "2023-03-09 19:32:58", tzLondon), 85 | schedule("2023-03-10", "2023-03-10 04:48:08", "2023-03-10 06:26:38", "2023-03-10 12:10:49", "2023-03-10 15:15:18", "2023-03-10 17:55:56", "2023-03-10 19:34:40", tzLondon), 86 | schedule("2023-03-11", "2023-03-11 04:45:56", "2023-03-11 06:24:24", "2023-03-11 12:10:33", "2023-03-11 15:16:26", "2023-03-11 17:57:40", "2023-03-11 19:36:23", tzLondon), 87 | schedule("2023-03-12", "2023-03-12 04:43:42", "2023-03-12 06:22:09", "2023-03-12 12:10:17", "2023-03-12 15:17:33", "2023-03-12 17:59:23", "2023-03-12 19:38:05", tzLondon), 88 | schedule("2023-03-13", "2023-03-13 04:41:29", "2023-03-13 06:19:54", "2023-03-13 12:10:01", "2023-03-13 15:18:40", "2023-03-13 18:01:06", "2023-03-13 19:39:47", tzLondon), 89 | schedule("2023-03-14", "2023-03-14 04:39:14", "2023-03-14 06:17:39", "2023-03-14 12:09:45", "2023-03-14 15:19:46", "2023-03-14 18:02:49", "2023-03-14 19:41:30", tzLondon), 90 | schedule("2023-03-15", "2023-03-15 04:36:58", "2023-03-15 06:15:23", "2023-03-15 12:09:28", "2023-03-15 15:20:51", "2023-03-15 18:04:32", "2023-03-15 19:43:14", tzLondon), 91 | schedule("2023-03-16", "2023-03-16 04:34:42", "2023-03-16 06:13:07", "2023-03-16 12:09:11", "2023-03-16 15:21:56", "2023-03-16 18:06:14", "2023-03-16 19:44:56", tzLondon), 92 | schedule("2023-03-17", "2023-03-17 04:32:24", "2023-03-17 06:10:51", "2023-03-17 12:08:54", "2023-03-17 15:23:00", "2023-03-17 18:07:57", "2023-03-17 19:46:41", tzLondon), 93 | schedule("2023-03-18", "2023-03-18 04:30:06", "2023-03-18 06:08:35", "2023-03-18 12:08:37", "2023-03-18 15:24:03", "2023-03-18 18:09:39", "2023-03-18 19:48:25", tzLondon), 94 | schedule("2023-03-19", "2023-03-19 04:27:48", "2023-03-19 06:06:18", "2023-03-19 12:08:19", "2023-03-19 15:25:06", "2023-03-19 18:11:21", "2023-03-19 19:50:10", tzLondon), 95 | schedule("2023-03-20", "2023-03-20 04:25:28", "2023-03-20 06:04:01", "2023-03-20 12:08:02", "2023-03-20 15:26:08", "2023-03-20 18:13:03", "2023-03-20 19:51:55", tzLondon), 96 | schedule("2023-03-21", "2023-03-21 04:23:07", "2023-03-21 06:01:45", "2023-03-21 12:07:44", "2023-03-21 15:27:09", "2023-03-21 18:14:45", "2023-03-21 19:53:42", tzLondon), 97 | schedule("2023-03-22", "2023-03-22 04:20:46", "2023-03-22 05:59:28", "2023-03-22 12:07:27", "2023-03-22 15:28:09", "2023-03-22 18:16:26", "2023-03-22 19:55:28", tzLondon), 98 | schedule("2023-03-23", "2023-03-23 04:18:24", "2023-03-23 05:57:11", "2023-03-23 12:07:09", "2023-03-23 15:29:09", "2023-03-23 18:18:08", "2023-03-23 19:57:14", tzLondon), 99 | schedule("2023-03-24", "2023-03-24 04:16:02", "2023-03-24 05:54:54", "2023-03-24 12:06:51", "2023-03-24 15:30:08", "2023-03-24 18:19:49", "2023-03-24 19:59:01", tzLondon), 100 | schedule("2023-03-25", "2023-03-25 04:13:39", "2023-03-25 05:52:37", "2023-03-25 12:06:33", "2023-03-25 15:31:06", "2023-03-25 18:21:31", "2023-03-25 20:00:49", tzLondon), 101 | schedule("2023-03-26", "2023-03-26 05:11:15", "2023-03-26 06:50:19", "2023-03-26 13:06:11", "2023-03-26 16:31:56", "2023-03-26 19:23:02", "2023-03-26 21:02:26", tzLondon), 102 | schedule("2023-03-27", "2023-03-27 05:08:52", "2023-03-27 06:48:03", "2023-03-27 13:05:55", "2023-03-27 16:33:03", "2023-03-27 19:24:52", "2023-03-27 21:04:25", tzLondon), 103 | schedule("2023-03-28", "2023-03-28 05:06:27", "2023-03-28 06:45:46", "2023-03-28 13:05:39", "2023-03-28 16:34:01", "2023-03-28 19:26:34", "2023-03-28 21:06:15", tzLondon), 104 | schedule("2023-03-29", "2023-03-29 05:04:03", "2023-03-29 06:43:30", "2023-03-29 13:05:20", "2023-03-29 16:34:56", "2023-03-29 19:28:15", "2023-03-29 21:08:05", tzLondon), 105 | schedule("2023-03-30", "2023-03-30 05:01:37", "2023-03-30 06:41:13", "2023-03-30 13:05:02", "2023-03-30 16:35:51", "2023-03-30 19:29:55", "2023-03-30 21:09:55", tzLondon), 106 | schedule("2023-03-31", "2023-03-31 04:59:11", "2023-03-31 06:38:57", "2023-03-31 13:04:45", "2023-03-31 16:36:46", "2023-03-31 19:31:36", "2023-03-31 21:11:46", tzLondon), 107 | schedule("2023-04-01", "2023-04-01 04:56:45", "2023-04-01 06:36:41", "2023-04-01 13:04:27", "2023-04-01 16:37:40", "2023-04-01 19:33:16", "2023-04-01 21:13:37", tzLondon), 108 | schedule("2023-04-02", "2023-04-02 04:54:18", "2023-04-02 06:34:25", "2023-04-02 13:04:09", "2023-04-02 16:38:33", "2023-04-02 19:34:57", "2023-04-02 21:15:29", tzLondon), 109 | schedule("2023-04-03", "2023-04-03 04:51:51", "2023-04-03 06:32:09", "2023-04-03 13:03:51", "2023-04-03 16:39:25", "2023-04-03 19:36:37", "2023-04-03 21:17:21", tzLondon), 110 | schedule("2023-04-04", "2023-04-04 04:49:24", "2023-04-04 06:29:54", "2023-04-04 13:03:34", "2023-04-04 16:40:17", "2023-04-04 19:38:18", "2023-04-04 21:19:15", tzLondon), 111 | schedule("2023-04-05", "2023-04-05 04:46:56", "2023-04-05 06:27:39", "2023-04-05 13:03:16", "2023-04-05 16:41:09", "2023-04-05 19:39:58", "2023-04-05 21:21:07", tzLondon), 112 | schedule("2023-04-06", "2023-04-06 04:44:28", "2023-04-06 06:25:24", "2023-04-06 13:02:59", "2023-04-06 16:42:00", "2023-04-06 19:41:39", "2023-04-06 21:23:02", tzLondon), 113 | schedule("2023-04-07", "2023-04-07 04:42:00", "2023-04-07 06:23:10", "2023-04-07 13:02:42", "2023-04-07 16:42:50", "2023-04-07 19:43:19", "2023-04-07 21:24:57", tzLondon), 114 | schedule("2023-04-08", "2023-04-08 04:39:32", "2023-04-08 06:20:57", "2023-04-08 13:02:25", "2023-04-08 16:43:40", "2023-04-08 19:44:59", "2023-04-08 21:26:52", tzLondon), 115 | schedule("2023-04-09", "2023-04-09 04:37:03", "2023-04-09 06:18:43", "2023-04-09 13:02:09", "2023-04-09 16:44:29", "2023-04-09 19:46:40", "2023-04-09 21:28:49", tzLondon), 116 | schedule("2023-04-10", "2023-04-10 04:34:35", "2023-04-10 06:16:31", "2023-04-10 13:01:53", "2023-04-10 16:45:18", "2023-04-10 19:48:20", "2023-04-10 21:30:46", tzLondon), 117 | schedule("2023-04-11", "2023-04-11 04:32:05", "2023-04-11 06:14:18", "2023-04-11 13:01:37", "2023-04-11 16:46:06", "2023-04-11 19:50:00", "2023-04-11 21:32:43", tzLondon), 118 | schedule("2023-04-12", "2023-04-12 04:29:37", "2023-04-12 06:12:07", "2023-04-12 13:01:21", "2023-04-12 16:46:54", "2023-04-12 19:51:41", "2023-04-12 21:34:41", tzLondon), 119 | schedule("2023-04-13", "2023-04-13 04:27:09", "2023-04-13 06:09:56", "2023-04-13 13:01:06", "2023-04-13 16:47:42", "2023-04-13 19:53:21", "2023-04-13 21:36:39", tzLondon), 120 | schedule("2023-04-14", "2023-04-14 04:24:41", "2023-04-14 06:07:46", "2023-04-14 13:00:51", "2023-04-14 16:48:29", "2023-04-14 19:55:02", "2023-04-14 21:38:39", tzLondon), 121 | schedule("2023-04-15", "2023-04-15 04:22:11", "2023-04-15 06:05:36", "2023-04-15 13:00:36", "2023-04-15 16:49:15", "2023-04-15 19:56:42", "2023-04-15 21:40:39", tzLondon), 122 | schedule("2023-04-16", "2023-04-16 04:19:43", "2023-04-16 06:03:27", "2023-04-16 13:00:22", "2023-04-16 16:50:01", "2023-04-16 19:58:23", "2023-04-16 21:42:40", tzLondon), 123 | schedule("2023-04-17", "2023-04-17 04:17:14", "2023-04-17 06:01:19", "2023-04-17 13:00:08", "2023-04-17 16:50:47", "2023-04-17 20:00:03", "2023-04-17 21:44:41", tzLondon), 124 | schedule("2023-04-18", "2023-04-18 04:14:46", "2023-04-18 05:59:11", "2023-04-18 12:59:54", "2023-04-18 16:51:32", "2023-04-18 20:01:44", "2023-04-18 21:46:44", tzLondon), 125 | schedule("2023-04-19", "2023-04-19 04:12:18", "2023-04-19 05:57:05", "2023-04-19 12:59:41", "2023-04-19 16:52:17", "2023-04-19 20:03:24", "2023-04-19 21:48:46", tzLondon), 126 | schedule("2023-04-20", "2023-04-20 04:09:50", "2023-04-20 05:54:59", "2023-04-20 12:59:28", "2023-04-20 16:53:01", "2023-04-20 20:05:04", "2023-04-20 21:50:49", tzLondon), 127 | schedule("2023-04-21", "2023-04-21 04:07:22", "2023-04-21 05:52:54", "2023-04-21 12:59:16", "2023-04-21 16:53:45", "2023-04-21 20:06:45", "2023-04-21 21:52:53", tzLondon), 128 | schedule("2023-04-22", "2023-04-22 04:04:55", "2023-04-22 05:50:50", "2023-04-22 12:59:04", "2023-04-22 16:54:29", "2023-04-22 20:08:25", "2023-04-22 21:54:58", tzLondon), 129 | schedule("2023-04-23", "2023-04-23 04:02:27", "2023-04-23 05:48:47", "2023-04-23 12:58:53", "2023-04-23 16:55:12", "2023-04-23 20:10:05", "2023-04-23 21:57:03", tzLondon), 130 | schedule("2023-04-24", "2023-04-24 04:00:01", "2023-04-24 05:46:45", "2023-04-24 12:58:42", "2023-04-24 16:55:54", "2023-04-24 20:11:45", "2023-04-24 21:59:07", tzLondon), 131 | schedule("2023-04-25", "2023-04-25 03:57:35", "2023-04-25 05:44:45", "2023-04-25 12:58:32", "2023-04-25 16:56:37", "2023-04-25 20:13:25", "2023-04-25 22:01:13", tzLondon), 132 | schedule("2023-04-26", "2023-04-26 03:55:10", "2023-04-26 05:42:45", "2023-04-26 12:58:22", "2023-04-26 16:57:19", "2023-04-26 20:15:05", "2023-04-26 22:03:20", tzLondon), 133 | schedule("2023-04-27", "2023-04-27 03:52:45", "2023-04-27 05:40:46", "2023-04-27 12:58:12", "2023-04-27 16:58:00", "2023-04-27 20:16:44", "2023-04-27 22:05:27", tzLondon), 134 | schedule("2023-04-28", "2023-04-28 03:50:19", "2023-04-28 05:38:48", "2023-04-28 12:58:03", "2023-04-28 16:58:41", "2023-04-28 20:18:24", "2023-04-28 22:07:33", tzLondon), 135 | schedule("2023-04-29", "2023-04-29 03:47:55", "2023-04-29 05:36:52", "2023-04-29 12:57:54", "2023-04-29 16:59:22", "2023-04-29 20:20:03", "2023-04-29 22:09:41", tzLondon), 136 | schedule("2023-04-30", "2023-04-30 03:45:32", "2023-04-30 05:34:57", "2023-04-30 12:57:46", "2023-04-30 17:00:02", "2023-04-30 20:21:41", "2023-04-30 22:11:48", tzLondon), 137 | schedule("2023-05-01", "2023-05-01 03:43:09", "2023-05-01 05:33:03", "2023-05-01 12:57:39", "2023-05-01 17:00:42", "2023-05-01 20:23:20", "2023-05-01 22:13:57", tzLondon), 138 | schedule("2023-05-02", "2023-05-02 03:40:47", "2023-05-02 05:31:11", "2023-05-02 12:57:32", "2023-05-02 17:01:22", "2023-05-02 20:24:58", "2023-05-02 22:16:04", tzLondon), 139 | schedule("2023-05-03", "2023-05-03 03:38:27", "2023-05-03 05:29:20", "2023-05-03 12:57:25", "2023-05-03 17:02:01", "2023-05-03 20:26:36", "2023-05-03 22:18:13", tzLondon), 140 | schedule("2023-05-04", "2023-05-04 03:36:06", "2023-05-04 05:27:30", "2023-05-04 12:57:20", "2023-05-04 17:02:40", "2023-05-04 20:28:13", "2023-05-04 22:20:20", tzLondon), 141 | schedule("2023-05-05", "2023-05-05 03:33:47", "2023-05-05 05:25:42", "2023-05-05 12:57:14", "2023-05-05 17:03:18", "2023-05-05 20:29:50", "2023-05-05 22:22:30", tzLondon), 142 | schedule("2023-05-06", "2023-05-06 03:31:29", "2023-05-06 05:23:55", "2023-05-06 12:57:09", "2023-05-06 17:03:56", "2023-05-06 20:31:27", "2023-05-06 22:24:38", tzLondon), 143 | schedule("2023-05-07", "2023-05-07 03:29:11", "2023-05-07 05:22:10", "2023-05-07 12:57:05", "2023-05-07 17:04:34", "2023-05-07 20:33:03", "2023-05-07 22:26:48", tzLondon), 144 | schedule("2023-05-08", "2023-05-08 03:26:56", "2023-05-08 05:20:27", "2023-05-08 12:57:01", "2023-05-08 17:05:12", "2023-05-08 20:34:39", "2023-05-08 22:28:57", tzLondon), 145 | schedule("2023-05-09", "2023-05-09 03:24:41", "2023-05-09 05:18:45", "2023-05-09 12:56:58", "2023-05-09 17:05:49", "2023-05-09 20:36:14", "2023-05-09 22:31:06", tzLondon), 146 | schedule("2023-05-10", "2023-05-10 03:22:27", "2023-05-10 05:17:05", "2023-05-10 12:56:56", "2023-05-10 17:06:26", "2023-05-10 20:37:48", "2023-05-10 22:33:14", tzLondon), 147 | schedule("2023-05-11", "2023-05-11 03:20:15", "2023-05-11 05:15:27", "2023-05-11 12:56:54", "2023-05-11 17:07:02", "2023-05-11 20:39:22", "2023-05-11 22:35:21", tzLondon), 148 | schedule("2023-05-12", "2023-05-12 03:18:04", "2023-05-12 05:13:50", "2023-05-12 12:56:52", "2023-05-12 17:07:38", "2023-05-12 20:40:55", "2023-05-12 22:37:30", tzLondon), 149 | schedule("2023-05-13", "2023-05-13 03:15:55", "2023-05-13 05:12:16", "2023-05-13 12:56:52", "2023-05-13 17:08:14", "2023-05-13 20:42:28", "2023-05-13 22:39:38", tzLondon), 150 | schedule("2023-05-14", "2023-05-14 03:13:47", "2023-05-14 05:10:43", "2023-05-14 12:56:52", "2023-05-14 17:08:50", "2023-05-14 20:43:59", "2023-05-14 22:41:44", tzLondon), 151 | schedule("2023-05-15", "2023-05-15 03:11:40", "2023-05-15 05:09:12", "2023-05-15 12:56:52", "2023-05-15 17:09:25", "2023-05-15 20:45:30", "2023-05-15 22:43:52", tzLondon), 152 | schedule("2023-05-16", "2023-05-16 03:09:36", "2023-05-16 05:07:44", "2023-05-16 12:56:53", "2023-05-16 17:09:59", "2023-05-16 20:47:00", "2023-05-16 22:45:58", tzLondon), 153 | schedule("2023-05-17", "2023-05-17 03:07:32", "2023-05-17 05:06:17", "2023-05-17 12:56:55", "2023-05-17 17:10:34", "2023-05-17 20:48:29", "2023-05-17 22:48:03", tzLondon), 154 | schedule("2023-05-18", "2023-05-18 03:05:32", "2023-05-18 05:04:53", "2023-05-18 12:56:57", "2023-05-18 17:11:08", "2023-05-18 20:49:57", "2023-05-18 22:50:08", tzLondon), 155 | schedule("2023-05-19", "2023-05-19 03:03:32", "2023-05-19 05:03:30", "2023-05-19 12:56:59", "2023-05-19 17:11:42", "2023-05-19 20:51:24", "2023-05-19 22:52:12", tzLondon), 156 | schedule("2023-05-20", "2023-05-20 03:01:36", "2023-05-20 05:02:10", "2023-05-20 12:57:03", "2023-05-20 17:12:15", "2023-05-20 20:52:50", "2023-05-20 22:54:14", tzLondon), 157 | schedule("2023-05-21", "2023-05-21 02:59:41", "2023-05-21 05:00:52", "2023-05-21 12:57:07", "2023-05-21 17:12:48", "2023-05-21 20:54:14", "2023-05-21 22:56:15", tzLondon), 158 | schedule("2023-05-22", "2023-05-22 02:57:49", "2023-05-22 04:59:37", "2023-05-22 12:57:11", "2023-05-22 17:13:20", "2023-05-22 20:55:37", "2023-05-22 22:58:16", tzLondon), 159 | schedule("2023-05-23", "2023-05-23 02:55:57", "2023-05-23 04:58:23", "2023-05-23 12:57:16", "2023-05-23 17:13:52", "2023-05-23 20:56:59", "2023-05-23 23:00:14", tzLondon), 160 | schedule("2023-05-24", "2023-05-24 02:54:10", "2023-05-24 04:57:13", "2023-05-24 12:57:21", "2023-05-24 17:14:24", "2023-05-24 20:58:19", "2023-05-24 23:02:10", tzLondon), 161 | schedule("2023-05-25", "2023-05-25 02:52:24", "2023-05-25 04:56:04", "2023-05-25 12:57:27", "2023-05-25 17:14:55", "2023-05-25 20:59:38", "2023-05-25 23:04:05", tzLondon), 162 | schedule("2023-05-26", "2023-05-26 02:50:42", "2023-05-26 04:54:58", "2023-05-26 12:57:33", "2023-05-26 17:15:26", "2023-05-26 21:00:55", "2023-05-26 23:05:59", tzLondon), 163 | schedule("2023-05-27", "2023-05-27 02:49:02", "2023-05-27 04:53:55", "2023-05-27 12:57:40", "2023-05-27 17:15:56", "2023-05-27 21:02:11", "2023-05-27 23:07:51", tzLondon), 164 | schedule("2023-05-28", "2023-05-28 02:47:26", "2023-05-28 04:52:54", "2023-05-28 12:57:47", "2023-05-28 17:16:26", "2023-05-28 21:03:25", "2023-05-28 23:09:41", tzLondon), 165 | schedule("2023-05-29", "2023-05-29 02:45:52", "2023-05-29 04:51:56", "2023-05-29 12:57:55", "2023-05-29 17:16:55", "2023-05-29 21:04:37", "2023-05-29 23:11:28", tzLondon), 166 | schedule("2023-05-30", "2023-05-30 02:44:20", "2023-05-30 04:51:01", "2023-05-30 12:58:03", "2023-05-30 17:17:23", "2023-05-30 21:05:47", "2023-05-30 23:13:12", tzLondon), 167 | schedule("2023-05-31", "2023-05-31 02:42:53", "2023-05-31 04:50:08", "2023-05-31 12:58:11", "2023-05-31 17:17:51", "2023-05-31 21:06:55", "2023-05-31 23:14:55", tzLondon), 168 | schedule("2023-06-01", "2023-06-01 02:41:28", "2023-06-01 04:49:18", "2023-06-01 12:58:20", "2023-06-01 17:18:19", "2023-06-01 21:08:01", "2023-06-01 23:16:34", tzLondon), 169 | schedule("2023-06-02", "2023-06-02 02:40:08", "2023-06-02 04:48:31", "2023-06-02 12:58:30", "2023-06-02 17:18:46", "2023-06-02 21:09:05", "2023-06-02 23:18:11", tzLondon), 170 | schedule("2023-06-03", "2023-06-03 02:38:51", "2023-06-03 04:47:47", "2023-06-03 12:58:39", "2023-06-03 17:19:12", "2023-06-03 21:10:07", "2023-06-03 23:19:44", tzLondon), 171 | schedule("2023-06-04", "2023-06-04 02:37:37", "2023-06-04 04:47:05", "2023-06-04 12:58:49", "2023-06-04 17:19:38", "2023-06-04 21:11:07", "2023-06-04 23:21:15", tzLondon), 172 | schedule("2023-06-05", "2023-06-05 02:36:29", "2023-06-05 04:46:27", "2023-06-05 12:59:00", "2023-06-05 17:20:03", "2023-06-05 21:12:05", "2023-06-05 23:22:42", tzLondon), 173 | schedule("2023-06-06", "2023-06-06 02:35:22", "2023-06-06 04:45:51", "2023-06-06 12:59:10", "2023-06-06 17:20:28", "2023-06-06 21:13:00", "2023-06-06 23:24:05", tzLondon), 174 | schedule("2023-06-07", "2023-06-07 02:34:20", "2023-06-07 04:45:18", "2023-06-07 12:59:21", "2023-06-07 17:20:52", "2023-06-07 21:13:53", "2023-06-07 23:25:25", tzLondon), 175 | schedule("2023-06-08", "2023-06-08 02:33:24", "2023-06-08 04:44:49", "2023-06-08 12:59:33", "2023-06-08 17:21:15", "2023-06-08 21:14:43", "2023-06-08 23:26:42", tzLondon), 176 | schedule("2023-06-09", "2023-06-09 02:32:31", "2023-06-09 04:44:22", "2023-06-09 12:59:44", "2023-06-09 17:21:38", "2023-06-09 21:15:31", "2023-06-09 23:27:53", tzLondon), 177 | schedule("2023-06-10", "2023-06-10 02:31:43", "2023-06-10 04:43:59", "2023-06-10 12:59:56", "2023-06-10 17:22:00", "2023-06-10 21:16:17", "2023-06-10 23:29:02", tzLondon), 178 | schedule("2023-06-11", "2023-06-11 02:30:59", "2023-06-11 04:43:38", "2023-06-11 13:00:08", "2023-06-11 17:22:21", "2023-06-11 21:16:59", "2023-06-11 23:30:05", tzLondon), 179 | schedule("2023-06-12", "2023-06-12 02:30:20", "2023-06-12 04:43:21", "2023-06-12 13:00:21", "2023-06-12 17:22:41", "2023-06-12 21:17:39", "2023-06-12 23:31:04", tzLondon), 180 | schedule("2023-06-13", "2023-06-13 02:29:46", "2023-06-13 04:43:06", "2023-06-13 13:00:33", "2023-06-13 17:23:01", "2023-06-13 21:18:17", "2023-06-13 23:31:59", tzLondon), 181 | schedule("2023-06-14", "2023-06-14 02:29:17", "2023-06-14 04:42:55", "2023-06-14 13:00:46", "2023-06-14 17:23:20", "2023-06-14 21:18:52", "2023-06-14 23:32:49", tzLondon), 182 | schedule("2023-06-15", "2023-06-15 02:28:54", "2023-06-15 04:42:47", "2023-06-15 13:00:59", "2023-06-15 17:23:38", "2023-06-15 21:19:23", "2023-06-15 23:33:33", tzLondon), 183 | schedule("2023-06-16", "2023-06-16 02:28:35", "2023-06-16 04:42:42", "2023-06-16 13:01:12", "2023-06-16 17:23:56", "2023-06-16 21:19:52", "2023-06-16 23:34:13", tzLondon), 184 | schedule("2023-06-17", "2023-06-17 02:28:21", "2023-06-17 04:42:40", "2023-06-17 13:01:25", "2023-06-17 17:24:12", "2023-06-17 21:20:18", "2023-06-17 23:34:48", tzLondon), 185 | schedule("2023-06-18", "2023-06-18 02:28:13", "2023-06-18 04:42:41", "2023-06-18 13:01:38", "2023-06-18 17:24:28", "2023-06-18 21:20:41", "2023-06-18 23:35:18", tzLondon), 186 | schedule("2023-06-19", "2023-06-19 02:28:09", "2023-06-19 04:42:45", "2023-06-19 13:01:51", "2023-06-19 17:24:43", "2023-06-19 21:21:02", "2023-06-19 23:35:43", tzLondon), 187 | schedule("2023-06-20", "2023-06-20 02:28:11", "2023-06-20 04:42:52", "2023-06-20 13:02:04", "2023-06-20 17:24:56", "2023-06-20 21:21:19", "2023-06-20 23:36:02", tzLondon), 188 | schedule("2023-06-21", "2023-06-21 02:28:18", "2023-06-21 04:43:02", "2023-06-21 13:02:17", "2023-06-21 17:25:09", "2023-06-21 21:21:33", "2023-06-21 23:36:16", tzLondon), 189 | schedule("2023-06-22", "2023-06-22 02:28:31", "2023-06-22 04:43:16", "2023-06-22 13:02:30", "2023-06-22 17:25:21", "2023-06-22 21:21:43", "2023-06-22 23:36:25", tzLondon), 190 | schedule("2023-06-23", "2023-06-23 02:28:48", "2023-06-23 04:43:32", "2023-06-23 13:02:44", "2023-06-23 17:25:32", "2023-06-23 21:21:51", "2023-06-23 23:36:28", tzLondon), 191 | schedule("2023-06-24", "2023-06-24 02:29:12", "2023-06-24 04:43:51", "2023-06-24 13:02:56", "2023-06-24 17:25:42", "2023-06-24 21:21:56", "2023-06-24 23:36:25", tzLondon), 192 | schedule("2023-06-25", "2023-06-25 02:29:40", "2023-06-25 04:44:13", "2023-06-25 13:03:09", "2023-06-25 17:25:50", "2023-06-25 21:21:57", "2023-06-25 23:36:18", tzLondon), 193 | schedule("2023-06-26", "2023-06-26 02:30:14", "2023-06-26 04:44:38", "2023-06-26 13:03:22", "2023-06-26 17:25:58", "2023-06-26 21:21:56", "2023-06-26 23:36:05", tzLondon), 194 | schedule("2023-06-27", "2023-06-27 02:30:53", "2023-06-27 04:45:06", "2023-06-27 13:03:35", "2023-06-27 17:26:05", "2023-06-27 21:21:51", "2023-06-27 23:35:48", tzLondon), 195 | schedule("2023-06-28", "2023-06-28 02:31:34", "2023-06-28 04:45:36", "2023-06-28 13:03:47", "2023-06-28 17:26:10", "2023-06-28 21:21:43", "2023-06-28 23:35:23", tzLondon), 196 | schedule("2023-06-29", "2023-06-29 02:32:23", "2023-06-29 04:46:10", "2023-06-29 13:03:59", "2023-06-29 17:26:14", "2023-06-29 21:21:32", "2023-06-29 23:34:56", tzLondon), 197 | schedule("2023-06-30", "2023-06-30 02:33:16", "2023-06-30 04:46:46", "2023-06-30 13:04:11", "2023-06-30 17:26:17", "2023-06-30 21:21:18", "2023-06-30 23:34:23", tzLondon), 198 | schedule("2023-07-01", "2023-07-01 02:34:13", "2023-07-01 04:47:24", "2023-07-01 13:04:23", "2023-07-01 17:26:19", "2023-07-01 21:21:01", "2023-07-01 23:33:45", tzLondon), 199 | schedule("2023-07-02", "2023-07-02 02:35:15", "2023-07-02 04:48:06", "2023-07-02 13:04:34", "2023-07-02 17:26:20", "2023-07-02 21:20:40", "2023-07-02 23:33:01", tzLondon), 200 | schedule("2023-07-03", "2023-07-03 02:36:20", "2023-07-03 04:48:49", "2023-07-03 13:04:45", "2023-07-03 17:26:20", "2023-07-03 21:20:17", "2023-07-03 23:32:14", tzLondon), 201 | schedule("2023-07-04", "2023-07-04 02:37:30", "2023-07-04 04:49:36", "2023-07-04 13:04:56", "2023-07-04 17:26:18", "2023-07-04 21:19:50", "2023-07-04 23:31:21", tzLondon), 202 | schedule("2023-07-05", "2023-07-05 02:38:43", "2023-07-05 04:50:24", "2023-07-05 13:05:06", "2023-07-05 17:26:15", "2023-07-05 21:19:20", "2023-07-05 23:30:24", tzLondon), 203 | schedule("2023-07-06", "2023-07-06 02:40:02", "2023-07-06 04:51:16", "2023-07-06 13:05:16", "2023-07-06 17:26:11", "2023-07-06 21:18:48", "2023-07-06 23:29:24", tzLondon), 204 | schedule("2023-07-07", "2023-07-07 02:41:23", "2023-07-07 04:52:09", "2023-07-07 13:05:26", "2023-07-07 17:26:05", "2023-07-07 21:18:12", "2023-07-07 23:28:18", tzLondon), 205 | schedule("2023-07-08", "2023-07-08 02:42:48", "2023-07-08 04:53:05", "2023-07-08 13:05:36", "2023-07-08 17:25:58", "2023-07-08 21:17:34", "2023-07-08 23:27:10", tzLondon), 206 | schedule("2023-07-09", "2023-07-09 02:44:16", "2023-07-09 04:54:03", "2023-07-09 13:05:45", "2023-07-09 17:25:50", "2023-07-09 21:16:52", "2023-07-09 23:25:56", tzLondon), 207 | schedule("2023-07-10", "2023-07-10 02:45:47", "2023-07-10 04:55:03", "2023-07-10 13:05:53", "2023-07-10 17:25:41", "2023-07-10 21:16:08", "2023-07-10 23:24:40", tzLondon), 208 | schedule("2023-07-11", "2023-07-11 02:47:21", "2023-07-11 04:56:05", "2023-07-11 13:06:02", "2023-07-11 17:25:30", "2023-07-11 21:15:21", "2023-07-11 23:23:19", tzLondon), 209 | schedule("2023-07-12", "2023-07-12 02:48:58", "2023-07-12 04:57:09", "2023-07-12 13:06:10", "2023-07-12 17:25:18", "2023-07-12 21:14:31", "2023-07-12 23:21:55", tzLondon), 210 | schedule("2023-07-13", "2023-07-13 02:50:38", "2023-07-13 04:58:15", "2023-07-13 13:06:17", "2023-07-13 17:25:04", "2023-07-13 21:13:38", "2023-07-13 23:20:28", tzLondon), 211 | schedule("2023-07-14", "2023-07-14 02:52:20", "2023-07-14 04:59:23", "2023-07-14 13:06:24", "2023-07-14 17:24:50", "2023-07-14 21:12:42", "2023-07-14 23:18:57", tzLondon), 212 | schedule("2023-07-15", "2023-07-15 02:54:05", "2023-07-15 05:00:33", "2023-07-15 13:06:30", "2023-07-15 17:24:33", "2023-07-15 21:11:44", "2023-07-15 23:17:23", tzLondon), 213 | schedule("2023-07-16", "2023-07-16 02:55:51", "2023-07-16 05:01:44", "2023-07-16 13:06:36", "2023-07-16 17:24:16", "2023-07-16 21:10:43", "2023-07-16 23:15:46", tzLondon), 214 | schedule("2023-07-17", "2023-07-17 02:57:40", "2023-07-17 05:02:57", "2023-07-17 13:06:42", "2023-07-17 17:23:57", "2023-07-17 21:09:39", "2023-07-17 23:14:07", tzLondon), 215 | schedule("2023-07-18", "2023-07-18 02:59:31", "2023-07-18 05:04:12", "2023-07-18 13:06:47", "2023-07-18 17:23:36", "2023-07-18 21:08:33", "2023-07-18 23:12:24", tzLondon), 216 | schedule("2023-07-19", "2023-07-19 03:01:23", "2023-07-19 05:05:28", "2023-07-19 13:06:51", "2023-07-19 17:23:14", "2023-07-19 21:07:25", "2023-07-19 23:10:39", tzLondon), 217 | schedule("2023-07-20", "2023-07-20 03:03:17", "2023-07-20 05:06:46", "2023-07-20 13:06:55", "2023-07-20 17:22:50", "2023-07-20 21:06:14", "2023-07-20 23:08:51", tzLondon), 218 | schedule("2023-07-21", "2023-07-21 03:05:14", "2023-07-21 05:08:05", "2023-07-21 13:06:58", "2023-07-21 17:22:25", "2023-07-21 21:05:00", "2023-07-21 23:07:01", tzLondon), 219 | schedule("2023-07-22", "2023-07-22 03:07:10", "2023-07-22 05:09:25", "2023-07-22 13:07:01", "2023-07-22 17:21:59", "2023-07-22 21:03:44", "2023-07-22 23:05:07", tzLondon), 220 | schedule("2023-07-23", "2023-07-23 03:09:08", "2023-07-23 05:10:46", "2023-07-23 13:07:03", "2023-07-23 17:21:31", "2023-07-23 21:02:26", "2023-07-23 23:03:14", tzLondon), 221 | schedule("2023-07-24", "2023-07-24 03:11:07", "2023-07-24 05:12:09", "2023-07-24 13:07:04", "2023-07-24 17:21:01", "2023-07-24 21:01:05", "2023-07-24 23:01:16", tzLondon), 222 | schedule("2023-07-25", "2023-07-25 03:13:07", "2023-07-25 05:13:33", "2023-07-25 13:07:05", "2023-07-25 17:20:31", "2023-07-25 20:59:42", "2023-07-25 22:59:17", tzLondon), 223 | schedule("2023-07-26", "2023-07-26 03:15:08", "2023-07-26 05:14:57", "2023-07-26 13:07:05", "2023-07-26 17:19:58", "2023-07-26 20:58:17", "2023-07-26 22:57:16", tzLondon), 224 | schedule("2023-07-27", "2023-07-27 03:17:10", "2023-07-27 05:16:23", "2023-07-27 13:07:05", "2023-07-27 17:19:24", "2023-07-27 20:56:50", "2023-07-27 22:55:12", tzLondon), 225 | schedule("2023-07-28", "2023-07-28 03:19:12", "2023-07-28 05:17:49", "2023-07-28 13:07:04", "2023-07-28 17:18:48", "2023-07-28 20:55:21", "2023-07-28 22:53:07", tzLondon), 226 | schedule("2023-07-29", "2023-07-29 03:21:15", "2023-07-29 05:19:17", "2023-07-29 13:07:02", "2023-07-29 17:18:11", "2023-07-29 20:53:50", "2023-07-29 22:51:01", tzLondon), 227 | schedule("2023-07-30", "2023-07-30 03:23:19", "2023-07-30 05:20:45", "2023-07-30 13:07:00", "2023-07-30 17:17:33", "2023-07-30 20:52:16", "2023-07-30 22:48:53", tzLondon), 228 | schedule("2023-07-31", "2023-07-31 03:25:23", "2023-07-31 05:22:14", "2023-07-31 13:06:57", "2023-07-31 17:16:53", "2023-07-31 20:50:41", "2023-07-31 22:46:42", tzLondon), 229 | schedule("2023-08-01", "2023-08-01 03:27:26", "2023-08-01 05:23:43", "2023-08-01 13:06:54", "2023-08-01 17:16:11", "2023-08-01 20:49:04", "2023-08-01 22:44:31", tzLondon), 230 | schedule("2023-08-02", "2023-08-02 03:29:31", "2023-08-02 05:25:13", "2023-08-02 13:06:50", "2023-08-02 17:15:28", "2023-08-02 20:47:25", "2023-08-02 22:42:18", tzLondon), 231 | schedule("2023-08-03", "2023-08-03 03:31:36", "2023-08-03 05:26:44", "2023-08-03 13:06:45", "2023-08-03 17:14:44", "2023-08-03 20:45:45", "2023-08-03 22:40:05", tzLondon), 232 | schedule("2023-08-04", "2023-08-04 03:33:40", "2023-08-04 05:28:15", "2023-08-04 13:06:40", "2023-08-04 17:13:58", "2023-08-04 20:44:02", "2023-08-04 22:37:49", tzLondon), 233 | schedule("2023-08-05", "2023-08-05 03:35:45", "2023-08-05 05:29:47", "2023-08-05 13:06:34", "2023-08-05 17:13:10", "2023-08-05 20:42:18", "2023-08-05 22:35:32", tzLondon), 234 | schedule("2023-08-06", "2023-08-06 03:37:50", "2023-08-06 05:31:19", "2023-08-06 13:06:27", "2023-08-06 17:12:21", "2023-08-06 20:40:33", "2023-08-06 22:33:15", tzLondon), 235 | schedule("2023-08-07", "2023-08-07 03:39:55", "2023-08-07 05:32:52", "2023-08-07 13:06:20", "2023-08-07 17:11:31", "2023-08-07 20:38:45", "2023-08-07 22:30:56", tzLondon), 236 | schedule("2023-08-08", "2023-08-08 03:42:00", "2023-08-08 05:34:25", "2023-08-08 13:06:13", "2023-08-08 17:10:39", "2023-08-08 20:36:57", "2023-08-08 22:28:36", tzLondon), 237 | schedule("2023-08-09", "2023-08-09 03:44:04", "2023-08-09 05:35:59", "2023-08-09 13:06:05", "2023-08-09 17:09:46", "2023-08-09 20:35:06", "2023-08-09 22:26:15", tzLondon), 238 | schedule("2023-08-10", "2023-08-10 03:46:09", "2023-08-10 05:37:33", "2023-08-10 13:05:56", "2023-08-10 17:08:51", "2023-08-10 20:33:15", "2023-08-10 22:23:54", tzLondon), 239 | schedule("2023-08-11", "2023-08-11 03:48:13", "2023-08-11 05:39:07", "2023-08-11 13:05:47", "2023-08-11 17:07:55", "2023-08-11 20:31:22", "2023-08-11 22:21:32", tzLondon), 240 | schedule("2023-08-12", "2023-08-12 03:50:18", "2023-08-12 05:40:42", "2023-08-12 13:05:37", "2023-08-12 17:06:58", "2023-08-12 20:29:27", "2023-08-12 22:19:08", tzLondon), 241 | schedule("2023-08-13", "2023-08-13 03:52:21", "2023-08-13 05:42:16", "2023-08-13 13:05:26", "2023-08-13 17:05:59", "2023-08-13 20:27:31", "2023-08-13 22:16:43", tzLondon), 242 | schedule("2023-08-14", "2023-08-14 03:54:24", "2023-08-14 05:43:51", "2023-08-14 13:05:15", "2023-08-14 17:04:59", "2023-08-14 20:25:34", "2023-08-14 22:14:18", tzLondon), 243 | schedule("2023-08-15", "2023-08-15 03:56:26", "2023-08-15 05:45:26", "2023-08-15 13:05:04", "2023-08-15 17:03:57", "2023-08-15 20:23:36", "2023-08-15 22:11:54", tzLondon), 244 | schedule("2023-08-16", "2023-08-16 03:58:29", "2023-08-16 05:47:02", "2023-08-16 13:04:52", "2023-08-16 17:02:54", "2023-08-16 20:21:37", "2023-08-16 22:09:28", tzLondon), 245 | schedule("2023-08-17", "2023-08-17 04:00:31", "2023-08-17 05:48:37", "2023-08-17 13:04:39", "2023-08-17 17:01:49", "2023-08-17 20:19:36", "2023-08-17 22:07:01", tzLondon), 246 | schedule("2023-08-18", "2023-08-18 04:02:33", "2023-08-18 05:50:13", "2023-08-18 13:04:26", "2023-08-18 17:00:44", "2023-08-18 20:17:35", "2023-08-18 22:04:34", tzLondon), 247 | schedule("2023-08-19", "2023-08-19 04:04:34", "2023-08-19 05:51:48", "2023-08-19 13:04:13", "2023-08-19 16:59:37", "2023-08-19 20:15:32", "2023-08-19 22:02:06", tzLondon), 248 | schedule("2023-08-20", "2023-08-20 04:06:34", "2023-08-20 05:53:24", "2023-08-20 13:03:59", "2023-08-20 16:58:28", "2023-08-20 20:13:28", "2023-08-20 21:59:39", tzLondon), 249 | schedule("2023-08-21", "2023-08-21 04:08:34", "2023-08-21 05:55:00", "2023-08-21 13:03:44", "2023-08-21 16:57:19", "2023-08-21 20:11:23", "2023-08-21 21:57:10", tzLondon), 250 | schedule("2023-08-22", "2023-08-22 04:10:34", "2023-08-22 05:56:35", "2023-08-22 13:03:29", "2023-08-22 16:56:08", "2023-08-22 20:09:18", "2023-08-22 21:54:42", tzLondon), 251 | schedule("2023-08-23", "2023-08-23 04:12:32", "2023-08-23 05:58:11", "2023-08-23 13:03:14", "2023-08-23 16:54:55", "2023-08-23 20:07:11", "2023-08-23 21:52:13", tzLondon), 252 | schedule("2023-08-24", "2023-08-24 04:14:30", "2023-08-24 05:59:47", "2023-08-24 13:02:58", "2023-08-24 16:53:42", "2023-08-24 20:05:03", "2023-08-24 21:49:43", tzLondon), 253 | schedule("2023-08-25", "2023-08-25 04:16:28", "2023-08-25 06:01:23", "2023-08-25 13:02:42", "2023-08-25 16:52:27", "2023-08-25 20:02:55", "2023-08-25 21:47:14", tzLondon), 254 | schedule("2023-08-26", "2023-08-26 04:18:24", "2023-08-26 06:02:58", "2023-08-26 13:02:25", "2023-08-26 16:51:11", "2023-08-26 20:00:46", "2023-08-26 21:44:44", tzLondon), 255 | schedule("2023-08-27", "2023-08-27 04:20:21", "2023-08-27 06:04:34", "2023-08-27 13:02:08", "2023-08-27 16:49:54", "2023-08-27 19:58:36", "2023-08-27 21:42:15", tzLondon), 256 | schedule("2023-08-28", "2023-08-28 04:22:15", "2023-08-28 06:06:09", "2023-08-28 13:01:50", "2023-08-28 16:48:36", "2023-08-28 19:56:25", "2023-08-28 21:39:45", tzLondon), 257 | schedule("2023-08-29", "2023-08-29 04:24:11", "2023-08-29 06:07:45", "2023-08-29 13:01:32", "2023-08-29 16:47:16", "2023-08-29 19:54:14", "2023-08-29 21:37:15", tzLondon), 258 | schedule("2023-08-30", "2023-08-30 04:26:04", "2023-08-30 06:09:20", "2023-08-30 13:01:14", "2023-08-30 16:45:56", "2023-08-30 19:52:02", "2023-08-30 21:34:45", tzLondon), 259 | schedule("2023-08-31", "2023-08-31 04:27:58", "2023-08-31 06:10:56", "2023-08-31 13:00:55", "2023-08-31 16:44:34", "2023-08-31 19:49:49", "2023-08-31 21:32:14", tzLondon), 260 | schedule("2023-09-01", "2023-09-01 04:29:51", "2023-09-01 06:12:31", "2023-09-01 13:00:36", "2023-09-01 16:43:11", "2023-09-01 19:47:36", "2023-09-01 21:29:45", tzLondon), 261 | schedule("2023-09-02", "2023-09-02 04:31:43", "2023-09-02 06:14:07", "2023-09-02 13:00:17", "2023-09-02 16:41:48", "2023-09-02 19:45:22", "2023-09-02 21:27:15", tzLondon), 262 | schedule("2023-09-03", "2023-09-03 04:33:35", "2023-09-03 06:15:42", "2023-09-03 12:59:57", "2023-09-03 16:40:23", "2023-09-03 19:43:08", "2023-09-03 21:24:46", tzLondon), 263 | schedule("2023-09-04", "2023-09-04 04:35:26", "2023-09-04 06:17:18", "2023-09-04 12:59:38", "2023-09-04 16:38:57", "2023-09-04 19:40:53", "2023-09-04 21:22:15", tzLondon), 264 | schedule("2023-09-05", "2023-09-05 04:37:16", "2023-09-05 06:18:53", "2023-09-05 12:59:18", "2023-09-05 16:37:30", "2023-09-05 19:38:38", "2023-09-05 21:19:46", tzLondon), 265 | schedule("2023-09-06", "2023-09-06 04:39:05", "2023-09-06 06:20:28", "2023-09-06 12:58:57", "2023-09-06 16:36:03", "2023-09-06 19:36:22", "2023-09-06 21:17:16", tzLondon), 266 | schedule("2023-09-07", "2023-09-07 04:40:55", "2023-09-07 06:22:04", "2023-09-07 12:58:37", "2023-09-07 16:34:34", "2023-09-07 19:34:06", "2023-09-07 21:14:48", tzLondon), 267 | schedule("2023-09-08", "2023-09-08 04:42:43", "2023-09-08 06:23:39", "2023-09-08 12:58:16", "2023-09-08 16:33:05", "2023-09-08 19:31:50", "2023-09-08 21:12:19", tzLondon), 268 | schedule("2023-09-09", "2023-09-09 04:44:31", "2023-09-09 06:25:15", "2023-09-09 12:57:56", "2023-09-09 16:31:34", "2023-09-09 19:29:33", "2023-09-09 21:09:49", tzLondon), 269 | schedule("2023-09-10", "2023-09-10 04:46:17", "2023-09-10 06:26:50", "2023-09-10 12:57:35", "2023-09-10 16:30:03", "2023-09-10 19:27:16", "2023-09-10 21:07:21", tzLondon), 270 | schedule("2023-09-11", "2023-09-11 04:48:05", "2023-09-11 06:28:26", "2023-09-11 12:57:14", "2023-09-11 16:28:31", "2023-09-11 19:24:59", "2023-09-11 21:04:54", tzLondon), 271 | schedule("2023-09-12", "2023-09-12 04:49:52", "2023-09-12 06:30:02", "2023-09-12 12:56:53", "2023-09-12 16:26:59", "2023-09-12 19:22:41", "2023-09-12 21:02:26", tzLondon), 272 | schedule("2023-09-13", "2023-09-13 04:51:36", "2023-09-13 06:31:37", "2023-09-13 12:56:31", "2023-09-13 16:25:25", "2023-09-13 19:20:23", "2023-09-13 20:59:58", tzLondon), 273 | schedule("2023-09-14", "2023-09-14 04:53:21", "2023-09-14 06:33:13", "2023-09-14 12:56:10", "2023-09-14 16:23:51", "2023-09-14 19:18:05", "2023-09-14 20:57:32", tzLondon), 274 | schedule("2023-09-15", "2023-09-15 04:55:07", "2023-09-15 06:34:49", "2023-09-15 12:55:49", "2023-09-15 16:22:16", "2023-09-15 19:15:47", "2023-09-15 20:55:06", tzLondon), 275 | schedule("2023-09-16", "2023-09-16 04:56:49", "2023-09-16 06:36:24", "2023-09-16 12:55:27", "2023-09-16 16:20:40", "2023-09-16 19:13:29", "2023-09-16 20:52:39", tzLondon), 276 | schedule("2023-09-17", "2023-09-17 04:58:33", "2023-09-17 06:38:00", "2023-09-17 12:55:06", "2023-09-17 16:19:04", "2023-09-17 19:11:11", "2023-09-17 20:50:15", tzLondon), 277 | schedule("2023-09-18", "2023-09-18 05:00:17", "2023-09-18 06:39:36", "2023-09-18 12:54:45", "2023-09-18 16:17:27", "2023-09-18 19:08:52", "2023-09-18 20:47:49", tzLondon), 278 | schedule("2023-09-19", "2023-09-19 05:01:59", "2023-09-19 06:41:12", "2023-09-19 12:54:23", "2023-09-19 16:15:49", "2023-09-19 19:06:34", "2023-09-19 20:45:25", tzLondon), 279 | schedule("2023-09-20", "2023-09-20 05:03:40", "2023-09-20 06:42:48", "2023-09-20 12:54:02", "2023-09-20 16:14:11", "2023-09-20 19:04:15", "2023-09-20 20:43:01", tzLondon), 280 | schedule("2023-09-21", "2023-09-21 05:05:23", "2023-09-21 06:44:25", "2023-09-21 12:53:41", "2023-09-21 16:12:33", "2023-09-21 19:01:57", "2023-09-21 20:40:39", tzLondon), 281 | schedule("2023-09-22", "2023-09-22 05:07:03", "2023-09-22 06:46:01", "2023-09-22 12:53:19", "2023-09-22 16:10:54", "2023-09-22 18:59:38", "2023-09-22 20:38:14", tzLondon), 282 | schedule("2023-09-23", "2023-09-23 05:08:43", "2023-09-23 06:47:37", "2023-09-23 12:52:58", "2023-09-23 16:09:14", "2023-09-23 18:57:20", "2023-09-23 20:35:53", tzLondon), 283 | schedule("2023-09-24", "2023-09-24 05:10:24", "2023-09-24 06:49:14", "2023-09-24 12:52:37", "2023-09-24 16:07:34", "2023-09-24 18:55:02", "2023-09-24 20:33:33", tzLondon), 284 | schedule("2023-09-25", "2023-09-25 05:12:03", "2023-09-25 06:50:51", "2023-09-25 12:52:16", "2023-09-25 16:05:54", "2023-09-25 18:52:43", "2023-09-25 20:31:11", tzLondon), 285 | schedule("2023-09-26", "2023-09-26 05:13:42", "2023-09-26 06:52:27", "2023-09-26 12:51:56", "2023-09-26 16:04:13", "2023-09-26 18:50:25", "2023-09-26 20:28:51", tzLondon), 286 | schedule("2023-09-27", "2023-09-27 05:15:22", "2023-09-27 06:54:04", "2023-09-27 12:51:35", "2023-09-27 16:02:32", "2023-09-27 18:48:08", "2023-09-27 20:26:32", tzLondon), 287 | schedule("2023-09-28", "2023-09-28 05:16:59", "2023-09-28 06:55:41", "2023-09-28 12:51:15", "2023-09-28 16:00:50", "2023-09-28 18:45:50", "2023-09-28 20:24:14", tzLondon), 288 | schedule("2023-09-29", "2023-09-29 05:18:37", "2023-09-29 06:57:19", "2023-09-29 12:50:54", "2023-09-29 15:59:09", "2023-09-29 18:43:33", "2023-09-29 20:21:57", tzLondon), 289 | schedule("2023-09-30", "2023-09-30 05:20:15", "2023-09-30 06:58:56", "2023-09-30 12:50:35", "2023-09-30 15:57:27", "2023-09-30 18:41:16", "2023-09-30 20:19:40", tzLondon), 290 | schedule("2023-10-01", "2023-10-01 05:21:52", "2023-10-01 07:00:34", "2023-10-01 12:50:15", "2023-10-01 15:55:45", "2023-10-01 18:38:59", "2023-10-01 20:17:24", tzLondon), 291 | schedule("2023-10-02", "2023-10-02 05:23:29", "2023-10-02 07:02:12", "2023-10-02 12:49:56", "2023-10-02 15:54:03", "2023-10-02 18:36:43", "2023-10-02 20:15:10", tzLondon), 292 | schedule("2023-10-03", "2023-10-03 05:25:05", "2023-10-03 07:03:50", "2023-10-03 12:49:37", "2023-10-03 15:52:20", "2023-10-03 18:34:27", "2023-10-03 20:12:56", tzLondon), 293 | schedule("2023-10-04", "2023-10-04 05:26:43", "2023-10-04 07:05:29", "2023-10-04 12:49:18", "2023-10-04 15:50:38", "2023-10-04 18:32:11", "2023-10-04 20:10:42", tzLondon), 294 | schedule("2023-10-05", "2023-10-05 05:28:19", "2023-10-05 07:07:08", "2023-10-05 12:49:00", "2023-10-05 15:48:56", "2023-10-05 18:29:56", "2023-10-05 20:08:30", tzLondon), 295 | schedule("2023-10-06", "2023-10-06 05:29:54", "2023-10-06 07:08:47", "2023-10-06 12:48:42", "2023-10-06 15:47:13", "2023-10-06 18:27:41", "2023-10-06 20:06:19", tzLondon), 296 | schedule("2023-10-07", "2023-10-07 05:31:30", "2023-10-07 07:10:26", "2023-10-07 12:48:24", "2023-10-07 15:45:31", "2023-10-07 18:25:27", "2023-10-07 20:04:09", tzLondon), 297 | schedule("2023-10-08", "2023-10-08 05:33:05", "2023-10-08 07:12:06", "2023-10-08 12:48:07", "2023-10-08 15:43:49", "2023-10-08 18:23:14", "2023-10-08 20:02:00", tzLondon), 298 | schedule("2023-10-09", "2023-10-09 05:34:41", "2023-10-09 07:13:46", "2023-10-09 12:47:50", "2023-10-09 15:42:07", "2023-10-09 18:21:00", "2023-10-09 19:59:51", tzLondon), 299 | schedule("2023-10-10", "2023-10-10 05:36:16", "2023-10-10 07:15:26", "2023-10-10 12:47:34", "2023-10-10 15:40:25", "2023-10-10 18:18:48", "2023-10-10 19:57:45", tzLondon), 300 | schedule("2023-10-11", "2023-10-11 05:37:51", "2023-10-11 07:17:07", "2023-10-11 12:47:18", "2023-10-11 15:38:43", "2023-10-11 18:16:36", "2023-10-11 19:55:38", tzLondon), 301 | schedule("2023-10-12", "2023-10-12 05:39:25", "2023-10-12 07:18:48", "2023-10-12 12:47:03", "2023-10-12 15:37:02", "2023-10-12 18:14:25", "2023-10-12 19:53:34", tzLondon), 302 | schedule("2023-10-13", "2023-10-13 05:41:00", "2023-10-13 07:20:30", "2023-10-13 12:46:48", "2023-10-13 15:35:20", "2023-10-13 18:12:15", "2023-10-13 19:51:31", tzLondon), 303 | schedule("2023-10-14", "2023-10-14 05:42:34", "2023-10-14 07:22:11", "2023-10-14 12:46:34", "2023-10-14 15:33:40", "2023-10-14 18:10:05", "2023-10-14 19:49:29", tzLondon), 304 | schedule("2023-10-15", "2023-10-15 05:44:09", "2023-10-15 07:23:53", "2023-10-15 12:46:21", "2023-10-15 15:31:59", "2023-10-15 18:07:56", "2023-10-15 19:47:29", tzLondon), 305 | schedule("2023-10-16", "2023-10-16 05:45:42", "2023-10-16 07:25:35", "2023-10-16 12:46:07", "2023-10-16 15:30:19", "2023-10-16 18:05:48", "2023-10-16 19:45:29", tzLondon), 306 | schedule("2023-10-17", "2023-10-17 05:47:17", "2023-10-17 07:27:18", "2023-10-17 12:45:55", "2023-10-17 15:28:40", "2023-10-17 18:03:41", "2023-10-17 19:43:31", tzLondon), 307 | schedule("2023-10-18", "2023-10-18 05:48:51", "2023-10-18 07:29:01", "2023-10-18 12:45:43", "2023-10-18 15:27:01", "2023-10-18 18:01:35", "2023-10-18 19:41:35", tzLondon), 308 | schedule("2023-10-19", "2023-10-19 05:50:25", "2023-10-19 07:30:44", "2023-10-19 12:45:32", "2023-10-19 15:25:23", "2023-10-19 17:59:29", "2023-10-19 19:39:39", tzLondon), 309 | schedule("2023-10-20", "2023-10-20 05:51:56", "2023-10-20 07:32:27", "2023-10-20 12:45:21", "2023-10-20 15:23:45", "2023-10-20 17:57:25", "2023-10-20 19:37:44", tzLondon), 310 | schedule("2023-10-21", "2023-10-21 05:53:31", "2023-10-21 07:34:11", "2023-10-21 12:45:11", "2023-10-21 15:22:08", "2023-10-21 17:55:22", "2023-10-21 19:35:52", tzLondon), 311 | schedule("2023-10-22", "2023-10-22 05:55:03", "2023-10-22 07:35:55", "2023-10-22 12:45:01", "2023-10-22 15:20:31", "2023-10-22 17:53:19", "2023-10-22 19:34:00", tzLondon), 312 | schedule("2023-10-23", "2023-10-23 05:56:36", "2023-10-23 07:37:39", "2023-10-23 12:44:53", "2023-10-23 15:18:56", "2023-10-23 17:51:18", "2023-10-23 19:32:11", tzLondon), 313 | schedule("2023-10-24", "2023-10-24 05:58:09", "2023-10-24 07:39:24", "2023-10-24 12:44:44", "2023-10-24 15:17:21", "2023-10-24 17:49:18", "2023-10-24 19:30:23", tzLondon), 314 | schedule("2023-10-25", "2023-10-25 05:59:41", "2023-10-25 07:41:08", "2023-10-25 12:44:37", "2023-10-25 15:15:47", "2023-10-25 17:47:19", "2023-10-25 19:28:36", tzLondon), 315 | schedule("2023-10-26", "2023-10-26 06:01:14", "2023-10-26 07:42:53", "2023-10-26 12:44:30", "2023-10-26 15:14:14", "2023-10-26 17:45:21", "2023-10-26 19:26:51", tzLondon), 316 | schedule("2023-10-27", "2023-10-27 06:02:45", "2023-10-27 07:44:38", "2023-10-27 12:44:24", "2023-10-27 15:12:42", "2023-10-27 17:43:24", "2023-10-27 19:25:07", tzLondon), 317 | schedule("2023-10-28", "2023-10-28 06:04:18", "2023-10-28 07:46:23", "2023-10-28 12:44:19", "2023-10-28 15:11:10", "2023-10-28 17:41:29", "2023-10-28 19:23:26", tzLondon), 318 | schedule("2023-10-29", "2023-10-29 05:05:52", "2023-10-29 06:48:12", "2023-10-29 11:44:18", "2023-10-29 14:09:41", "2023-10-29 16:39:39", "2023-10-29 18:21:50", tzLondon), 319 | schedule("2023-10-30", "2023-10-30 05:07:22", "2023-10-30 06:49:55", "2023-10-30 11:44:12", "2023-10-30 14:08:16", "2023-10-30 16:37:43", "2023-10-30 18:20:08", tzLondon), 320 | schedule("2023-10-31", "2023-10-31 05:08:53", "2023-10-31 06:51:40", "2023-10-31 11:44:08", "2023-10-31 14:06:48", "2023-10-31 16:35:52", "2023-10-31 18:18:32", tzLondon), 321 | schedule("2023-11-01", "2023-11-01 05:10:24", "2023-11-01 06:53:25", "2023-11-01 11:44:05", "2023-11-01 14:05:22", "2023-11-01 16:34:02", "2023-11-01 18:16:55", tzLondon), 322 | schedule("2023-11-02", "2023-11-02 05:11:54", "2023-11-02 06:55:11", "2023-11-02 11:44:04", "2023-11-02 14:03:57", "2023-11-02 16:32:14", "2023-11-02 18:15:23", tzLondon), 323 | schedule("2023-11-03", "2023-11-03 05:13:26", "2023-11-03 06:56:57", "2023-11-03 11:44:03", "2023-11-03 14:02:33", "2023-11-03 16:30:28", "2023-11-03 18:13:53", tzLondon), 324 | schedule("2023-11-04", "2023-11-04 05:14:56", "2023-11-04 06:58:43", "2023-11-04 11:44:04", "2023-11-04 14:01:10", "2023-11-04 16:28:43", "2023-11-04 18:12:22", tzLondon), 325 | schedule("2023-11-05", "2023-11-05 05:16:27", "2023-11-05 07:00:29", "2023-11-05 11:44:05", "2023-11-05 13:59:49", "2023-11-05 16:27:00", "2023-11-05 18:10:55", tzLondon), 326 | schedule("2023-11-06", "2023-11-06 05:17:57", "2023-11-06 07:02:15", "2023-11-06 11:44:07", "2023-11-06 13:58:30", "2023-11-06 16:25:19", "2023-11-06 18:09:31", tzLondon), 327 | schedule("2023-11-07", "2023-11-07 05:19:26", "2023-11-07 07:04:01", "2023-11-07 11:44:10", "2023-11-07 13:57:12", "2023-11-07 16:23:39", "2023-11-07 18:08:06", tzLondon), 328 | schedule("2023-11-08", "2023-11-08 05:20:56", "2023-11-08 07:05:46", "2023-11-08 11:44:13", "2023-11-08 13:55:56", "2023-11-08 16:22:01", "2023-11-08 18:06:46", tzLondon), 329 | schedule("2023-11-09", "2023-11-09 05:22:25", "2023-11-09 07:07:32", "2023-11-09 11:44:18", "2023-11-09 13:54:41", "2023-11-09 16:20:25", "2023-11-09 18:05:26", tzLondon), 330 | schedule("2023-11-10", "2023-11-10 05:23:53", "2023-11-10 07:09:17", "2023-11-10 11:44:23", "2023-11-10 13:53:28", "2023-11-10 16:18:52", "2023-11-10 18:04:09", tzLondon), 331 | schedule("2023-11-11", "2023-11-11 05:25:22", "2023-11-11 07:11:02", "2023-11-11 11:44:29", "2023-11-11 13:52:17", "2023-11-11 16:17:20", "2023-11-11 18:02:55", tzLondon), 332 | schedule("2023-11-12", "2023-11-12 05:26:51", "2023-11-12 07:12:47", "2023-11-12 11:44:37", "2023-11-12 13:51:08", "2023-11-12 16:15:50", "2023-11-12 18:01:41", tzLondon), 333 | schedule("2023-11-13", "2023-11-13 05:28:17", "2023-11-13 07:14:31", "2023-11-13 11:44:44", "2023-11-13 13:50:01", "2023-11-13 16:14:22", "2023-11-13 18:00:30", tzLondon), 334 | schedule("2023-11-14", "2023-11-14 05:29:45", "2023-11-14 07:16:15", "2023-11-14 11:44:53", "2023-11-14 13:48:55", "2023-11-14 16:12:57", "2023-11-14 17:59:23", tzLondon), 335 | schedule("2023-11-15", "2023-11-15 05:31:11", "2023-11-15 07:17:58", "2023-11-15 11:45:03", "2023-11-15 13:47:52", "2023-11-15 16:11:34", "2023-11-15 17:58:16", tzLondon), 336 | schedule("2023-11-16", "2023-11-16 05:32:38", "2023-11-16 07:19:41", "2023-11-16 11:45:13", "2023-11-16 13:46:50", "2023-11-16 16:10:13", "2023-11-16 17:57:12", tzLondon), 337 | schedule("2023-11-17", "2023-11-17 05:34:03", "2023-11-17 07:21:23", "2023-11-17 11:45:25", "2023-11-17 13:45:51", "2023-11-17 16:08:54", "2023-11-17 17:56:11", tzLondon), 338 | schedule("2023-11-18", "2023-11-18 05:35:26", "2023-11-18 07:23:04", "2023-11-18 11:45:37", "2023-11-18 13:44:54", "2023-11-18 16:07:38", "2023-11-18 17:55:11", tzLondon), 339 | schedule("2023-11-19", "2023-11-19 05:36:51", "2023-11-19 07:24:44", "2023-11-19 11:45:50", "2023-11-19 13:43:59", "2023-11-19 16:06:24", "2023-11-19 17:54:14", tzLondon), 340 | schedule("2023-11-20", "2023-11-20 05:38:13", "2023-11-20 07:26:24", "2023-11-20 11:46:04", "2023-11-20 13:43:06", "2023-11-20 16:05:13", "2023-11-20 17:53:20", tzLondon), 341 | schedule("2023-11-21", "2023-11-21 05:39:35", "2023-11-21 07:28:03", "2023-11-21 11:46:18", "2023-11-21 13:42:16", "2023-11-21 16:04:04", "2023-11-21 17:52:27", tzLondon), 342 | schedule("2023-11-22", "2023-11-22 05:40:56", "2023-11-22 07:29:40", "2023-11-22 11:46:33", "2023-11-22 13:41:28", "2023-11-22 16:02:58", "2023-11-22 17:51:39", tzLondon), 343 | schedule("2023-11-23", "2023-11-23 05:42:17", "2023-11-23 07:31:17", "2023-11-23 11:46:50", "2023-11-23 13:40:42", "2023-11-23 16:01:54", "2023-11-23 17:50:50", tzLondon), 344 | schedule("2023-11-24", "2023-11-24 05:43:36", "2023-11-24 07:32:52", "2023-11-24 11:47:06", "2023-11-24 13:39:59", "2023-11-24 16:00:53", "2023-11-24 17:50:06", tzLondon), 345 | schedule("2023-11-25", "2023-11-25 05:44:54", "2023-11-25 07:34:26", "2023-11-25 11:47:24", "2023-11-25 13:39:18", "2023-11-25 15:59:55", "2023-11-25 17:49:24", tzLondon), 346 | schedule("2023-11-26", "2023-11-26 05:46:11", "2023-11-26 07:35:59", "2023-11-26 11:47:42", "2023-11-26 13:38:39", "2023-11-26 15:59:00", "2023-11-26 17:48:44", tzLondon), 347 | schedule("2023-11-27", "2023-11-27 05:47:28", "2023-11-27 07:37:31", "2023-11-27 11:48:02", "2023-11-27 13:38:04", "2023-11-27 15:58:08", "2023-11-27 17:48:08", tzLondon), 348 | schedule("2023-11-28", "2023-11-28 05:48:42", "2023-11-28 07:39:00", "2023-11-28 11:48:21", "2023-11-28 13:37:30", "2023-11-28 15:57:18", "2023-11-28 17:47:33", tzLondon), 349 | schedule("2023-11-29", "2023-11-29 05:49:57", "2023-11-29 07:40:29", "2023-11-29 11:48:42", "2023-11-29 13:37:00", "2023-11-29 15:56:32", "2023-11-29 17:47:02", tzLondon), 350 | schedule("2023-11-30", "2023-11-30 05:51:10", "2023-11-30 07:41:56", "2023-11-30 11:49:03", "2023-11-30 13:36:32", "2023-11-30 15:55:49", "2023-11-30 17:46:32", tzLondon), 351 | schedule("2023-12-01", "2023-12-01 05:52:21", "2023-12-01 07:43:21", "2023-12-01 11:49:25", "2023-12-01 13:36:06", "2023-12-01 15:55:08", "2023-12-01 17:46:05", tzLondon), 352 | schedule("2023-12-02", "2023-12-02 05:53:31", "2023-12-02 07:44:44", "2023-12-02 11:49:48", "2023-12-02 13:35:44", "2023-12-02 15:54:31", "2023-12-02 17:45:42", tzLondon), 353 | schedule("2023-12-03", "2023-12-03 05:54:38", "2023-12-03 07:46:05", "2023-12-03 11:50:11", "2023-12-03 13:35:24", "2023-12-03 15:53:57", "2023-12-03 17:45:21", tzLondon), 354 | schedule("2023-12-04", "2023-12-04 05:55:46", "2023-12-04 07:47:25", "2023-12-04 11:50:35", "2023-12-04 13:35:07", "2023-12-04 15:53:26", "2023-12-04 17:45:03", tzLondon), 355 | schedule("2023-12-05", "2023-12-05 05:56:51", "2023-12-05 07:48:42", "2023-12-05 11:50:59", "2023-12-05 13:34:53", "2023-12-05 15:52:59", "2023-12-05 17:44:47", tzLondon), 356 | schedule("2023-12-06", "2023-12-06 05:57:54", "2023-12-06 07:49:57", "2023-12-06 11:51:24", "2023-12-06 13:34:41", "2023-12-06 15:52:35", "2023-12-06 17:44:35", tzLondon), 357 | schedule("2023-12-07", "2023-12-07 05:58:57", "2023-12-07 07:51:10", "2023-12-07 11:51:50", "2023-12-07 13:34:32", "2023-12-07 15:52:14", "2023-12-07 17:44:24", tzLondon), 358 | schedule("2023-12-08", "2023-12-08 05:59:59", "2023-12-08 07:52:21", "2023-12-08 11:52:16", "2023-12-08 13:34:26", "2023-12-08 15:51:56", "2023-12-08 17:44:17", tzLondon), 359 | schedule("2023-12-09", "2023-12-09 06:00:56", "2023-12-09 07:53:29", "2023-12-09 11:52:42", "2023-12-09 13:34:23", "2023-12-09 15:51:42", "2023-12-09 17:44:12", tzLondon), 360 | schedule("2023-12-10", "2023-12-10 06:01:54", "2023-12-10 07:54:35", "2023-12-10 11:53:09", "2023-12-10 13:34:23", "2023-12-10 15:51:31", "2023-12-10 17:44:11", tzLondon), 361 | schedule("2023-12-11", "2023-12-11 06:02:50", "2023-12-11 07:55:39", "2023-12-11 11:53:37", "2023-12-11 13:34:26", "2023-12-11 15:51:24", "2023-12-11 17:44:11", tzLondon), 362 | schedule("2023-12-12", "2023-12-12 06:03:42", "2023-12-12 07:56:39", "2023-12-12 11:54:05", "2023-12-12 13:34:31", "2023-12-12 15:51:20", "2023-12-12 17:44:15", tzLondon), 363 | schedule("2023-12-13", "2023-12-13 06:04:33", "2023-12-13 07:57:37", "2023-12-13 11:54:33", "2023-12-13 13:34:39", "2023-12-13 15:51:19", "2023-12-13 17:44:22", tzLondon), 364 | schedule("2023-12-14", "2023-12-14 06:05:23", "2023-12-14 07:58:33", "2023-12-14 11:55:01", "2023-12-14 13:34:50", "2023-12-14 15:51:22", "2023-12-14 17:44:30", tzLondon), 365 | schedule("2023-12-15", "2023-12-15 06:06:09", "2023-12-15 07:59:25", "2023-12-15 11:55:30", "2023-12-15 13:35:04", "2023-12-15 15:51:28", "2023-12-15 17:44:43", tzLondon), 366 | schedule("2023-12-16", "2023-12-16 06:06:53", "2023-12-16 08:00:14", "2023-12-16 11:55:59", "2023-12-16 13:35:21", "2023-12-16 15:51:38", "2023-12-16 17:44:57", tzLondon), 367 | schedule("2023-12-17", "2023-12-17 06:07:36", "2023-12-17 08:01:01", "2023-12-17 11:56:28", "2023-12-17 13:35:40", "2023-12-17 15:51:51", "2023-12-17 17:45:14", tzLondon), 368 | schedule("2023-12-18", "2023-12-18 06:08:16", "2023-12-18 08:01:44", "2023-12-18 11:56:58", "2023-12-18 13:36:02", "2023-12-18 15:52:07", "2023-12-18 17:45:34", tzLondon), 369 | schedule("2023-12-19", "2023-12-19 06:08:56", "2023-12-19 08:02:25", "2023-12-19 11:57:27", "2023-12-19 13:36:26", "2023-12-19 15:52:27", "2023-12-19 17:45:56", tzLondon), 370 | schedule("2023-12-20", "2023-12-20 06:09:30", "2023-12-20 08:03:02", "2023-12-20 11:57:57", "2023-12-20 13:36:54", "2023-12-20 15:52:51", "2023-12-20 17:46:22", tzLondon), 371 | schedule("2023-12-21", "2023-12-21 06:10:03", "2023-12-21 08:03:36", "2023-12-21 11:58:27", "2023-12-21 13:37:24", "2023-12-21 15:53:17", "2023-12-21 17:46:48", tzLondon), 372 | schedule("2023-12-22", "2023-12-22 06:10:34", "2023-12-22 08:04:07", "2023-12-22 11:58:57", "2023-12-22 13:37:56", "2023-12-22 15:53:47", "2023-12-22 17:47:19", tzLondon), 373 | schedule("2023-12-23", "2023-12-23 06:11:02", "2023-12-23 08:04:34", "2023-12-23 11:59:26", "2023-12-23 13:38:31", "2023-12-23 15:54:20", "2023-12-23 17:47:51", tzLondon), 374 | schedule("2023-12-24", "2023-12-24 06:11:28", "2023-12-24 08:04:58", "2023-12-24 11:59:56", "2023-12-24 13:39:08", "2023-12-24 15:54:57", "2023-12-24 17:48:26", tzLondon), 375 | schedule("2023-12-25", "2023-12-25 06:11:51", "2023-12-25 08:05:19", "2023-12-25 12:00:26", "2023-12-25 13:39:48", "2023-12-25 15:55:36", "2023-12-25 17:49:03", tzLondon), 376 | schedule("2023-12-26", "2023-12-26 06:12:12", "2023-12-26 08:05:37", "2023-12-26 12:00:56", "2023-12-26 13:40:30", "2023-12-26 15:56:19", "2023-12-26 17:49:43", tzLondon), 377 | schedule("2023-12-27", "2023-12-27 06:12:30", "2023-12-27 08:05:51", "2023-12-27 12:01:25", "2023-12-27 13:41:15", "2023-12-27 15:57:05", "2023-12-27 17:50:25", tzLondon), 378 | schedule("2023-12-28", "2023-12-28 06:12:45", "2023-12-28 08:06:02", "2023-12-28 12:01:54", "2023-12-28 13:42:02", "2023-12-28 15:57:54", "2023-12-28 17:51:10", tzLondon), 379 | schedule("2023-12-29", "2023-12-29 06:12:57", "2023-12-29 08:06:09", "2023-12-29 12:02:24", "2023-12-29 13:42:51", "2023-12-29 15:58:45", "2023-12-29 17:51:56", tzLondon), 380 | schedule("2023-12-30", "2023-12-30 06:13:09", "2023-12-30 08:06:14", "2023-12-30 12:02:53", "2023-12-30 13:43:42", "2023-12-30 15:59:40", "2023-12-30 17:52:45", tzLondon), 381 | schedule("2023-12-31", "2023-12-31 06:13:16", "2023-12-31 08:06:14", "2023-12-31 12:03:21", "2023-12-31 13:44:36", "2023-12-31 16:00:38", "2023-12-31 17:53:35", tzLondon), 382 | }, 383 | } 384 | --------------------------------------------------------------------------------