前言:《三国演义》第46回草船借箭,孔明对鲁肃说“为将而不通天文,不识地利,不知奇门,不晓阴阳,不看阵图,不明兵势,是庸才也。”那么程序员也一样,作为一个全能型的程序员,须得上知天文,下知地理。现在有一个统计全球各地的用户在一天当中的每个时段的使用频率。也就是说,我大天朝的15点和蛮夷小邦的15点统计在一起,所以要解决时区问题。
解决思路是这样的,我以一个时区作为参照点,其它时区的时间根据所处的时区进行时间相加减即可。用户上传的时间是unix时间戳,是0时区的时间,就以他作为参照点。现在的问题只剩下计算出用户的时区与0时区的时间差距即可。
怎么计算这个时间差距?用户给了gps信息,是不是可以调用第三方接口?
绝对不行!!!
因为这是大数据项目,网络传输都是致命的!况且接口有次数限制,超过免费次数后要收钱,这是最棘手的。那怎么搞?何不自己解析呢,虽然程序员大多理科出身,但是高中地理可不是白读的!
我们先来复习一下高中地理经纬度的课程:
经、纬度计算:经度差与地方时差算经度——地方时每相差1小时,经度相差15°;
经纬线上长度算经纬度——1°经线长111km,1°纬线长111cosфkm(ф为纬度)。
东西经-——东(西)经度的增大方向与地球自转方向相同(反)。
计算时区只用到经度即可,下面只看经度:
经度时间计算:
①某地时区数=该地经度÷15,对商取整数部分,尾数部分四舍五入;
②区时的计算:根据各时区中央经线的地方时即为本时区区时,相邻的两个时区的区时相差1小时,即求某地区区时=已知地区时±两地时区,注意东加西减;
③地方时的计算:找出已知的经度与时间,经度差=东边地点的经度-西边地点的经度 (不跨180°经线计算,东经度为正,西经度为负值), 时间差=经度差÷地球自转角速度15°/时或1°/4分,注意加减行程时间根据东早西晚。结果若小于0,则应加24小时,日期变为昨天。
⑤日期界线有两条:自然界线即地方时0:00经线,顺着地球的自转方向,跨过它时日期应加上1天;人为界线即国际日期变更线,也就是180°经线(但两者有三处并不完全重合),顺着地球的自转方向,跨过它时日期应减去1天。注意今天与昨天范围的描述。
综上所述,我们可以自己编写一个计算时区差的程序:
//根据毫秒数得到时间
public static int getTimeByLongSecond(Long timeSecond,String gps) {
Date date = new Date(timeSecond);
//本初子午线的时间
int zeroTime = date.getHours();
String[] s_gps = gps.split(",");
//经度
int longitude = Integer.parseInt(s_gps[1].substring(0,s_gps[1].indexOf(".")));
//经度所在时间
int mytime;
//每个时区为15度,遵循东加西减原则
//东经
if(longitude > 0) {
mytime = zeroTime + longitude/15;
if(mytime > 24) {
mytime -= 24;
}
}
//西经
else
{
mytime = zeroTime - (Math.abs(longitude))/15;
if(mytime < 0 ) {
mytime += 24;
}
}
return mytime;
}
//测试一下
public static void main(String[] args) throws Exception {
System.out.println(getTimeByLongSecond(1511106631240L,"22.726868,120.905893"));
}
由于本地可以计算时区的差距,hadoop 直接挂载本地方法,用户时间的获取就方便快捷很多。