路燈監控:根據座標,時間段算出,日出日落作息16進製作息表
1、效果圖
2、代碼部分
2.1、SunRiseSet 工具類
package com.lg.sun;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 算出日出日落時間
*
* (1)先計算出從格林威治時間公元2000年1月1日到計算日天數days;
* (2)計算從格林威治時間公元2000年1月1日到計算日的世紀數t, 則t=(days+UTo/360)/36525;
* (3)計算太陽的平黃徑 : L=280.460+36000.770×t;
* (4)計算太陽的平近點角 :G=357.528+35999.050×t
* (5)計算太陽的黃道經度 :λ=L+1.915×sinG+0.020xsin(2G);
* (6)計算地球的傾角 ε=23.4393-0.0130×t;
* (7)計算太陽的偏差 δ=arcsin(sinε×sinλ);
* (8)計算格林威治時間的太陽時間角GHA: GHA=UTo-180-1.915×sinG-0.020×sin(2G) +2.466×sin(2λ)-0.053×sin(4λ)
* (9)計算修正值e: e=arcos{[ sinh-sin(Glat)sin(δ)]/cos(Glat)cos(δ)}
* (10)計算新的日出日落時間 :UT=UTo-(GHA+Long±e); 其中“+”表示計算日出時間,“-”表示計算日落時間;
* (11)比較UTo和UT之差的絕對值,如果大於0.1°即0.007小時,把UT作爲新的日出日落時間值,重新從第(2)步開始進行迭代計算,如果UTo和UT之差的絕對值小於0.007小時,則UT即爲所求的格林威治日出日落時間;
* (12)上面的計算以度爲單位,即180°=12小時,因此需要轉化爲以小時表示的時間,再加上所在的時區數Zone,即要計算地的日出日落時間爲 :T=UT/15+Zone
* 上面的計算日出日落時間方法適用於小於北緯60°和南緯60°之間的區域,如果計算位置爲西半球時,經度Long爲負數。
*/
public class SunRiseSet {
private static int[] days_of_month_1 = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
private static int[] days_of_month_2 = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
private final static double h = -0.833;//日出日落時太陽的位置
private final static double UTo = 180.0;//上次計算的日落日出時間,初始迭代值180.0
//輸入日期
//輸入經緯度
//判斷是否爲閏年:若爲閏年,返回1;若不是閏年,返回0
public static boolean leap_year(int year) {
if (((year % 400 == 0) || (year % 100 != 0) && (year % 4 == 0))) return true;
else return false;
}
//求從格林威治時間公元2000年1月1日到計算日天數days
public static int days(int year, int month, int date) {
int i, a = 0;
for (i = 2000; i < year; i++) {
if (leap_year(i)) a = a + 366;
else a = a + 365;
}
if (leap_year(year)) {
for (i = 0; i < month - 1; i++) {
a = a + days_of_month_2[i];
}
} else {
for (i = 0; i < month - 1; i++) {
a = a + days_of_month_1[i];
}
}
a = a + date;
return a;
}
//求格林威治時間公元2000年1月1日到計算日的世紀數t
public static double t_century(int days, double UTo) {
return ((double) days + UTo / 360) / 36525;
}
//求太陽的平黃徑
public static double L_sun(double t_century) {
return (280.460 + 36000.770 * t_century);
}
//求太陽的平近點角
public static double G_sun(double t_century) {
return (357.528 + 35999.050 * t_century);
}
//求黃道經度
public static double ecliptic_longitude(double L_sun, double G_sun) {
return (L_sun + 1.915 * Math.sin(G_sun * Math.PI / 180) + 0.02 * Math.sin(2 * G_sun * Math.PI / 180));
}
//求地球傾角
public static double earth_tilt(double t_century) {
return (23.4393 - 0.0130 * t_century);
}
//求太陽偏差
public static double sun_deviation(double earth_tilt, double ecliptic_longitude) {
return (180 / Math.PI * Math.asin(Math.sin(Math.PI / 180 * earth_tilt) * Math.sin(Math.PI / 180 * ecliptic_longitude)));
}
//求格林威治時間的太陽時間角GHA
public static double GHA(double UTo, double G_sun, double ecliptic_longitude) {
return (UTo - 180 - 1.915 * Math.sin(G_sun * Math.PI / 180) - 0.02 * Math.sin(2 * G_sun * Math.PI / 180) + 2.466 * Math.sin(2 * ecliptic_longitude * Math.PI / 180) - 0.053 * Math.sin(4 * ecliptic_longitude * Math.PI / 180));
}
//求修正值e
public static double e(double h, double glat, double sun_deviation) {
return 180 / Math.PI * Math.acos((Math.sin(h * Math.PI / 180) - Math.sin(glat * Math.PI / 180) * Math.sin(sun_deviation * Math.PI / 180)) / (Math.cos(glat * Math.PI / 180) * Math.cos(sun_deviation * Math.PI / 180)));
}
//求日出時間
public static double UT_rise(double UTo, double GHA, double glong, double e) {
return (UTo - (GHA + glong + e));
}
//求日落時間
public static double UT_set(double UTo, double GHA, double glong, double e) {
return (UTo - (GHA + glong - e));
}
//判斷並返回結果(日出)
public static double result_rise(double UT, double UTo, double glong, double glat, int year, int month, int date) {
double d;
if (UT >= UTo) d = UT - UTo;
else d = UTo - UT;
if (d >= 0.1) {
UTo = UT;
UT = UT_rise(UTo,
GHA(UTo, G_sun(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))),
glong,
e(h, glat, sun_deviation(earth_tilt(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo))))));
result_rise(UT, UTo, glong, glat, year, month, date);
}
return UT;
}
//判斷並返回結果(日落)
public static double result_set(double UT, double UTo, double glong, double glat, int year, int month, int date) {
double d;
if (UT >= UTo) d = UT - UTo;
else d = UTo - UT;
if (d >= 0.1) {
UTo = UT;
UT = UT_set(UTo,
GHA(UTo, G_sun(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))),
glong,
e(h, glat, sun_deviation(earth_tilt(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo))))));
result_set(UT, UTo, glong, glat, year, month, date);
}
return UT;
}
//求時區
public static int Zone(double glong) {
if (glong >= 0) return (int) ((int) (glong / 15.0) + 1);
else return (int) ((int) (glong / 15.0) - 1);
}
public static String getSunrise(BigDecimal longitude, BigDecimal latitude, Date sunTime) {
if (sunTime != null && longitude != null && latitude != null) {
double sunrise, glong, glat;
int year, month, date;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateTime = sdf.format(sunTime);
String[] rq = dateTime.split("-");
String y = rq[0];
String m = rq[1];
String d = rq[2];
year = Integer.parseInt(y);
if (m != null && m != "" && m.indexOf("0") == -1) {
m = m.replaceAll("0", "");
}
month = Integer.parseInt(m);
date = Integer.parseInt(d);
glong = longitude.doubleValue();
glat = latitude.doubleValue();
sunrise = result_rise(UT_rise(UTo,
GHA(UTo, G_sun(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))),
glong,
e(h, glat, sun_deviation(earth_tilt(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))))), UTo, glong, glat, year, month, date);
return (int) (sunrise / 15 + 8) + ":" + (int) (60 * (sunrise / 15 + 8 - (int) (sunrise / 15 + 8)));
}
return null;
}
public static String getSunset(BigDecimal longitude, BigDecimal latitude, Date sunTime) {
if (sunTime != null && latitude != null && longitude != null) {
double sunset, glong, glat;
int year, month, date;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateTime = sdf.format(sunTime);
String[] rq = dateTime.split("-");
String y = rq[0];
String m = rq[1];
String d = rq[2];
year = Integer.parseInt(y);
if (m != null && m != "" && m.indexOf("0") == -1) {
m = m.replaceAll("0", "");
}
month = Integer.parseInt(m);
date = Integer.parseInt(d);
glong = longitude.doubleValue();
glat = latitude.doubleValue();
sunset = result_set(UT_set(UTo,
GHA(UTo, G_sun(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))),
glong,
e(h, glat, sun_deviation(earth_tilt(t_century(days(year, month, date), UTo)),
ecliptic_longitude(L_sun(t_century(days(year, month, date), UTo)),
G_sun(t_century(days(year, month, date), UTo)))))), UTo, glong, glat, year, month, date);
return (int) (sunset / 15 + 8) + ":" + (int) (60 * (sunset / 15 + 8 - (int) (sunset / 15 + 8)));
}
return null;
}
/**
* 將當前時間轉換爲16進制
* @return
*/
public static String getTimeTo16(String time) {
Date date = null;
SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
// date = formatter.parse("2020-03-26 16:03:55");
date = formatter.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
//Date格式
Long t = date.getTime()/1000;
String hexString = Long.toHexString(t);
System.out.println("十六進制:"+hexString);
return hexString;
}
//將指定時間轉換成 date 格式
public static Date getTime(String time) {
Date date = null;
// SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd"); //日期
try {
date = formatter.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
2.2、MainActivity
package com.lg.sun;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class MainActivity extends AppCompatActivity {
private EditText edit_longitude, edit_latit, edit_date, date_start, date_end;
private TextView tv;
public Button btSave;
public String sunrise, sunset;
public String str1, str2;
public Double longitude, latit;
public String tvTime, SunriseSunsetDate;
public String longitudeText, latitTextHint, datetime, dateEnd, dateStart;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// test();
init();
}
private void init() {
btSave = findViewById(R.id.bt_save);
edit_longitude = findViewById(R.id.longitude);
edit_latit = findViewById(R.id.latit);
edit_date = findViewById(R.id.date);
date_start = findViewById(R.id.date_start); //起始時間
date_end = findViewById(R.id.date_end); //結束時間
tv = findViewById(R.id.tv);
findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String longit = edit_longitude.getText().toString();
String latitText = edit_latit.getText().toString();
String dateText = edit_date.getText().toString();
String startTime = date_start.getText().toString();
String endTime = date_end.getText().toString();
//經度
if (longit.isEmpty()) { //如果無輸入,則讀取默認值
longitudeText = edit_longitude.getHint().toString();
Log.d("longitudeText --->", longitudeText);
} else {
longitudeText = edit_longitude.getText().toString();
}
//緯度
if (latitText.isEmpty()) {
latitTextHint = edit_latit.getHint().toString();
Log.d("latitTextHint====》", latitTextHint);
} else {
latitTextHint = edit_latit.getText().toString();
}
if (!dateText.isEmpty()) {
datetime = edit_date.getText().toString();
Log.d("dateTime", datetime);
} else {
datetime = edit_date.getHint().toString();
Log.d("dateTime = ", datetime);
}
//起始時間
if (!startTime.isEmpty()) { //起始時間
dateStart = date_start.getText().toString();
Log.d("dateStart", dateStart);
} else {
dateStart = date_start.getHint().toString();
Log.d("dateStart = ", dateStart);
}
//結束時間
if (!endTime.isEmpty()) { //結束時間
dateEnd = date_end.getText().toString();
Log.d("date_end", dateEnd);
} else {
dateEnd = date_end.getHint().toString();
Log.d("date_end = ", dateEnd);
}
longitude = Double.parseDouble(longitudeText); //經度
latit = Double.parseDouble(latitTextHint); //緯度
//遍歷全年日期 賦值datetime ,得出 日出日落16進制時間表
getDateToYear(dateStart, dateEnd, longitude, latit);
tv.setText(tvTime);
btSave.setVisibility(View.VISIBLE);
}
});
btSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//寫入文件數據
saveDate(SunriseSunsetDate);
}
});
}
/**
* @param longitude 經度
* @param latit 緯度
* @param dateTime 日期
*/
public void earchDate(Double longitude, Double latit, String dateTime) {
//1、輸入座標、日期,計算出日出日落時間
str1 = SunRiseSet.getSunrise(new BigDecimal(longitude), new BigDecimal(latit), SunRiseSet.getTime(dateTime));
str2 = SunRiseSet.getSunset(new BigDecimal(longitude), new BigDecimal(latit), SunRiseSet.getTime(dateTime));
//2、獲取今天的日期 2020-03-26
Date time = SunRiseSet.getTime(dateTime);
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd");//Date指定格式:yyyy-MM-dd HH:mm:ss:SSS
String format = simpleDateFormat1.format(time);
//3、組成 2020-03-26 18:21:55
String morning = format + " " + str1 + ":15";
String evening = format + " " + str2 + ":25";
Log.d("sunrise",morning);
Log.d("sunset",evening);
//4、將日出日落時間--->轉成16進制
sunrise = SunRiseSet.getTimeTo16(morning);
sunset = SunRiseSet.getTimeTo16(evening);
}
private void getDateToYear(String start, String end, Double longitude, Double latit) {
Calendar calendar1 = new GregorianCalendar();
Calendar calendar2 = new GregorianCalendar();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date dayStart = df.parse(start); //按照yyyy-MM-dd格式轉換爲日期
Date dayEnd = df.parse(end);
calendar1.setTime(dayStart); //設置calendar的日期
calendar2.setTime(dayEnd);
} catch (ParseException e) {
e.printStackTrace();
}
for (; calendar1.compareTo(calendar2) <= 0; ) { //calendar1在calendar2之前就循環
String allDate = calendar1.get(Calendar.YEAR) + "-" + calendar1.get(Calendar.MONTH) + "-" + calendar1.get(Calendar.DATE);
Log.d("時間", allDate);
calendar1.add(Calendar.DAY_OF_YEAR, 1); //加1天
//算出日出日落時間
earchDate(longitude, latit, allDate);
//
Log.d("日出:", sunrise);
Log.d("日落:", sunset);
String string = "日出:"+sunrise+" 日落:"+sunset;
tvTime += string;
//
SunriseSunsetDate ="日出:"+sunrise+" 日落:"+sunset;
}
}
/**
* @param str 存儲數據
*/
public void saveDate(String str) {
String filePath = null;
boolean hasSDCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if (hasSDCard) {
filePath = Environment.getExternalStorageDirectory().toString() + File.separator + "datetime.txt";
} else {
filePath = Environment.getDownloadCacheDirectory().toString() + File.separator + "datetime.txt";
}
try {
File file = new File(filePath);
if (!file.exists()) {
File dir = new File(file.getParent());
dir.mkdirs();
file.createNewFile();
}
BufferedWriter fout = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(file,true)));
fout.write(str + "\n");
fout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.3、清單文件及頁面
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.lg.sun">
<uses-permission android:name="android.permission.INTERNET"/>
<!--寫入權限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="118.7720775600" />
<EditText
android:id="@+id/latit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="31.9788128700" />
<EditText
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="2020-03-26"
android:visibility="gone" />
<EditText
android:id="@+id/date_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="2020-01-01" />
<EditText
android:id="@+id/date_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="2020-12-31" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/bt"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:hint="查詢" />
<Button
android:visibility="invisible"
android:id="@+id/bt_save"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:hint="保存" />
</LinearLayout>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" "
android:textSize="16dp" />
</ScrollView>
</LinearLayout>