判断任意时刻、位置是白昼?黑夜?
问题描述:给定经纬度(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 = (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:判断白天,还是黑夜 * isDayTime ? 1 : 2其中1:白天;2:是黑夜 * @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); } } }