使用.NET查询日出日落时间
在WPF中,通过资源文件实现主题切换是个常见的功能,有不少文章介绍了如何实现手动切换主题。那如何实现自动切换主题呢?通常有两种机制:一是跟随系统明暗主题切换,二是像手机操作系统那样根据日出日落时间自动切换。本文将以终为始,采用倒推法一步步介绍如何使用.NET免费获取日出日落时间。
获取日出日落时间
日出日落时间会随季节及各地方经度纬度的不同而不同,此外还会受到大气折射等因素的影响。计算日出和日落时间通常需要考虑以下因素:
- 日期:具体的年、月、日,用于确定太阳相对于地球的位置。
- 经度:地理位置的经度,影响日出和日落的具体时刻。
- 纬度:地理位置的纬度,影响日出和日落时间的早晚以及全年日照时间的长短。
- 海拔:较高的海拔会影响大气折射,从而略微影响日出和日落时间。
获取日出日落时间可以使用在线API或者公式计算。最简单的方法就是付费API,其中有不少API提供免费试用(每天限额请求次数)。公式计算则不受网络限制,但准确度要低一点。
在线API
查询日出日落时间的在线API比较多,这里介绍一个无需注册,无需AccessKey的免费API
sunrise-sunset ,它是一个简单的RESTful API,只需要通过GET请求https://api.sunrise-sunset.org/json即可。最少只用提供经度和纬度参数。详细参数说明如下:
- lat(float):十进制的纬度,例如22.5559。必要参数
- lng(float):十进制的经度,例如114.0577。必要参数
- date(string):
YYYY-MM-DD格式的日期,也可以是其他的日期格式或者相对日期格式,默认值是当天。可选参数 - callback (string):JSONP回调函数名称。可选参数
- formatted (integer):0 or 1 (默认值是1)。值为0时,API响应结果中时间类型的值将按照 ISO 8601显示,并且昼长(day_length)以秒为单位显示。可选参数
- tzid (string):时区标识符。例如:UTC,Asia/Shanghai。可用的时区标识符参见支持的时区列表,如果设置了该参数,响应结果中的时间将根据该参数中时区作为基准。默认是国际协调时间UTC。可选参数
以下是获取日出日落时间最基本参数的示例和响应结果:
https://api.sunrise-sunset.org/json?lat=23.1181&lng=113.2539
由于参数只提供了最基本的纬度和经度信息,响应结果默认是当天的日出日落信息,并且数据进行了默认的格式化,所有的时间都是以UTC作为基准且没有进行夏令时调整。
{
"results": {
"sunrise": "9:48:35 PM",
"sunset": "10:58:28 AM",
"solar_noon": "4:23:32 AM",
"day_length": "13:09:53",
"civil_twilight_begin": "9:25:53 PM",
"civil_twilight_end": "11:21:10 AM",
"nautical_twilight_begin": "8:57:33 PM",
"nautical_twilight_end": "11:49:30 AM",
"astronomical_twilight_begin": "8:28:26 PM",
"astronomical_twilight_end": "12:18:37 PM"
},
"status": "OK",
"tzid": "UTC"
}
以下是提供了时区参数的请求示例和响应结果:
https://api.sunrise-sunset.org/json?lat=23.1181&lng=113.2539&tzid=Asia/shanghai
响应结果中的时间都是以东八区作为基准:
{
"results": {
"sunrise": "5:48:35 AM",
"sunset": "6:58:28 PM",
"solar_noon": "12:23:32 PM",
"day_length": "13:09:53",
"civil_twilight_begin": "5:25:53 AM",
"civil_twilight_end": "7:21:10 PM",
"nautical_twilight_begin": "4:57:33 AM",
"nautical_twilight_end": "7:49:30 PM",
"astronomical_twilight_begin": "4:28:26 AM",
"astronomical_twilight_end": "8:18:37 PM"
},
"status": "OK",
"tzid": "Asia/shanghai"
}
公式计算日出日落时间
除了通过在线API获取日出日落时间,还可以通过天文算法计算,这些算法通常基于地球自转、公转、地球椭圆轨道、黄赤交角以及大气折射等因素。下边这个公式没有涉及大气折射因素,但依旧有较高的精度。
前边通过在线API获取的时间与多个付费API比较结果一致,姑且以在线API作为参照基准,此处公式计算结果偏差有几分钟。
计算机一般采用弧度制,公式为:
日出时间=(180+时区*15-经度-arccos(tan(10547π/81000*cos(2π*(日期+9)/365))*tan(纬度*π/180))*180/π)/15
日落时间=(180+时区*15-经度+arccos(tan(10547π/81000*cos(2π*(日期+9)/365))*tan(纬度*π/180))*180/π)/15
请注意,使用这些公式时应确保:
- 日期:通常表示为距离当年1月1日的天数。(例如:1月1日表示日期=1,2月15日表示日期=46)
- 时区:以小时为单位,东时区为正,西时区为负。(例如:我国时区为东八区,时区=8)
- 经度、纬度:以度为单位,东经、北纬为正,西经、南纬为负。(例如:东经100º13′30″,北纬35º20′15″,则表示经度=100.225,纬度=35.3375;西经25º15′54″,南纬50º45′18″,则表示经度=-25.265,纬度=-50.755)
经度纬度查询
不管是在线API还是公式计算的方式获取日出日落时间,都需要输入经度纬度信息,直接获取经度纬度信息并不容易。但是,我们可以轻松地获取到另一个和地理位置有关的网络信息:IP地址。然后通过IP地址与地理位置的映射(包括经度纬度)得到想要的信息。通常可以通过在线API服务或者离线数据库完成IP地址到经度纬度信息地转换。
在线API服务
除了百度地图,还有许多其他提供IP到经纬度转换的服务,如 MaxMind GeoIP、IPinfo.io、IPGeolocation.io 等。这些服务通常提供免费和付费版本,使用方式类似,通常包括注册、获取API密钥、按照文档指示构造请求URL并解析响应。
使用本地数据库或API库
如果需要在本地处理大量IP到经纬度的转换,或者希望减少对外部API的依赖,可以考虑使用如IP2Location、GeoIP等提供的数据库产品。这些数据库包含了IP地址与地理位置信息的映射,可以直接在本地进行查询,无需每次请求都通过网络发送到第三方服务器。
IP2Location
IP2Location提供了付费的版本IP2Location和免费版本IP2Location Lite,他们的区别在于付费版本数据更多更准确,详细对比参见版本比较。IP2Location Lite提供了CSV和Bin两种格式的数据库,并根据数据丰富性分为多个不同的版本。这里以包含了国家、地区、城市、经度纬度、邮政编码、时区的DB11为例介绍如何使用。
首先,下载IP2LOCATION-LITE-DB11.BIN数据库文件,然后在项目中通过Nuget引用IP2Location.IPGeolocation包。调用代码如下:
Component oIP2Location = new Component();
IPResult oIPResult = new IPResult();
oIP2Location.Open(@"C:\Users\John\Downloads\IP2LOCATION-LITE-DB11.BIN");
oIPResult = oIP2Location.IPQuery("120.236.111.205");
if (oIPResult.Status == "OK")
{
Console.WriteLine(oIPResult.Latitude); //23.12736
Console.WriteLine(oIPResult.Longitude); //113.2646
Console.WriteLine(oIPResult.CountryLong); //"China"
Console.WriteLine(oIPResult.CountryShort); //"CN"
Console.WriteLine(oIPResult.Region); //"Guangdong"
Console.WriteLine(oIPResult.City); //"Guangzhou"
Console.WriteLine(oIPResult.TimeZone); //"+08:00"
Console.WriteLine(oIPResult.ZipCode); //"510140"
}
oIP2Location.Close();
GeoIP
GeoIP也是提供了付费版本GeoIP2和免费版本GeoLite2,付费版本除了数据更多更准确,更新频率也更高一些。GeoLite2也是提供了CSV和mmdb两种格式数据库,并根据内容不同分为GeoLite2 Country、GeoLite2 City、GeoLite2 ASN三个版本,详细信息参见GeoLite2 IP元数据数据库对比。这里以GeoLite2 City.mmdb为例介绍如何使用。
首先,下载GeoLite2-City.mmdb数据库文件,然后在项目中通过Nuget引用MaxMind.GeoIP2包。调用代码如下:
using (var reader = new DatabaseReader(@"C:\Users\John\Downloads\GeoLite2-City.mmdb"))
{
var city = reader.City("120.236.111.205");
Console.WriteLine(city.Country.IsoCode); // "CN"
Console.WriteLine(city.Country.Name); // "China"
Console.WriteLine(city.Country.Names["zh-CN"]); // "中国"
Console.WriteLine(city.MostSpecificSubdivision.Name); // null
Console.WriteLine(city.MostSpecificSubdivision.IsoCode); // null
Console.WriteLine(city.City.Name); // null
Console.WriteLine(city.Postal.Code); // null
Console.WriteLine(city.Location.Latitude); // 34.7732
Console.WriteLine(city.Location.Longitude); // 113.722
}
不太幸运的是,这个IP并没有查询到城市信息,只返回了国家信息,因此结果中的经度纬度信息也不准确。国内所有未查询到城市信息的IP,返回都是这个经度纬度信息(通过百度地图查询到该坐标处于郑州)。但是GeoIP2的在线服务查询到了准确的城市及经度纬度信息。
最新(2024-5-7下载)的GeoLite2数据库中查询到20071个中国的IP网段,其中有11270条是未查询到具体城市信息的记录。
IP2Location Lite和GeoLite2数据库的覆盖情况并没有一个确切的数据,两个数据库结合使用或许能提高查询命中率。
获取公网IP
自己的公网IP非常容易获取,比如使用在线IP查询网站,或者搜索引擎中搜索关键词“IP”,搜索结果中通常会显示自己的公网IP地址。在程序中也可以通过特定API获取公网IP,比如下边这个API:
Get https://ipecho.net/plain
小结
在计算日出日落和经度纬度信息的环节都介绍了在线API服务和离线获取两种方式。在线API服务的优势是结果更准确,离线方式的优势是无需依赖第三方服务,缺点就是结果没那么精准。当然,在根据日出日落时间实现自动切换主题的需求上,准确度要求没那么高,离线计算方式足矣。
使用.NET查询日出日落时间的更多相关文章
- C#可用的日出日落时间类
一个现成代码的公共类库,复制下来作为一个类文件就可以调用了.一般不需要了解实现过程,各种数学公式太麻烦. 调用方法: SunTimeResult result = SunTimes.GetSunTim ...
- DB2查询当前时间与指定时间的时间差(相隔的秒数)
DB2查询当前时间与指定时间的时间差(相隔的秒数). 例子:“拍品表 auct_item”中有个“结束时间 end_date”的字段,求结束时间与当前时间的间隔秒数. select (DAYS(a. ...
- Linux如何修改和查询时区时间
Linux如何修改和查询时区时间 我在日常工作中,最近遇到了在解压源码包的时候,提示时间比较旧,解压安装出现问题.原因是,租用的vps所在时区和自己所需要的时区不一致,于是在网上找了相关资料.并亲自实 ...
- Confluence 6 配置数据库查询超时时间
如果数据库的查询时间太长同时你的应用程序显示没有响应,你可以配置数据库的查询超时时间.在默认情况下 Confluence 没有超时时间.希望配置数据库查询超时时间,在你的测试服务器上进行下面的操作: ...
- mysql查询根据时间排序
表数据: mysql查询根据时间排序,如果有相同时间则只查询出来一个 所以需要再判断,如果时间相同,则根据id进行降序排序
- MySql 简单统计查询消耗时间脚本
MySql 简单统计查询消耗时间脚本 by:授客 QQ:1033553122 drop procedure if exists selectTime; delimiter; create proced ...
- Oracle11g 查询长时间运行的SQL
一.大量的查询 某些时候,因为SQL的问题,导致数据库的session大量积压,服务器的磁盘读增大,CPU使用率剧增.一般这种SQL,都是一些全表扫描.多表关联.报表或者排序类的SQL.这中情况很有可 ...
- sql查询关于时间的一些汇总
今天的所有数据:select * from 表名 where DateDiff(dd,datetime类型字段,getdate())=0 昨天的所有数据:select * from 表名 where ...
- dig指定服务器查询域名解析时间
time=$(dig @8.8.8.8 baidu.com | grep Query | awk '{print $4}') echo $time 一 nslookup指定服务器查询域名解析时间 ro ...
- Sql server 查询指定时间区间工作日数、休息日数等日期操作
1.查询指定时间区间的工作日 这个主要难点是法定节假日,国家的法定节假日每年都不一样,还涉及到调休,所以我们设计一个假日表.主要字段有年份,类型(是否调休),假期日期.如下: CREATE TABLE ...
随机推荐
- Scala 中断循环
一.采用 Scala 自带的函数,退出循环 1 package com.atguigu.break 2 3 object TestBreak { 4 import scala.util.control ...
- 实例演示如何使用CCE XGPU虚拟化
本文分享自华为云社区<CCE XGPU虚拟化的使用>,作者: 可以交个朋友. 一 背景 在互联网场景中,用户的AI训练和推理任务对GPU虚拟化有着强烈的诉求.GPU卡作为重要的计算资源不管 ...
- #主席树,fread,fwrite#洛谷 1972 [SDOI2009]HH的项链
题目 分析 维护每个位置的后继,问题转换为后继在区间外的位置的个数, 但是这题太卡常了,所以我就加了fread和fwrite 其实树状数组的解法我也写过了 代码 #include <cstdio ...
- #主席树,离散,扫描线#洛谷 3168 [CQOI2015]任务查询系统
题目 分析 询问显然得预处理,考虑以优先级建权值线段树, 将优先级离散化处理,那么第\(k\)大可以用线段树来求 那任务怎么办,考虑时间用扫描线的方法,按照时间建新的线段树 把任务分成两部分,在两端差 ...
- 使用OHOS SDK构建lua
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/lua/lua.git ...
- 开源机密计算平台:蓬莱-OpenHarmony
演讲嘉宾 | 杜 东 回顾整理 | 廖 涛 排版校对 | 李萍萍 嘉宾简介 杜东,上海交通大学助理研究员.中国计算机学会CCF会员,ACM会员.研究兴趣为操作系统与体系结构.服务器无感知(Se ...
- 面试必备HashMap源码解析
Map的实现有很多种,而HashMap算是最经典的实现之一了吧,在平时的使用中,绝大部分的使用也都是HashMap,我记得刚入行那会,脑子里对Map的使用就是Map map = new HashMap ...
- 如何获取华为运动健康服务授权码并调用Rest API访问数据?
华为运动健康服务(HUAWEI Health Kit)允许三方生态应用在获取用户授权后,通过REST API接口访问数据库,读取华为和生态伙伴开放的运动健康数据或写入数据到华为运动健康服务,为用户提供 ...
- js获取select标签的 value 和 text
<select name="" id="test"> <option value="a1">yi</optio ...
- openGauss3.1.0企业版HA环境部署测试
前言 openGauss 是华为开源的一款高性能关系型数据库,这两年感觉 pg 系的数据库在国内慢慢火起来了,pg 的操作还是跟 mysql 和 oracle 略有差距,还得慢慢学,先从部署开始吧.对 ...