• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.support.v7.app;
18 
19 import android.text.format.DateUtils;
20 
21 /**
22  * Imported from frameworks/base/services/core/java/com/android/server/TwilightCalculator.java
23  *
24  * <p>Calculates the sunrise and sunsets times for a given location.</p>
25  */
26 class TwilightCalculator {
27 
28     private static TwilightCalculator sInstance;
29 
getInstance()30     static TwilightCalculator getInstance() {
31         if (sInstance == null) {
32             sInstance = new TwilightCalculator();
33         }
34         return sInstance;
35     }
36 
37     /** Value of {@link #state} if it is currently day */
38     public static final int DAY = 0;
39 
40     /** Value of {@link #state} if it is currently night */
41     public static final int NIGHT = 1;
42 
43     private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
44 
45     // element for calculating solar transit.
46     private static final float J0 = 0.0009f;
47 
48     // correction for civil twilight
49     private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
50 
51     // coefficients for calculating Equation of Center.
52     private static final float C1 = 0.0334196f;
53     private static final float C2 = 0.000349066f;
54     private static final float C3 = 0.000005236f;
55 
56     private static final float OBLIQUITY = 0.40927971f;
57 
58     // Java time on Jan 1, 2000 12:00 UTC.
59     private static final long UTC_2000 = 946728000000L;
60 
61     /**
62      * Time of sunset (civil twilight) in milliseconds or -1 in the case the day
63      * or night never ends.
64      */
65     public long sunset;
66 
67     /**
68      * Time of sunrise (civil twilight) in milliseconds or -1 in the case the
69      * day or night never ends.
70      */
71     public long sunrise;
72 
73     /**
74      * Current state
75      */
76     public int state;
77 
78     /**
79      * calculates the civil twilight bases on time and geo-coordinates.
80      *
81      * @param time time in milliseconds.
82      * @param latitude latitude in degrees.
83      * @param longitude latitude in degrees.
84      */
calculateTwilight(long time, double latitude, double longitude)85     public void calculateTwilight(long time, double latitude, double longitude) {
86         final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
87 
88         // mean anomaly
89         final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
90 
91         // true anomaly
92         final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2
93                 * Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly);
94 
95         // ecliptic longitude
96         final double solarLng = trueAnomaly + 1.796593063d + Math.PI;
97 
98         // solar transit in days since 2000
99         final double arcLongitude = -longitude / 360;
100         float n = Math.round(daysSince2000 - J0 - arcLongitude);
101         double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly)
102                 + -0.0069d * Math.sin(2 * solarLng);
103 
104         // declination of sun
105         double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY));
106 
107         final double latRad = latitude * DEGREES_TO_RADIANS;
108 
109         double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
110                 * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
111         // The day or night never ends for the given date and location, if this value is out of
112         // range.
113         if (cosHourAngle >= 1) {
114             state = NIGHT;
115             sunset = -1;
116             sunrise = -1;
117             return;
118         } else if (cosHourAngle <= -1) {
119             state = DAY;
120             sunset = -1;
121             sunrise = -1;
122             return;
123         }
124 
125         float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
126 
127         sunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
128         sunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
129 
130         if (sunrise < time && sunset > time) {
131             state = DAY;
132         } else {
133             state = NIGHT;
134         }
135     }
136 
137 }