そのコード、読んでみた:【Python】UTC表記はどう決まる?_name_from_offsetを読解する

目次

きっかけ

ある日、「プログラマー脳〜優れたプログラマーになるための認知科学に基づくアプローチ〜」という本を読んだ。
そこで紹介されていたのは、“コードを読む力”を育てるために、自分の好きな言語でコードを要約してみようというアプローチ。
なるほど、読むことからすべてが始まるのか。

ということで、いざ実践!

今回のターゲット

せっかくなので、Pythonの標準ライブラリから選ぶことにした。
選ばれたのは、datetimeモジュール
GitHubで開かれているdatetime.pyのソースコードは、コメント含めて約2.5KL(キロライン!)あるが……

さすがに全部は無理。

そこで、今回はこの関数を読んでみることにした:

def _name_from_offset(delta):
    if not delta:
        return 'UTC'
    if delta < timedelta(0):
        sign = '-'
        delta = -delta
    else:
        sign = '+'
    hours, rest = divmod(delta, timedelta(hours=1))
    minutes, rest = divmod(rest, timedelta(minutes=1))
    seconds = rest.seconds
    microseconds = rest.microseconds
    if microseconds:
        return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
                f'.{microseconds:06d}')
    if seconds:
        return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
    return f'UTC{sign}{hours:02d}:{minutes:02d}'

なんか名前からして、UTCまわりの何かをやってそうな気がするぞ?

読んでみたら、こうなった

1. 関数名をじっと見る

まずは関数名と引数名。
_name_from_offset。ふむふむ。
「オフセットから名前を作る」らしい。名前? どの名前? 地名? 時間名?芸名?
しかも先頭にアンダースコアがあるから内部用っぽい

引数のdeltaも気になる。何が入ってくるんだ、これ?

まぁ考えてても始まらないので中を読んでみる。

2. 最初のif not delta:にひっかかる

if not delta:
    return 'UTC'

おぉ、いきなりのnot
「deltaが“ない”ときは’UTC’を返す」のか。なるほど。

でもちょっと待って。deltaって何型?
文字列? 数値? まさかのNone??

「notって、何に使えるんだっけ…?」とふと不安になったので、Pythonのnot演算子を調べてみた。

notは真偽値を反転します。TrueならFalseに、FalseならTrueに。

はい、これは知ってた。けど、文字列とか数値でもいけるの?

気になったら、試すしかない。

a = ''
print(not a)  # True

a = 'aaa'
print(not a)  # False

よし、空文字はFalseとみなされる!ということは、deltaが空っぽなら’UTC’を返すんだな。納得。

3. 負の時間?そんなのアリか

次に出てきたのがこれ:

if delta < timedelta(0):
    sign = '-'
    delta = -delta

なるほど、負の時間が来たら、マイナス記号をつける処理か。

そもそもtimedelta(0)ってなんだ?
調べればわかるけど、ここは“あえて”想像力でカバーするフェーズ。
引数が0ってことは、「ゼロ時間」を意味してるんだろうな。

つまり、deltaがマイナスなら、sign-をセットして、絶対値に直すってことか。

4. divmod、お前は誰だ

hours, rest = divmod(delta, timedelta(hours=1))
minutes, rest = divmod(rest, timedelta(minutes=1))
seconds = rest.seconds
microseconds = rest.microseconds

見たことない関数が出てきた。divmodって何者!?

名前的にはdiv(割り算)+mod(あまり)。たぶん、「商」と「あまり」を同時に返してくれる便利やつ。

たしかに、時間の分解にはぴったりだ。
「まずは1時間で割って、残りで1分を割って、さらにそのあまりから秒とマイクロ秒を…」という処理なんだな。

しかも、restって名前も良い。残り物感が出てて好き。

5. 最後の仕上げは文字列フォーマット

if microseconds:
    return (f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
            f'.{microseconds:06d}')
if seconds:
    return f'UTC{sign}{hours:02d}:{minutes:02d}:{seconds:02d}'
return f'UTC{sign}{hours:02d}:{minutes:02d}'

なるほど、マイクロ秒があるならフルで表示。
なければ秒まで。さらに何もなければ分まで、という三段階表示方式

ちなみに{hours:02d}みたいな書き方は、2桁でゼロ埋めってやつですね。
UTC+09:00みたいな、よく見るあの形を作ってるのか。

まとめ:コードを読むと、世界がちょっと広がる

ここまで読んでわかったこと:

  • deltaがなければ'UTC'を返す
  • 負のオフセットなら符号をつけて絶対値に
  • 時間を分・秒・マイクロ秒単位で分解
  • 可能な限り詳細な表記で返す

つまりこの関数は、時差情報をいい感じのUTC表記に変換してくれるやつだったのだ。

そして静かに感動する

自分がいつも何気なく見ていたUTC+09:00みたいな表示、
あれ、こんなふうに作られていたのか。

知らなかったものが、ちょっとだけわかるようになる。
そんな一歩が、コードを読む楽しさかもしれない。

おまけ:今後の自分へ

もしまたdivmodに出会ったときは、「お、君か!」と声をかけてあげよう。
そしてrestには、そっと敬意を払いたい。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次