Log目次

【Ruby】秒数から時間変換で24時間を超えるとバグった話

作成日 2025-08-05更新日 2025-08-05

はじめに

秒数を「◯時間◯分◯秒」の形式で表示する処理をこの前書いていて、アレ?ってなったのでメモしておきます この時はTimeで変換すればいいじゃん!と思っていました・・・

実行環境

Time.at で変換してみた

# 10秒の場合 Time.at(10).strftime("%H時間%M分%S秒") => "00時間00分10秒" # 60秒の場合 Time.at(60).strftime("%H時間%M分%S秒") => "00時間01分00秒" # 360秒の場合 Time.at(360).strftime("%H時間%M分%S秒") => "00時間06分00秒" # 3600秒の場合 Time.at(3600).strftime("%H時間%M分%S秒") => "01時間00分00秒"

上の結果を見て「お、ちゃんとできてるじゃん!」と思っていました……が。

24時間を超えるとバグる

以下が期待値なのですが、実際に Time.at を使ってみると…

実行結果

# OK Time.at(86399).strftime("%H時間%M分%S秒") => "23時間59分59秒" # アレ????? Time.at(86400).strftime("%H時間%M分%S秒") => "00時間00分00秒" # アレ????? Time.at(86401).strftime("%H時間%M分%S秒") => "00時間00分01秒" # 123456秒って 34時間17分36秒 のはずじゃない? Time.at(123456).strftime("%H時間%M分%S秒") => "10時間17分36秒"

なんでこうなった

Timeクラスについて

Time オブジェクトは時刻を起算時からの経過秒数で保持しています。起算時は協定世界時(UTC、もしくはその旧称から GMT とも表記されます) の 1970年1月1日午前0時です。なお、うるう秒を勘定するかどうかはシステムによります。

Timeクラスのatについて

unit に応じて seconds + xseconds ミリ秒などの時刻を表す Time オブジェクトを返します。[PARAM] seconds:起算時からの経過秒数を表わす値をInteger、 Float、 Rational、または他のNumericで指定します。

Time.at(seconds) は「1970年1月1日 00:00:00 UTC」から seconds 秒後の "時刻" を生成します。 下記のコードは「1970年1月2日 10:17:36 UTC」という“時刻”を作っていて、strftime("%H") で表示されるのはその日の「時刻(10時)」です。

Time.at(123456).to_s => "1970-01-02 10:17:36 +0000"

この状態で strftime("%H") を使うと、「その日」の時刻(つまり0〜23)で返されるため、24時間を超えると0に戻ってしまうというわけです。

正しい実装

こんな感じ

seconds = 123456 => 123456 hours = seconds / 3600 => 34 minutes = (seconds % 3600) / 60 => 17 secs = seconds % 60 => 36 format("%02d時間%02d分%02d秒", hours, minutes, secs) => "34時間17分36秒"

まとめ

参考リンク