作者: TAMURA.KENICHI
日時: 2002/3/05(01:41)
たむらです。時刻合わせ-その2です。

Win32api の setLocalTime/getLocalTime と、syscall での実装です。
定数 RUBY_PLATFORM で、 Windows 環境かどうかをチェックしてます。
もちろん、Win32apiの中にも同様なものがありますが。
MSのサイトで、getLocalTime した構造体を setLocalTime で埋めなさいと
あったので、こういう実装にしてます。
Syscall の方は、関数 syscall の利用です。OSによって、settimeofday の
定義された数値が違ったりするので、やはり RUBY_PLATFORM で分岐させてます。

メソッド settime は、モジュール Win32/Syscall を自動的に呼んで、
実際の時刻設定を行います。 Rubyは、基本的に上から順に文を評価していくので、
書き方によっては、妙なエラーになったりします。
例えば、Linux で動かす場合は、require 'win32api' なんかしたくないわけです。

#! ruby -Ke
# -*- mode: Ruby; -*-
## $Id: $

module Win32
  def platform?
    /(cygwin|mingw32|mswin32)$/ === RUBY_PLATFORM
  end
  def settime(year,month,day, hour,min,sec)
    require 'Win32API'
    getLocalTime = Win32API.new("kernel32", "GetLocalTime", %w(P), 'V')
    setLocalTime = Win32API.new("kernel32", "SetLocalTime", %w(P), 'V')
    getLastError = Win32API.new("kernel32", "GetLastError", [], 'L')
#   year,month,dayofweek,day, hour,min,sec,msec
    pSYSTEMTIME = ' ' * 2 * 8   # 2byte x 8
    
    getLocalTime.call(pSYSTEMTIME)
    t = pSYSTEMTIME.unpack("S8")
    t[0..1] = year,month
    t[3..6] = day, hour,min,sec
    setLocalTime.call( t.pack("S8") )
    
    e = getLastError.call
    if e != 0 then
      raise "Error[#{e}]: setLocalTime(win32api)!!"
    end
  end
  module_function :settime, :platform? 
end

module Syscall
  CODE_SETTIMEOFDAY =
    case RUBY_PLATFORM
    when /linux.*$/
      79
    when /(free|net)bsd.*$/
      122
#    when /(sunos|solaris).*$/
#      37  # find /usr/include -name \*.h |xargs grep -i settimeofday
          # で探すと、/usr/include/bsm/audit_kevents.h に
          #define AUE_SETTIMEOFDAY 37 ってのがあったけど、動かなかった。
          # `syscall':Invalid argument (Errno::EINVAL)
    else
      nil
    end
    
  def settime(year,month,day, hour,min,sec)
    raise "Not imprement yet!!" if CODE_SETTIMEOFDAY.nil?
    t = Time.mktime(year,month,day, hour,min,sec)
    syscall(CODE_SETTIMEOFDAY, [t.to_i,0].pack('ll'), [0,0].pack('ii'))
  end
  module_function :settime
end

def settime(year,month,day, hour,min,sec)
  if Win32::platform? then
    Win32::settime(year,month,day,hour,min,sec)
  else
    if Syscall::settime(year,month,day,hour,min,sec) != 0 then
      raise "Error: settimeofday(syscall)!!"
    end
  end
end

if __FILE__ == $0  # for test
  p t = Time.now
  n = t.hour % 2 == 0 ? -1 : +1
  p settime(t.year,t.month,t.day,t.hour+n,t.min,t.sec)
  p Time.now
end


__END__

『if __FILE__ == $0  # for test』以下は、テストケースです。
単純に今の時刻の時間を 1時間早めたり、遅くしたりしてます。
時刻を元に戻しやすいようにしただけですが (^^;
# 0分をまたいで、やると破綻しますが。

どなたか前回のと合体させて、こちらにアップしてみませんか ?
今回のスクリプトは、ちょっと小細工しすぎなので、もっと単純で
良いと思います。
# OS 限定とか

tDiary はじめました。 http://tamura.tdiary.net
たむら mailto:sgs02516@...