【Python】24時(0時)をまたぐ時刻の平均を出したい場合の方法【Timedelta】

カテゴリ:Python 投稿:2022年7月11日1:04、更新:2022年7月11日1:04

・記事の概要 

Pythonで24時(0時)をまたぐ時刻の平均を出そうとして、面白かったので記事にしてみます。

ちょっとニッチな記事ですね。


・この記事でできること 

Pythonで0時またぎの深夜時間を24時,25時などと換算して平均を出すときの手法がわかります。

Timedeltaを使っていきます。


・やろうとしていたことの前提 

すごく思いつきで、

ブログの「記事投稿時間の平均」をスクレイピングをかけながら出してみようと思ったのが背景。

正直自分のブログならクエリ投げた方が早いかなあと思いつつ、自ブログ以外にも利用可能な汎用性を持たせてみようとコーディングしたものでした。


・躓きポイント 

「スクレイピングさえ書ければ余裕っしょ〜」と思っていたんですが、躓きました。

何かって言うと「記事の投稿時間」の平均と考えた時に

  • 午前7時と午前8時であれば7時半⇨わかる
  • 22時と23時であれば22時半⇨わかる
  • 23時と深夜1時半であれば正午12時半⇨正しいんだけど、深夜0時半(24時半)としたいよね

となったのです。

私のブログの投稿時間は主に23時〜深夜2時(26時)であったため、

そもそも時間って平均求めにくいのに、25時とかも考慮に入れるのかあ、となりました。


・対応とコード 

まずはコードの概観(スクレイピングの部分は除いています)。

#平均求める用のリスト
avg_list=[]
#時刻計算用の基準値(1970-01-01 00:00:00)
base_time = pd.Timestamp(0)

#リストを1行ずづ読み込んで部分一致する行だけ抽出
for text in all_text_list:
    #投稿の含まれる行を抽出し、抜き出したい文字の前後idxを取得
    if "投稿:" in text:
        target_s = '投稿:'
        target_e = '更新:'
        idx_s = text.find(target_s)
        idx_e = text.find(target_e)
        
        #idx指定で抜き出した文字列の日付をdatetime変換
        post_date = datetime.strptime(text[idx_s+3:idx_e-3], '%Y年%m月%d日%H:%M')
        
        #post_dateはdatetime
        #cal_dateはtimedelta(時刻間の差)で扱う
        cal_date = (post_date- base_time) % pd.Timedelta(1, 'D')
        
        #cal_date(ex:0 days 00:43:00)のhhによっては1dayを足す
        #0時~4時を深夜と定義する場合(定義ファイルを作り、外出しして呼び出しの方が良い)
        if  0 <= post_date.hour <5 :
            add_date = timedelta(days=1,hours=post_date.hour , minutes=post_date.minute)
            avg_list.append(add_date)
        else:
            avg_list.append(cal_date)

#timedeltaのリストから平均を算出
td_avg = sum(avg_list, timedelta(0)) / len(avg_list)

#timedeltaのdayまで整値する場合は条件により1day引くのも良い
#avg_time = td_avg - timedelta(days=1) など

#debug用
print(avg_list)
print(avg_time)

#秒数の合計を出して時分に換算、また今回は結果はprint出力
sec = avg_time.total_seconds()
post_hour =int(sec//3600)
post_minute = int(sec%3600//60)
print("投稿時間の平均は{0}時{1}分です".format(post_hour, post_minute))

前提として、以下もあります。

#算出に利用
from datetime import datetime, timedelta
import pandas as pd

#all_text_listはスクレイピングで取ってきた投稿時間含みの全文を1行ずつリスト化したもの。今回はあまり気にしないでいい。・


・説明 

コメントにもありますが、post_dateは投稿時間の文字列をdatetimeにしたものです。

また基準日時(base_time)からの時間差を1日(pd.Timedelta(1, 'D'))で除した余り

を、cal_dateに格納します。

基準日時は過去であればいつでも。


そうするとcal_dateは「0 days 00:30:00」のようになります。

これは差分が30分あることを示しますが、ただ日を跨いでいる場合は本来24時間(1day)と30分の差分が欲しいのです。

ゆえにif文で深夜0時~X時の間は1dayを足し、実質的に「24時」「25時」を表現します。

(もちろん、何時までを深夜とするのかについては外出しで定義した値を呼び出す方が良いですが、今回の本質ではないので横着します。)


そうすると

#debug用
print(avg_list)
print(avg_time)

の出力は

[datetime.timedelta(days=1, seconds=2580), datetime.timedelta(days=1, seconds=480), datetime.timedelta(days=1, seconds=3060), datetime.timedelta(days=1, seconds=60), Timedelta('0 days 23:43:00'), datetime.timedelta(days=1, seconds=8100), datetime.timedelta(days=1, seconds=3480), Timedelta('0 days 23:43:00')]
0 days 00:32:45

となります。


最終的な出力結果は秒数換算したものから算出し、以下となりました。

投稿時間の平均は0時32分です


・まとめ 

いかがだったでしょうか。

ちょっとニッチな内容ですが、該当するような記事がなかったので書いてみました。



また自動化を学習、特にPythonなどのプログラミング言語を習得する際には

以下のようなオンライン学習(動画学習)サービスがオススメです!

リンク先にPythonを初めて触る方でも難なく学習可能で、Pythonでタスク自動化などができる講義を紐づけています。

動画の解説を見て、手を実際に動かして、自動化や効率化技術を習得しましょう!

 



コメント一覧

コメント投稿ページへ


書いている人

のぎ
PG->SE->PMとして働き、現在はIT企業で新卒採用の担当をしています。長期育休取得明けで0歳娘の対応に毎日バタバタです。笑
採用業務をしつつ社内利用ツールなど作成しており、当ブログも勉強の一環でコーディングして作成しています。 エンジニア領域、人事・採用領域、育児関連など発信していきます。