|
| 1 | +package astrotime |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math" |
| 6 | + "testing" |
| 7 | + "time" |
| 8 | +) |
| 9 | + |
| 10 | +type location struct { |
| 11 | + timezone string |
| 12 | + latitude float64 |
| 13 | + longitude float64 |
| 14 | +} |
| 15 | + |
| 16 | +type times struct { |
| 17 | + date string |
| 18 | + sunrise string |
| 19 | + sunset string |
| 20 | + dawn string |
| 21 | + dusk string |
| 22 | +} |
| 23 | + |
| 24 | +type test struct { |
| 25 | + times times |
| 26 | + location location |
| 27 | + error time.Duration |
| 28 | +} |
| 29 | + |
| 30 | +// test data from http://www.timeanddate.com/worldclock/sunrise.html |
| 31 | + |
| 32 | +var ( |
| 33 | + SYDNEY = location{ |
| 34 | + timezone: "Australia/Sydney", |
| 35 | + latitude: -33.86, |
| 36 | + longitude: -151.20, |
| 37 | + } |
| 38 | + STOCKHOLM = location{ |
| 39 | + timezone: "Europe/Stockholm", |
| 40 | + latitude: 59.33, |
| 41 | + longitude: -18.067, |
| 42 | + } |
| 43 | + NEWYORK = location{ |
| 44 | + timezone: "America/New_York", |
| 45 | + latitude: 40.642, |
| 46 | + longitude: 74.017, |
| 47 | + } |
| 48 | + NOVEMBER = "2014-11-01" |
| 49 | + JULY = "2015-07-01" |
| 50 | + MINUTE = time.Minute |
| 51 | + DATA = []*test{ |
| 52 | + &test{times{NOVEMBER, "05:55", "19:23", "05:29", "19:49"}, SYDNEY, MINUTE}, |
| 53 | + &test{times{NOVEMBER, "07:07", "15:55", "06:23", "16:39"}, STOCKHOLM, MINUTE}, |
| 54 | + &test{times{NOVEMBER, "07:26", "17:52", "06:58", "18:21"}, NEWYORK, MINUTE}, |
| 55 | + &test{times{JULY, "07:01", "16:57", "06:33", "17:25"}, SYDNEY, MINUTE}, |
| 56 | + &test{times{JULY, "03:37", "22:06", "02:09", "23:33"}, STOCKHOLM, MINUTE}, |
| 57 | + &test{times{JULY, "05:29", "20:31", "04:55", "21:04"}, NEWYORK, MINUTE}, |
| 58 | + } |
| 59 | +) |
| 60 | + |
| 61 | +func TestData(t *testing.T) { |
| 62 | + for _, datum := range DATA { |
| 63 | + if loc, err := time.LoadLocation(datum.location.timezone); err != nil { |
| 64 | + t.Fatalf("bad location %s", datum.location.timezone) |
| 65 | + } else { |
| 66 | + formatted := fmt.Sprintf("%s 00:00:00", datum.times.date) |
| 67 | + midnight, err := time.ParseInLocation("2006-01-02 15:04:05", formatted, loc) |
| 68 | + if err != nil { |
| 69 | + t.Fatalf("failed to parse date/timestamp '%s': %s", formatted, err) |
| 70 | + } |
| 71 | + |
| 72 | + checkDate := func(description string, timeOfDay string, calculated time.Time) { |
| 73 | + formatted := fmt.Sprintf("%s %s", datum.times.date, timeOfDay) |
| 74 | + timestamp, err := time.ParseInLocation("2006-01-02 15:04", formatted, loc) |
| 75 | + if err != nil { |
| 76 | + t.Fatalf("failed to parse date/timestamp '%s': %s", formatted, err) |
| 77 | + } |
| 78 | + actualError := math.Abs((float64)(timestamp.Sub(calculated))) |
| 79 | + if actualError > float64(datum.error) { |
| 80 | + t.Errorf("calculated -> %v, wanted -> %v %d -> (wanted < %d). location=%s date=%s", calculated, timestamp, actualError, datum.error, datum.location.timezone, datum.times.date) |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + checkDate("dawn", datum.times.dawn, NextDawn(midnight, datum.location.latitude, datum.location.longitude, CIVIL_DAWN)) |
| 85 | + checkDate("sunrise", datum.times.sunrise, NextSunrise(midnight, datum.location.latitude, datum.location.longitude)) |
| 86 | + checkDate("sunset", datum.times.sunset, NextSunset(midnight, datum.location.latitude, datum.location.longitude)) |
| 87 | + checkDate("dusk", datum.times.dusk, NextDusk(midnight, datum.location.latitude, datum.location.longitude, CIVIL_DUSK)) |
| 88 | + } |
| 89 | + |
| 90 | + } |
| 91 | +} |
0 commit comments