mruby-yabmでの時間処理


パワーコントロールモジュールを作って、毎時0分に処理をするような仕組みにしてみたいと思いました。

蟹さんのmrubyには時間系のクラスが入ってないので、とりあえずbuild_config.rbにmruby-timeを加えてみました。

mrubyのlibのビルドはできるのですが、rtlbm-mrubyのビルドでreadなどのstdioの関数が無いというエラーになります。

おそらくmruby-time/src/time.cのコードでnewlibのstdioが必要な関数を呼んでいるのだと思われます。

ライブラリの関数をこつこつ外して調べていきます。time.oをnmでダンプしてmrb以外の関数シンボルを一つづつ潰していきます。

一つではなくて、複数だったので結構てこづりました。

localtime_r,mktime,strftimeが原因でした。

time.cにはMRB_DISABLE_STDIOの判断も入っているのですが、環境によっては機能しないようです。

rubyやmrubyのTime classはstrftimeによるものなので、strftimeが使えないのは致命的です。mruby-timeは諦めることにしました。

rtlbm-mrubyにはbearsslの証明書の時間確認のためにtime関数はすでに用意してあり、ntpである程度正確な時間にできるようになっています。

mruby-yabmにnowを追加してtime()の値を返すようにすることにしました。

これで

yabm.now % 3600 == 0

で毎時0分に処理が実行できるようになりました。

ここを参考にしてmrubyでdateを計算してみました。

yabm = YABM.new

seconds = yabm.now + 9 * 60 * 60
minutes  = seconds / 60
seconds -= minutes * 60
hours    = minutes / 60
minutes -= hours * 60
days     = hours / 24
hours   -= days * 24

year      = 1970
dayOfWeek = 4

while 1 do
  leapYear   = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
  daysInYear = leapYear ? 366 : 365
  if days >= daysInYear then
    dayOfWeek += leapYear ? 2 : 1
    days      -= daysInYear
    if dayOfWeek >= 7 then
      dayOfWeek -= 7
    end
    year += 1
  else
    ydays = days
    dayOfWeek  += days
    dayOfWeek  %= 7
    daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    for month in 0..11 do
      dim = daysInMonth[month]
      if month == 1 && leapYear
        dim += 1
      end
      if days >= dim then
        days -= dim
      else
        break
      end
    end
    break
  end
end

yabm.print year.to_s + "\n"
yabm.print month.to_s + "\n"
yabm.print (days + 1).to_s + "\n"
yabm.print ydays.to_s + "\n"
yabm.print hours.to_s + "\n"
yabm.print minutes.to_s + "\n"
yabm.print seconds.to_s + "\n"