ローイングファンのプログラミング日記

ボート競技やプログラミングについて書きます

文字列をTimeオブジェクトに変換する

ボート競技(レガッタ)はスピードを競う競技。
なので情報の中でもタイムは特に気にするところ。
タイム差をもとめるには独特の計算が必要になる。頭の中で無意識にこなしてしまうけれど、計算式であらわそうとすればけっこう大変だ。
RubyのTimeオブジェクトならば-メソッドでタイム差を計算できるし、 <>メソッドでタイムの比較もできる。
今回はTimeオブジェクトのつくりかたを試す。

目次


任意の時刻をつくる

Timeクラスのlocalメソッド

RbuyにはTimeクラスが組み込まれている。
Timeクラスのlocalメソッドを使って任意の時刻をつくることができる。
書式は次のとおり。

Time.local(年,月,日,時,分,秒,コンマ秒)


年から秒まで順に全て記入する必要がある。
コンマ秒は任意。

TimeクラスのWebページ
Rubyリファレンスマニュアル
組み込みライブラリ Timeクラス
https://docs.ruby-lang.org/ja/latest/class/Time.html

timeライブラリのparseメソッド

timeライブラリはTimeクラスを拡張するライブラリ。
標準添付ライブラリなので読み込むだけで使える。
timeライブラリを読み込むと、文字列をTimeオブジェクトに変換するparseメソッドが使えるようになる。
parseメソッドの書式は次のとおり。


require 'time'
Time.parse("年-月-日 時:分:秒.コンマ秒")


年月日はなくても大丈夫。
時は必須。
コンマ秒は任意。

timeライブラリのWebページ
Rubyリファレンスマニュアル
timeライブラリ > Timeクラス > parse
https://docs.ruby-lang.org/ja/latest/method/Time/s/parse.html

Timeオブジェクトを呼び出す

年月日時分秒コンマ秒を個別に呼び出す

書式は次のとおり。

Timeオブジェクト.year
Timeオブジェクト.mon
Timeオブジェクト.day
Timeオブジェクト.hour
Timeオブジェクト.min
Timeオブジェクト.sec
Timeオブジェクト.usec


書式を指定して表示する strftimeメソッド

strftimeメソッドの書式は次のとおり。

Timeオブジェクト.strftime("書式")


書式に使う主な記号は次のとおり。

%M: 分
%S: 秒
%L: ミリ秒
%nN: 小数点以下nケタ秒


フォーマットの詳細はWebページに載っている。

Rubyリファレンスマニュアル Timeクラス
インスタンスメソッド strftime
https://docs.ruby-lang.org/ja/latest/class/Time.html#I_STRFTIME

コードを書く

実際にコードを書く。
ボートレース(レガッタ)、2017年全日本選手権、男子エイトの優勝タイムと準優勝タイム、5分47秒コンマ74秒と5分51秒コンマ44秒をTimeオブジェクトにする。

time_test.rb

#組み込みクラスでゴールタイムをつくる
goal_time = Time.local(2018,4,25,0,5,47,74)
#タイムを読み込む
puts "組み込みクラスでつくったタイム"
p goal_time
p goal_time.min
p goal_time.sec
p goal_time.usec
puts "#{goal_time.strftime("%M:%S.%2N")}"

#文字列をTimeオブジェクトに変換する
require 'time'
time_str = "05:51.44"
goal_time_fromstr = Time.parse("00:" + time_str)
#タイムを読み込む
puts "文字列から変換したタイム"
p goal_time_fromstr
p goal_time_fromstr.min
p goal_time_fromstr.sec
p goal_time_fromstr.usec
puts "#{goal_time_fromstr.strftime("%M:%S.%2N")}"


コードの説明

  • 組み込みクラスでゴールタイムをつくる
    • localメソッドを使う
      • 引数には年,月,日,時,分,秒を数値で記入。コンマ秒は任意
  • タイムを読み込む
    • Timeオブジェクト全体をpメソッドで表示
    • minメソッドで分を表示
    • secメソッドで秒を表示
    • usecメソッドでコンマ秒を表示
    • strftimeメソッドで形式を指定して表示
      • %2Nはコンマ秒を下2ケタで表示
  • 文字列をTimeオブジェクトに変換する
  • timeライブラリをrequireで読み込む
  • タイムの文字列を変数に代入
  • 文字列をTimeオブジェクトに変換
    • parseメソッドを使う
    • 引数の単位に「時間」は必須なので変数の頭に00:を加える
  • 読み込みは組み込みクラスでつくったタイム出力と同じ


実行結果

組み込みクラスでつくったタイム
2018-04-25 00:05:47 +0900
5
47
74
05:47.00
文字列から変換したタイム
2018-04-25 00:05:51 +0900
5
51
440000
05:51.44


全体表示の+900は標準時(イギリス グリニッジ天文台の時刻)に9時間足しました、という意味。
+900ならば日本時間をあらわしていることになる。
Time.localTime.parseでusecメソッドの結果に(桁数の)違いがある。
Time.localでつくったオブジェクトの場合、strftimeメソッドの%2Nは正しく表示されない。

Timeオブジェクトになっているか確認する

Timeオブジェクトかどうか時間差を求めて確認する。

time_test2.rb

require 'time'
#組み込みクラスでゴールタイムをつくる
goal_time = Time.local(2018,4,25,0,5,47,74)

#文字列をTimeオブジェクトに変換する
time_str = "05:51.44"
goal_time_fromstr = Time.parse("00:" + time_str)

#タイム差をもとめる
time_lag = goal_time_fromstr - goal_time
puts "2つのタイムの差は#{time_lag}秒です。"

#classメソッドで確認する
puts "goal_timeのクラスは: #{goal_time.class}"
puts "goal_time_fromstrのクラスは: #{goal_time_fromstr.class}"
puts "time_lagのクラスは: #{time_lag.class}"

#タイムを比較する
p goal_time < goal_time_fromstr
p goal_time > goal_time_fromstr


実行結果

2つのタイムの差は4.439926秒です。
goal_timeのクラスは: Time
goal_time_fromstrのクラスは: Time
time_lagのクラスは: Float
true
false


実行結果からTimeオブジェクトになっているのがわかる。
-で計算したタイム差はTimeクラスではなくFloatクラスになる。

肝心の引き算の答えがおかしい。
localメソッドでつくったオブジェクトは小数点以下秒数がうまく呼び出せない。

小数点以下の秒数をあつかう場合

Timeオブジェクトのつくりかたをそろえて計算してみる。

re_time_test2.rb

require 'time'
localtime1 = Time.local(2018,4,25,0,5,47,74)
localtime2 = Time.local(2018,4,25,0,5,51,44)

parsetime1 = Time.parse("00:05:47.74")
parsetime2 = Time.parse("00:05:51.44")

puts "parse - local: #{parsetime2 - localtime1}"
puts "localメソッド同士: #{localtime2 - localtime1}"
puts "parseメソッド同士: #{parsetime2 - parsetime1}"


実行結果

parse - local: 4.439926
localメソッド同士: 3.99997
parseメソッド同士: 3.7


3つとも結果が違うので注意が必要。
小数点以下の秒数がある場合、parseメソッドを使って文字列から変換するやりかたがよさそう。


今回の動作確認環境
macOS 10.13.4
Ruby 2.4.4p296
ターミナル 2.8.2

Windows10 1709
Ruby 2.5.1p57 [x64-mingw32]
Windows PowerShell 5.1.16299.251