这是一个用来说明火星历法和地球历法换算方法的文档。

火星历法的说明:火星历法@星际移民之书

火星和地球之间,一个非常最要的联系是地球上 UTC 时间的 2000 年 01 月 06 日,这一天的午夜正好是火星上零度经线的午夜。因此,一个比较好的算法是,以这一天为基准。

最终要达成的目的是,给定一个地球上的 UTC 日期和时间,我们能够换算到火星的零度经线的日期和时间。

Prep


In [91]:
import math
import datetime ## to deal with dates
from IPython.display import Image

火星历法

火星闰年

火星的历法采用 Darian Calendar,这种历法中,年分为平年和闰年,其中平年 668 天,闰年 669 天。计算闰年的方法为


In [92]:
# will return True if a year is a leap year on Mars
def is_leap_year_mars(year):
    if year % 3000 == 0:
        return False
    elif year % 1000 == 0:
        return True
    elif year % 100 == 0:
        return False
    elif (year % 2 != 0) or (year % 10 == 0):
        return True
    else:
        return False

所以,一年的总天数,我们可以这样表示


In [93]:
def total_days(year):
    return 668 + is_leap_year_mars(year)

测试一下这两个函数。


In [94]:
print total_days(10)
print total_days(11)


669
669
任意某年某月的天数,用以下函数进行计算:

In [95]:
def month_total_days(year,month):
    if is_leap_year_mars(year):
        if month == 24:
            return 28
        else:
            return 27 + ((month)%6!=0)
    if not is_leap_year_mars(year):
        return 27 + ((month)%6!=0)

In [96]:
print month_total_days(1,24)


28

火星月日的计算

火星上一年共分为 24 个月,6 个月一组分为四组,每组的前五个月是 28 天,第六个月是 27 天,但是倘若当年是闰年,则第 24 个月包含 28 天。因此如果给定一个小于当年年份总天数的天数,我们可以计算对应的是当年的哪个日期。


In [97]:
# returns the month and date given a number of dates.
# calendar_date(a number of days, which year we are calculating)
def calendar_date(days, year):
    if days > total_days(year):
        return "Error! Given number of days are more than the overall possible days of the year."
    else:
        for month in range(24):
            month = month + 1.0
            if month == 24:                                       # the last month is special because it might change with year
                return tuple([int(month),int(days)])                      # using tuple to avoid modification
            elif ((month) < 24) & ( (days) < (27 + 1 + (month%6!=0))):   # the condition for days makes sure that days is never larger than days in that month
                return tuple([int(month),int(days)])
                break
            elif ((month) < 24) & ((days) > (27 + (month%6!=0))):
                days = days - 27 - ((month)%6!=0)
                continue
            else:
                return "Unhandled in calendar_date(days, year) function! (inner for loop) "
                break

测试此函数


In [98]:
print "the 669th day of the tenth year is (month:{}, day:{})".format(calendar_date(669,10)[0],calendar_date(669,10)[1])
print "the 669th day of year one is (month:{}, day:{})".format(calendar_date(669,1)[0],calendar_date(669,1)[1]) # should return error message
print "the 1000th day of year one is (month:{}, day:{})".format(calendar_date(1000,1)[0],calendar_date(1000,1)[1]) # should return error message
print "the 30th day of year one is (month:{}, day:{})".format(calendar_date(30,1)[0],calendar_date(30,1)[1])


the 669th day of the tenth year is (month:24, day:28)
the 669th day of year one is (month:24, day:28)
the 1000th day of year one is (month:E, day:r)
the 30th day of year one is (month:2, day:2)

In [99]:
calendar_date(1,1)


Out[99]:
(1, 1)

可以看到函数正确的返回了月日以及错误信息。

火星日

火星上的一天,或者说称为一个火星太阳日,共有 24 小时 39 分钟 35.244 秒,共计 88775.2 秒,但是历法中为了大家使用方便,仅仅使用 88775 秒。火星日和地球上 24 小时的比值是 1.02748842593 . 因此我们可以定义一个常数,即用来转换地球日和火星日的常数:


In [100]:
m2e = 88775.0/86400  # the ratio of mars sol day and earth 24-hour day or we can use 1.027491252
print m2e


1.02748842593

火星元年与校准日期

火星元年的开始对应于地球的 1970 年 4 月 28 日,而校准日期为地球 UTC 时间的 2000 年 01 月 06 日午夜,也就是最后可以被称作 6 日的那个时间点,此时火星的零度经线也正好对应某个火星日的午夜。

通过计算得知,在地球上 1970 年 04 月 28 日和 2000 年 01 月 06 日之间共有 10846 个地球日,考虑到我们的计算的校准时间是在 6 日深夜,所以这个计算中包含了 6 日当天。转换成火星日:


In [101]:
mars_sol_day_coor = math.floor(10846/m2e)
print mars_sol_day_coor


10555.0

注意到 floor() 里面的除法不能整除,是因为火星元年并非是从 1970 年 04 月 28 日的 0 点开始的,所以我们这里扔掉后面的小数位。

我们需要计算的是,校准日期对应的是火星历法中的哪个日期。现在我们已经知道了 mars_sol_day_coor 给出了元年开始和校准日期之间的火星日的数目。而这个数目恰好是 15 年多余 534 火星日。(第 16 年并非闰年。)然后我们可以通过之前的计算日期的函数得出 534 火星日对应的是火星纪年第 16 年的什么日期。


In [102]:
calendar_date(534,16)


Out[102]:
(20, 5)

也就是说,是火星历法中的第 20 个月的 5 日,即小寒月 5 日。

这样我们也可以得知火星元年对应的地球历的日期和时间。上面我们的计算中,我们得知


In [103]:
Image(url="https://raw.githubusercontent.com/InterImm/marsCalendar/master/py/assets/timeCalibration.png")


Out[103]:

由于我们的计算中,只考虑了 mars_sol_day_coor = 10555.0 个火星日,所以我们现在换算回地球日,并且从地球日历的 2000-01-06 (包含)反推回地球日历中所对应的日期和时间。 这些火星日对应的地球日的数目


In [104]:
earth_day_coor = mars_sol_day_coor * m2e
print earth_day_coor


10845.1403356

简单的数学可以得知元年对应的地球日历是

1970 年 04 月 28 日,21:17:30 ## 第一版的计算结果是 1970.0,4.0,28.0,20.0 + 38.0/60 + 55.0/3600 为了与后面 2000 - 01 - 06 午夜的协调,放弃此版本。

历法换算

历法换算有一个比较重要的转折点,就是 2012 年 07 月 01 日,因为这一天增加了 35 + 32.184 秒的闰秒。因此程序计算需要一个判断给定的地球历法是否大于此日期的函数。

为了换算方便,我们把所有给定的日期都换算成 Julian Date.


In [105]:
def julian_days(cdate):     # Input is calendar date with the list format [year like 2014, month like 07, day like 24, hours like 12, min]
    y = cdate[0]
    m = cdate[1]
    d = cdate[2]
    h = cdate[3] + cdate[4]/60.0
    
    return 367.0 * y - math.floor(7.0 * ( y * 1.0 + math.floor( ( m*1.0 + 9.0 )/12.0 ) )/4.0 ) - math.floor(3.0*(math.floor( (y*1.0 + (m*1.0 - 9.0)/7.0 )/100.0 ) + 1.0 )/4.0 ) + math.floor( 275.0 * m / 9.0 ) + d*1.0 + 1721028.5 + h / 24.0                  ## Using an equation from http://scienceworld.wolfram.com/astronomy/JulianDate.html

作为测试,我们知道 UNIX 系统里面使用的,1970-01-01,00:00:00 的时刻对应的时间是 2 440 587.5 个 julian days,用我们这个函数给出来的结果呢?


In [106]:
julian_days([1970,1,1,0,0])


Out[106]:
2440587.5

与已知结果是一致的。需要强调的是,这个计算在使用的时候,需要先把分钟和秒换算成小数点的小时数目。

因此在需要计算日期之间的天数差的话,只需要使用此函数转换成 julian days,然后计算差值即可。一个比较方便的换算是,计算出火星元年对应的 julian days,然后以后的换算就通过将地球历跟火星元年的地球的天数,然后换算成火星日的数目,然后利用上面计算火星历的方法,获得火星上的日期。

火星元年(1970 年 04 月 28 日,20:38:55)对应的地球历法中的 julian days 是


In [107]:
julian_coor_earth = julian_days([1970.0,4.0,28.0,21.0,17.0 + 30.0/60])  # 1970.0,4.0,28.0,20.0 + 38.0/60 + 55.0/3600
print julian_coor_earth


2440705.38715

因此我们可以定义这样一个函数,来计算地球日的数目


In [108]:
def julian_diff(datelist):
    return julian_days(datelist) - julian_coor_earth

In [109]:
julian_diff([1970.0,4.0,28.0,21,17])


Out[109]:
-0.000347222201526165

同样我们可以定义换算出火星日数目的函数


In [110]:
def mars_days_origin(datelist):
    return math.floor(julian_diff(datelist)/m2e)

测试此函数


In [111]:
mars_days_origin([1970.0,4.0,28.0,21,17])


Out[111]:
-1.0

如果要计算当日的时间,需要用到被 floor 掉的小数部分。


In [112]:
def mars_days_origin_rem(datelist):
    return julian_diff(datelist)/m2e - math.floor(julian_diff(datelist)/m2e)

然后我们可以利用 calendar_date() 函数给出对应的火星历的日期。


In [113]:
def earth2mars_calendar(datelist):
    year = 1
    md = mars_days_origin(datelist)
    while (md > (668.0 + is_leap_year_mars(year) ) ):
        year = year + 1
        md = md - 668 - is_leap_year_mars(year)
    return [year,calendar_date(md+1,year-1)]

In [114]:
earth2mars_calendar([1970,4,29,20,0])


Out[114]:
[1, (1, 1)]

In [115]:
earth2mars_calendar([1971,4,30,23,23])


Out[115]:
[1, (13, 24)]

那么这个函数给出的地球上 2000 年 01 月 06 日午夜必须是火星历的 0016 年小寒月 05 日。下面是测试


In [116]:
earth2mars_calendar([2000,1,6,0,0])


Out[116]:
[16, (19, 25)]

火星时刻

火星上采用的计时方法是 24 小时外加附加时间。火星上一个太阳日是 24 hours, 39 minutes, and 35.244 seconds,其中的 39'35.244'' 被归为附加时间。

将小数点的时间换算为时刻需要得知一天共有多少秒:


In [117]:
24 * 3600 + 39 * 60 + 35.244


Out[117]:
88775.244

In [118]:
def mday2time(remainder):                         # input a number smaller than 1.
    if remainder > 1:
        return "Input should a fraction of a martian day, i.e., a number smaller than 1."
    else:
        total_sec = 24.0 * 3600 + 39.0 * 60 + 35.244  # total seconds in a martian day
        seconds = remainder * total_sec                   # total seconds of the given input
        hour = int(math.floor(seconds / 3600.0))               # hour
        min = int(math.floor( (seconds - 3600.0 * hour)/60 ) )  # min
        sec = int(seconds - hour * 3600.0 - min * 60.0)
        
        return [hour, min, sec]

In [119]:
mday2time(0.3)


Out[119]:
[7, 23, 52]

利用 mars_days_origin_rem() 函数可以计算地球 UTC 日期对应的火星零度经线当天的火星时间。


In [120]:
def earth2mars_calendar_time(datelist):
    return mday2time(mars_days_origin_rem(datelist))

In [121]:
earth2mars_calendar_time([1971,4,30,23,59])


Out[121]:
[7, 10, 15]

In [122]:
earth2mars_calendar_time([2000,1,6,0,0])


Out[122]:
[24, 39, 35]

In [123]:
mars_days_origin_rem([2000,1,6,0,0])


Out[123]:
0.9999999997999112

In [124]:
10846/m2e


Out[124]:
10555.836665727966

In [125]:
earth2mars_calendar_time([1970.0,4.0,28.0,20,55])


Out[125]:
[24, 17, 5]

In [126]:
month_name = ('春分','清明','谷雨','立夏','小满','芒种','夏至','小暑','大暑','立秋','处暑','白露','秋分','寒露','霜降','立冬','小雪','大雪','冬至','小寒','大寒','立春','雨水','惊蛰')
week_name = ('六','日','一','二','三','四','五')
def chinese_character(mars_calendar,mars_time):
    calendar_str = "火历"+str(mars_calendar[0])+"年 "+str(month_name[mars_calendar[1][0]-1])+"月"+str(int(mars_calendar[1][1]))+"日"+"星期"+str(week_name[int(mars_calendar[1][1])%7])
    if mars_time[0] < 24.0:
        if mars_time[2] < 10:
            return calendar_str+" "+str(int(mars_time[0]))+":"+str(int(mars_time[1]))+":0"+str(int(mars_time[2]))
        else:
            return calendar_str+" "+str(int(mars_time[0]))+":"+str(int(mars_time[1]))+":"+str(int(mars_time[2]))
    else:
        if mars_time[2] < 10:
            return calendar_str+" +"+str(int(mars_time[1]))+":0"+str(int(mars_time[2]))
        else:
            return calendar_str+" +"+str(int(mars_time[1]))+":"+str(int(mars_time[2]))

In [127]:
print chinese_character([16, (20, 4.0)],[24.0, 17.0, 5.240289495923207])


火历16年 小寒月4日星期三 +17:05

In [128]:
print chinese_character([1, (1, 1.0)],[7.0, 10.0, 15.070938780310826])


火历1年 春分月1日星期日 7:10:15

In [129]:
print chinese_character(earth2mars_calendar([2014,10,13,23,52]),earth2mars_calendar_time([2014,10,13,23,52]))


火历24年 立冬月10日星期二 16:19:30

测试地球历法到火星历法的换算

测试时刻的输出。


In [130]:
earth2mars_calendar_time([2000,1,6,0,0])


Out[130]:
[24, 39, 35]

In [131]:
earth2mars_calendar_time([2014,10,13,21,1])


Out[131]:
[13, 28, 30]

由 Mars24 给出的 AMT 是 12:46,换算成我们的计时方法是


In [132]:
test11 = (12.0 + 46.0/60)/24 * (24.0*m2e)
print str(test11) + "h" + "=" + str(int(math.floor(test11))) + ":" + str(int((test11 - math.floor(test11))*60))


13.1176022377h=13:7

这样看来相差了大约 21 分钟的时间。


In [133]:
earth2mars_calendar_time([2020,1,1,0,0])


Out[133]:
[17, 20, 0]

In [134]:
test12 = (16.0 + 23.0/60) * m2e
print str(test12) + "h" + "=" + str(int(math.floor(test12))) + ":" + str(int((test12 - math.floor(test12))*60))


16.8336853781h=16:50

为了测试方便,定义一个 Mars24 的 24 小时计时方法与我中心的计时方法的换算的函数。


In [135]:
def mars242iic(hour):
    print str(hour) + "h" + "=" + str(int(math.floor(hour))) + ":" + str(int((hour - math.floor(hour))*60))

In [136]:
mars242iic(test12)


16.8336853781h=16:50

测试多个年份看看是不是“误差”随着时间推移增加。如果是的话,很可能是某个常数用的不对或者那个变量的精度有问题。

2030 年 1 月 1 日


In [137]:
earth2mars_calendar_time([2030,1,1,0,0])


Out[137]:
[24, 1, 15]

Mars24 给出的是 22:40


In [138]:
mars242iic((22.0+40.0/60)*m2e)


23.2897376543h=23:17

差距为


In [139]:
earth2mars_calendar_time([2030,1,1,0,0])[0] + earth2mars_calendar_time([2030,1,1,0,0])[1]/60 - (22.0+40.0/60)*m2e


Out[139]:
0.7102623456790127

In [140]:
def mars24_iic_diff(datelist,result):
    print earth2mars_calendar_time(datelist)[0] + earth2mars_calendar_time(datelist)[1]/60 - (result[0]*1.0 + result[1]*1.0/60.0)*m2e

In [141]:
mars24_iic_diff([2020,1,1,0,0],[16,23])


0.166314621914

In [142]:
mars24_iic_diff([2021,1,1,0,0],[21,22])


0.0459972993827

In [143]:
mars24_iic_diff([2022,1,1,0,0],[2,29])


0.448403742284

In [144]:
mars24_iic_diff([2023,1,1,0,0],[8,26])


0.334847608025

In [145]:
mars24_iic_diff([2030,1,1,0,0],[22,40])


0.710262345679

In [146]:
mars24_iic_diff([2040,1,1,0,0],[5,35])


0.263189621914

In [147]:
mars24_iic_diff([2050,1,1,0,0],[11,51])


0.824262152778

这样看趋势似乎并不是一直增大,而是在不停的浮动。这样就怀疑是由于 Mars24 AMT 采用的当地的太阳日的时刻,而我们采用的是平均太阳日。如何验证呢?可以考虑一个火星年的周期来看看。 2021 - 02 -07 到 2022 - 12 - 26 正好是一个火星年的周期。

Aug 25 2021 -Jul 12 2023

Feb 24 2022 Jan 12 2024

Jul 21 2022 Jun 07 2024


In [148]:
mars24_iic_diff([2021,2,7,0,0],[21,36])
mars24_iic_diff([2022,12,26,0,0],[12,28])


-0.19375
0.190644290123

In [149]:
mars24_iic_diff([2021,8,25,0,0],[13,49])
mars24_iic_diff([2023,7,12,0,0],[5,19])


-0.196465084877
0.537186535494

In [150]:
mars24_iic_diff([2022,2,24,0,0],[16,19])
mars24_iic_diff([2024,1,12,0,0],[7,10])


0.234813850309
-0.363667052469

In [151]:
mars24_iic_diff([2022,7,21,0,0],[17,55])
mars24_iic_diff([2024,6,7,0,0],[8,46])


-0.409167631173
-0.00764853395062

由此可见并非是因为太阳日的变化造成的。但是所有的浮动都在一个小时之内。

从火星历法到地球历法

从火星历转换回地球历法,思路是,先把火星历换算成地球历法中距离火星元年的 julian days,然后我们已知火星元年对应的 julian days 是由 julian_coor_earth 变量给出的,这样就可以计算火星历法中的某天某时刻对应的地球历法中的 julian days,最后由此计算地球历法的时间。

下面 mars_date2days() 函数给出火星日的数目。


In [152]:
def mars_date2days(datelist):   # given a date, calculate the days since the first calendar day. [martian year, month in number, day, hour, min]
    y = datelist[0]
    m = datelist[1]
    d = datelist[2]
    h = datelist[3] * 1.0
    min = datelist[4] * 1.0
    
    year = 1
    days = 0
    while year < y:
        days = days + 668 + is_leap_year_mars(year)
        year = year + 1
        
    month = 1
    while month < m:
        days = days + 27 + (month%6!=0)
        month = month + 1
        
    days = days + d + ( h + min/60.0 )/(24*m2e)
    
    return days - 1

In [153]:
mars_date2days([1,1,1,0,0])


Out[153]:
0.0

In [154]:
mars_date2days([1,1,1,24,39])


Out[154]:
0.9996057448606026

In [155]:
mars_date2days([12,24,28,24,39.5])


Out[155]:
8023.999943677837

火星日对应的 julian days 可以直接通过乘以 m2e 来换算。


In [156]:
mars_date2days([1,1,1,24,39]) * m2e + julian_coor_earth


Out[156]:
2440706.414236111

获得了 julian day,下一步就只需要将这个对应的日期找出来就好了。

我从 这里 找到了一个现成的函数,作者使用 BSD2 协议,正好我们可以直接拿来用或修改。


In [157]:
def ipart(x):
    """Return integer part of given number."""
    return math.modf(x)[1]

def jd2gcal(jd1,jd2):
    """Julian date to Gregorian calendar date and time of day.

    The input and output are for the proleptic Gregorian calendar,
    i.e., no consideration of historical usage of the calendar is
    made.

    Parameters
    ----------
    jd1, jd2: int
        Sum of the two numbers is taken as the given Julian date. For
        example `jd1` can be the zero point of MJD (MJD_0) and `jd2`
        can be the MJD of the date and time. But any combination will
        work.

    Returns
    -------
    y, m, d, f : int, int, int, float
        Four element tuple containing year, month, day and the
        fractional part of the day in the Gregorian calendar. The first
        three are integers, and the last part is a float.

    Examples
    --------
    >>> jd2gcal(*gcal2jd(2000,1,1))
    (2000, 1, 1, 0.0)
    >>> jd2gcal(*gcal2jd(1950,1,1))
    (1950, 1, 1, 0.0)

    Out of range months and days are carried over to the next/previous
    year or next/previous month. See gcal2jd for more examples.

    >>> jd2gcal(*gcal2jd(1999,10,12))
    (1999, 10, 12, 0.0)
    >>> jd2gcal(*gcal2jd(2000,2,30))
    (2000, 3, 1, 0.0)
    >>> jd2gcal(*gcal2jd(-1999,10,12))
    (-1999, 10, 12, 0.0)
    >>> jd2gcal(*gcal2jd(2000, -2, -4))
    (1999, 9, 26, 0.0)

    >>> gcal2jd(2000,1,1)
    (2400000.5, 51544.0)
    >>> jd2gcal(2400000.5, 51544.0)
    (2000, 1, 1, 0.0)
    >>> jd2gcal(2400000.5, 51544.5)
    (2000, 1, 1, 0.5)
    >>> jd2gcal(2400000.5, 51544.245)
    (2000, 1, 1, 0.24500000000261934)
    >>> jd2gcal(2400000.5, 51544.1)
    (2000, 1, 1, 0.099999999998544808)
    >>> jd2gcal(2400000.5, 51544.75)
    (2000, 1, 1, 0.75)

    Notes
    -----
    The last element of the tuple is the same as

       (hh + mm / 60.0 + ss / 3600.0) / 24.0

    where hh, mm, and ss are the hour, minute and second of the day.

    See Also
    --------
    gcal2jd

    """
    from math import modf

    jd1_f, jd1_i = modf(jd1)
    jd2_f, jd2_i = modf(jd2)

    jd_i = jd1_i + jd2_i

    f = jd1_f + jd2_f

    # Set JD to noon of the current date. Fractional part is the
    # fraction from midnight of the current date.
    if -0.5 < f < 0.5:
        f += 0.5
    elif f >= 0.5:
        jd_i += 1
        f -= 0.5
    elif f <= -0.5:
        jd_i -= 1
        f += 1.5

    l = jd_i + 68569
    n = ipart((4 * l) / 146097.0)
    l -= ipart(((146097 * n) + 3) / 4.0)
    i = ipart((4000 * (l + 1)) / 1461001)
    l -= ipart((1461 * i) / 4.0) - 31
    j = ipart((80 * l) / 2447.0)
    day = l - ipart((2447 * j) / 80.0)
    l = ipart(j / 11.0)
    month = j + 2 - (12 * l)
    year = 100 * (n - 49) + i + l

    return int(year), int(month), int(day), f

def julian_days2gcal(jd):        # jd is the julian day difference from julian_coor_earth
    tmp = jd2gcal(julian_coor_earth,jd)
    
    return (tmp[0],tmp[1],tmp[2],math.floor(tmp[3]*24.0),math.floor((tmp[3]*24.0 - math.floor(tmp[3]*24.0))*60.0))

测试一下这个函数


In [158]:
julian_days2gcal(0)


Out[158]:
(1970, 4, 28, 21.0, 17.0)

这个结果正好是对应我们的火星元年开始时刻。

下面我们定义火星历转为地球 G 历法的函数。


In [159]:
def mars2earth_calendar(datelist):  # given a mars calendar date list [year, month, day, hour, min], calculate the corresponding earth g calendar
    
    jd_diff = mars_date2days(datelist) * m2e   # julian days difference from the beginning of martian calendar: julian_coor_earth
    
    return julian_days2gcal(jd_diff)

In [160]:
mars2earth_calendar([1,1,1,0,0])


Out[160]:
(1970, 4, 28, 21.0, 17.0)

时区划分

火星上的时区,按1小时划分为24个时区,两个时区之间间隔15/m2e°,剩下的时区单独处理,共25个时区。


In [161]:
zoneDegree = 15/m2e
def mars_time_zones(longitude):  # given a longitude on Mars, return the time zone
    if not(0 <= longitude < 360):
        return "Wrong input(0 <= longitude < 360)"
    else:
        n = longitude/zoneDegree
        if math.floor(n) < 24:
            return int(n)
        else:
            return 24

In [162]:
mars_time_zones(351)


Out[162]:
24

为了以后画图方便,做出一个时区列表


In [163]:
time_zones_list = []
for n in range(1,25):
    time_zones_list += [15/m2e*n]

In [164]:
time_zones_list


Out[164]:
[14.598704590256267,
 29.197409180512533,
 43.7961137707688,
 58.39481836102507,
 72.99352295128134,
 87.5922275415376,
 102.19093213179387,
 116.78963672205013,
 131.3883413123064,
 145.98704590256267,
 160.58575049281893,
 175.1844550830752,
 189.78315967333145,
 204.38186426358774,
 218.980568853844,
 233.57927344410027,
 248.17797803435653,
 262.7766826246128,
 277.3753872148691,
 291.97409180512534,
 306.5727963953816,
 321.17150098563786,
 335.7702055758941,
 350.3689101661504]

最后一个地区的经度范围为:


In [165]:
zoneDegree25 = 360 - time_zones_list[23]

In [166]:
print zoneDegree25


9.63108983385

再用一个函数来进行时间转换:


In [167]:
def days2mars_date(days):
    year = 1
    month = 1
    hour = 0
    minute = 0
    while days >= total_days(year):
        days -= total_days(year)
        year += 1
    while days >= month_total_days(year,month):
        days -= month_total_days(year,month)
        month += 1
    remainder = days - math.floor(days)
    day = int(math.floor(days)) + 1
    time = remainder * 86400 * m2e
    while time >= 3600:
        time -= 3600
        hour += 1
    while time >= 60:
        time -=60
        minute += 1
    return [year,month,day,hour,minute]

In [168]:
mars_date2days([12,12,12,24,39])


Out[168]:
7673.999605744861

In [169]:
days2mars_date(7673.999605744861)


Out[169]:
[12, 12, 12, 24, 39]

In [170]:
def mars_time_zones_convert(datelist,timezones):
    time = mars_date2days(datelist)
    time += timezones / (24.0 * m2e)
    return days2mars_date(time)

In [171]:
mars_time_zones_convert([12, 12, 12, 24, 39],24)


Out[171]:
[12, 12, 13, 23, 59]

In [172]:
mars_time_zones_convert([1, 1, 1, 0, 0],1)


Out[172]:
[1, 1, 1, 0, 59]

再定义一个简单的地球上的时区转换函数:


In [173]:
def earth_time_zones_convert(datelist,timezones):
    time = julian_days([datelist[0],datelist[1],datelist[2],datelist[3],datelist[4]])
    time -= timezones / 24.0
    timelist = jd2gcal(2400000.5,time - 2400000.5)
    hour = math.floor(timelist[3]*24)
    minute = round((timelist[3]*24 - hour)*60)

    return [timelist[0],timelist[1],timelist[2],int(hour),int(minute)]

In [174]:
earth_time_zones_convert([1970,1,1,5,5],+8.5)


Out[174]:
[1969, 12, 31, 20, 35]

最后定义地球上任意时区的时间,转换到火星上任意时区的时间的函数:


In [175]:
def earth2mars_timezones(datelist,earthTimezones,marsTimezones):
    Earthdate = earth_time_zones_convert(datelist,earthTimezones)
    calendar = earth2mars_calendar(Earthdate)
    time = earth2mars_calendar_time(Earthdate)
    Marsdate = [calendar[0],calendar[1][0],calendar[1][1],time[0],time[1]]
    return mars_time_zones_convert(Marsdate,marsTimezones)

In [176]:
print chinese_character(earth2mars_calendar([2014,10,16,23,50]),earth2mars_calendar_time([2014,10,16,23,50]))


火历24年 立冬月13日星期五 14:18:45

In [177]:
earth2mars_timezones([2014,10,16,23,50],0,0)


Out[177]:
[24, 16, 13, 14, 18]

经多次测试,earth2mars_timezones()的分钟和earth2mars_calendar_time()有时会存在1分钟的误差

假如我现在在地球上的东八区,则此时位于火星上的小好奇(东经137°26′25″)的火历时间为:


In [178]:
earth2mars_timezones([2014,10,17,0,0],+8,mars_time_zones(137.4))


Out[178]:
[24, 16, 13, 15, 27]