JSONP 形式での時刻配信
NICT の日本標準時プロジェクトにて NTP の時刻情報を JSON で、こんな感じで取得できます。
jsont( { "id": "ntp-a1.nict.go.jp", "it": 1232963971.248, "st": 1232963971.920, "leap": 33, "next": 1230768000 } )
取得項目は以下の通りです
Scala の Source.fromURL
Scala の Source.fromURL で JSON で取得した時刻情報を表示してみます。
JSON のパースは scala.util.parsing.json.JSON でできます。
import io.Source import scala.util.parsing.json.JSON import java.util.Date object Main extends Application { val src = Source.fromURL("http://ntp-b1.nict.go.jp/cgi-bin/jsont","UTF-8").getLines.mkString val json = src.replace("jsont(", "").replace(")", "") for (tpl <- JSON.parse(json).get) { tpl match { case (t1:String, t2:Double) if(t1 == "st") => println(new Date((t2*1000).toLong)) case _ => } } }
実行結果はこんな感じになります。簡単です。。
Fri Mar 25 05:49:08 JST 2011
Ntpクラスにマップする
少し手を入れて、以下のような Ntp クラスにマップしてみます。
class Ntp(id: String, it: Double, st: Double, leap: Double, next: Double)
最初に Ntp クラスに toString をオーバーライドして実装しておきます。
class Ntp(id: String, it: Double, st: Double, leap: Double, next: Double) { private def toDate(posixSec: Double) = new Date((posixSec * 1000).toLong) override def toString = "Local Time:" + toDate(it) + "\nNTP Time :" + toDate(st) }
JSON 形式で取得する時刻は UNIX Time(POSIX仕様) で、少数以下3桁(ミリ秒まで)なので、1000で割って桁数を合わせて日付に変換する函数も定義しておきます。
次に json を取ってくる処理を関数に切り出しておきます。
def url = "http://ntp-b1.nict.go.jp/cgi-bin/jsont?" + System.currentTimeMillis / 1000 def jsont = Source.fromURL(url, "UTF-8").getLines.mkString.replace("jsont(", "").replace(")", "")
URL にクエリとしてローカルの時刻を付けると NTP サーバの時刻とのずれが得られます。
取得した JSON をパースする ntpOf 関数を作成します。
def ntpOf(json: String):Option[Ntp] = JSON.parseFull(json) match { case Some(s) => mapNtp(s.asInstanceOf[Map[String, Any]]) case None => None }
JSON.parseFull にて JSON をパースすると、Option の結果が得られ、Option[Map[String, Any]]型となります(対象の JSON の内容によりますが、今回はこの形)。asInstanceOf でキャストして mapNtp 関数に渡します。Scala でのキャストは asInstanceOf にて行い、isInstanceOf にて型の判定ができます。
mapNtp 関数にて各マップのキーから値を取得して束縛します。
def mapNtp(map: Map[String, Any]) = for { id <- map.get("id") it <- map.get("it") st <- map.get("st") leap <- map.get("leap") next <- map.get("next") } yield new Ntp(id.toString, asDouble(it), asDouble(st), asDouble(leap), asDouble(next)) def asDouble(d: Any) = d.asInstanceOf[Double]
マップの値は、今回のJSONの例だと、文字列と Double 値なので、Any型からキャストして Ntp オブジェクトを作成します。
最後に Ntp を画面出力する処理を。
def printNtp(ntp: Option[Ntp]):Unit = ntp match { case Some(s) => println(s) case None => println("none") }
副作用のための関数なので戻り値なしの :Unit を明示します。
では。
printNtp(ntpOf(jsont))
とすると以下のような出力が得られます。
Local Time:Sat Mar 26 05:46:37 JST 2011 NTP Time :Sat Mar 26 05:46:39 JST 2011
ソース
import io.Source import scala.util.parsing.json.JSON import java.util.Date object Main { class Ntp(id: String, it: Double, st: Double, leap: Double, next: Double) { private def toDate(posixSec: Double) = new Date((posixSec * 1000).toLong) override def toString = "Local Time:" + toDate(it) + "\nNTP Time :" + toDate(st) } def url = "http://ntp-b1.nict.go.jp/cgi-bin/jsont?" + System.currentTimeMillis / 1000 def jsont = Source.fromURL(url, "UTF-8").getLines.mkString.replace("jsont(", "").replace(")", "") def ntpOf(json: String):Option[Ntp] = JSON.parseFull(json) match { case Some(s) => mapNtp(s.asInstanceOf[Map[String, Any]]) case None => None } def mapNtp(map: Map[String, Any]) = for { id <- map.get("id") it <- map.get("it") st <- map.get("st") leap <- map.get("leap") next <- map.get("next") } yield new Ntp(id.toString, asDouble(it), asDouble(st), asDouble(leap), asDouble(next)) def asDouble(d: Any) = d.asInstanceOf[Double] def printNtp(ntp: Option[Ntp]):Unit = ntp match { case Some(s) => println(s) case None => println("none") } def main(args: Array[String]): Unit = { printNtp(ntpOf(jsont)) } }
それだけです。。