判断任意时刻、位置是白昼?黑夜?

问题描述:给定经纬度(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);
        }

    }
}
原文地址:https://www.cnblogs.com/yangyuxiaozi/p/3774718.html