Time spent on the moon

Lunar module and lunar rover, photo via NASA

This post will illustrate two things: the amount of time astronauts have spent on the moon, and how to process dates and times in Python.

I was curious how long each Apollo mission spent on the lunar surface, so I looked up the timelines for each mission from NASA. Here’s the timeline for Apollo 11, and you can find the timelines for the other missions by making the obvious change to the URL.

Here are the data on when each Apollo lunar module touched down and when it ascended.

    data = [
        ("Apollo 11", "1969-07-20 20:17:39", "1969-07-21 17:54:00"),
        ("Apollo 12", "1969-11-19 06:54:36", "1969-11-20 14:25:47"),
        ("Apollo 14", "1971-02-05 09:18:13", "1971-02-06 18:48:42"),
        ("Apollo 15", "1971-07-30 22:16:31", "1971-08-02 17:11:23"),
        ("Apollo 16", "1972-04-21 02:23:35", "1972-04-24 01:25:47"),
        ("Apollo 17", "1972-12-11 19:54:58", "1972-12-14 22:54:37"),
    ]

Here’s a first pass at a program to parse the dates and times above and report their differences.

    from datetime import datetime, timedelta

    def str_to_datetime(string):
        return datetime.strptime(string, "%Y-%m-%d %H:%M:%S")

    def diff(str1, str2):
        return str_to_datetime(str1) - str_to_datetime(str2)

    for (mission, touchdown, liftoff) in data:
        print(f"{mission} {diff(liftoff, touchdown)}")

This works, but the formatting is unsatisfying.

    Apollo 11 21:36:21
    Apollo 12 1 day, 7:31:11
    Apollo 14 1 day, 9:30:29
    Apollo 15 2 days, 18:54:52
    Apollo 16 2 days, 23:02:12
    Apollo 17 3 days, 2:59:39

It would be easier to scan the output if it were all in hours. So we rewrite our diff function as follows.

    def diff(str1, str2):
        delta = str_to_datetime(str1) - str_to_datetime(str2)
        hours = delta.total_seconds() / 3600
        return round(hours, 2)

Now the output is easier to read.

    Apollo 11 21.61
    Apollo 12 31.52
    Apollo 14 33.51
    Apollo 15 66.91
    Apollo 16 71.04
    Apollo 17 74.99

These durations fall into three clusters, corresponding to the Apollo mission types G, H, and J. Apollo 11 was the only G-type mission. Apollo 12, 13, and 14 were H-type, intended to demonstrate a precise landing and explore the lunar surface. (Apollo 13 had to loop around the moon without landing.) The J-type missions were more extensive scientific missions. These missions included a lunar rover (“moon buggy”) to let the astronauts travel further from the landing site. There were no I-type missions; the objectives of the original I-type missions were merged into the J-type missions.

Incidentally, UNIX systems store times as seconds since 1970-01-01 00:00:00. That means the first two lunar landings were at negative times and the last four were at positive times. More on UNIX time here.

Related posts

3 thoughts on “Time spent on the moon

  1. Instead of calling .total_seconds on the timedelta, then dividing by 3600, you can divide by datetime.timedelta(hours=1):

    (dt1 - dt2) / timedelta(hours=1)

    This is a much clearer way to express the same thing, in my opinion.

    If you are concerned with speed, it helps to cache the “one hour” timedelta rather than constructing it each time.

  2. I agree that it’s usually a good idea to replace magic numbers with symbolic constants. In this case, however, I think

    total_seconds()/3600

    is obviously converting seconds to hours. In context it’s clear what 3600 means, though perhaps 60*60 would have been even clearer, and its value won’t change. On the other hand, I don’t think it’s obvious what

    (dt1 – dt2) / timedelta(hours=1)

    does. At a minimum, it requires understanding how timedelta works, whereas I imagine the meaning of total_seconds()/3600 would be clear to someone who doesn’t know Python.

  3. I mean, what else could division by a timedelta do, particularly in this context?

    This is a situation where people are distracted by the existence of the .total_seconds() method, and they don’t realize that it’s even possible to divide timedeltas like that, even though using division is the recommended method.

    If your goal is to educate people how to use datetime in Python, you’d get much more mileage out of the more idiomatic construction rather than dividing total seconds by a magic number (even a well-known one like 3600).

Comments are closed.