问题描述:给定经纬度(lon,lat),计算某时刻(utc时间戳)是白天还是黑夜?
具体代码实现如下:
package common.utils;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
/**
* @description:①给定任意utc,计算该utc对应的白昼时长。调用函数:getDayTimeLength(int utc);
* ②给定经纬度(lon,lat),计算某时刻(utc时间戳)是白天还是黑夜?
* @author: fangchangtan
* @create: 2019-01-14 15:10
*/
public class DayNightUtil {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("D");
/*
角度转换为弧度的公式
*/
private static double toRadians(double angel) {
return Math.PI * angel / 180;
}
//1.计算utc对应的是一年中的第几天;计算num_days
private static int getNdayInYear(int utc) {
int year = Integer.valueOf(dateFormat.format(utc * 1000D));
return year;
}
//2.计算b
private static double getB(int num_days) {
return 2 * Math.PI * (num_days - 1) / 365;
}
//3.计算solar_declination
private static double getSolar_Declination(int utc) {
int ndayInYear = getNdayInYear(utc);
double b = getB(ndayInYear);
double solar_declination = 0.006918 - 0.399912 * Math.cos(b)
+ 0.070257 * Math.sin(b)
- 0.006758 * Math.cos(2 * b)
+ 0.000907 * Math.sin(2 * b)
- 0.002697 * Math.cos(3 * b)
+ 0.00148 * Math.sin(3 * b);
return solar_declination;
}
/*
4.计算t:昼长计算公式
单位是小时
*/
public static double getDayTimeLength(int utc, double currentLat) {
double solar_declination = getSolar_Declination(utc);
double dayLong = 0;
dayLong = 24 - (2 / 15d) * Math.acos(Math.tan(toRadians(currentLat)) * Math.tan(solar_declination)) * (180 / Math.PI);
if (Double.isNaN(dayLong) || Double.isInfinite(dayLong)) {
if (Math.sin(toRadians(currentLat)) * Math.sin(solar_declination) > 0) {
return 24;
} else {
return 0;
}
}
return dayLong;
}
/*
获取各个时区中的正午时间差值:单位s秒
例如121度,是+240s
*/
private static int getMidDayInTimeZone(double lon) {
double value = lon % 15;
// int midday = 0;
// if (value >= 0) {
// midday = (int)((value > 7.5 ? 15 - value : value) * 4 * 60);
// } else {
// double value2 = -value;
// midday = -(int)((value2 > 7.5 ? 15 - value2 : value2) * 4 * 60);
// }
int midday = (int) ((Math.abs(value) > 7.5 ? 15 - Math.abs(value) : Math.abs(value)) * Math.signum(value) * 4 * 60);
return midday;
}
/**
* 根据经度获取时区;例如121:8;-121:-8;
*
* @param currentLon
* @return
*/
public static String caculateTimeZone(double currentLon) {
int timeZone;
int shangValue = (int) (currentLon / 15);
double yushuValue = Math.abs(currentLon % 15);
if (yushuValue <= 7.5) {
timeZone = shangValue;
} else {
timeZone = shangValue + (currentLon > 0 ? 1 : -1);
}
return timeZone >= 0 ? "+" + Math.abs(timeZone) : "-" + Math.abs(timeZone);
}
private static SimpleDateFormat dateFormatYMD = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat dateFormatHms = new SimpleDateFormat("HH:mm:ss");
/**
* func:判断白天,还是黑夜
*
* @param utc
* @param currentLon
* @param currentLat
* @return
*/
public static int judegeDayOrNight(int utc, double currentLon, double currentLat) {
//获得白昼时长
double dayTimeLength = getDayTimeLength(utc, currentLat);
System.out.println("dayTimeLength: " + dayTimeLength);
//获得与中午12:00点的时间差。单位是s
int middayOffset = getMidDayInTimeZone(currentLon);
//获得时区编号
String sTimeZone = caculateTimeZone(currentLon);
dateFormatHms.setTimeZone(TimeZone.getTimeZone("GMT" + sTimeZone));
String HHmmss = dateFormatHms.format(utc * 1000L);
String[] split = HHmmss.split(":");
double hour = 0;
if (split.length == 3) {
hour = Integer.valueOf(split[0]) + Integer.valueOf(split[1]) / 60 + Integer.valueOf(split[2]) / 3600;
}
//如果时间差值小于昼长的一半(t/2),则当前时刻为白昼,否则为黑夜
boolean isDayTime;
if ((12 + middayOffset / 3600) - dayTimeLength / 2 < hour && hour <= (12 + middayOffset / 3600) + dayTimeLength / 2) {
isDayTime = true;
} else {
isDayTime = false;
}
return isDayTime ? 1 : 2;
}
/**
* 主函数main
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
// double nday = getDayTimeLength(1484611200, 10 * i);
// System.out.println("i:" + i + "; ndayLength:" + nday);
int iDayTime = judegeDayOrNight(1484611200, 116, 10 * i);
System.out.println(iDayTime);
}
}
}
时间仓促,简单测试通过!如有不足,欢迎指正!
可以参考;http://www.cnblogs.com/hanoi/archive/2012/07/04/2576325.html