Imaginary Code

from kougaku-navi.net

Processingで日時指定&ミリ秒表示付きのタイマーを作る

とある目的でProcessingでタイマーを作ることになったのですが、そこでの要件が「日付込みで終了時刻を設定したい」と「ミリ秒の桁(正確には1/100秒の桁)の表示もしたい」の2つでした。これが地味に面倒だったので、どうやったのかの記録をここに残しておきます。ProcessingというよりはもはやJavaの話です。

f:id:kougaku-navi:20201225030545p:plain

import java.util.Date;
import java.util.Calendar;
import java.text.ParseException;
import java.text.SimpleDateFormat;

// 終了時刻の設定(yyyy/MM/dd hh:mm:ssの形式で記述)
Date limit = stringToDate("2020/12/31 23:59:00");

void setup() {
  size(600, 300);
}

void draw() {
  background(50);

  // 終了時刻と現在時刻の差から残り時間をミリ秒単位で取得
  Date current = new Date();
  long remaining_ms = limit.getTime() - current.getTime();
  if ( remaining_ms < 0 ) remaining_ms = 0;

  // 残り時間表示
  textSize(50);
  textAlign(CENTER);
  text( msToString(remaining_ms), width/2, height/2 );
}

// 「yyyy/MM/dd hh:mm:ss」形式の文字列をDateに変換
Date stringToDate(String str) {
  try {
    SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
    return sdFormat.parse(str);
  } 
  catch (ParseException e) {
    e.printStackTrace();
  }
  return null;
}

// ミリ秒から「dd days hh:mm:ss:SS」形式の文字列に変換 
String msToString(long ms) {  
  final long day_ms = 86400000;
  final long hour_ms = 3600000;
  final long min_ms = 60000;
  final long sec_ms = 1000;

  long day = ms/day_ms;
  ms %= day_ms;
  long hour = ms/hour_ms;
  ms %= hour_ms;
  long min = ms/min_ms;
  ms %= min_ms;
  long sec = ms/sec_ms;
  ms %= sec_ms;
  long SS = ms/10;
  
  return nf(day, 1, 0) + "days " + nf(hour, 2, 0) + ":" + nf(min, 2, 0) + ":" + nf(sec, 2, 0) + "." + nf(SS, 2, 0);
}


冒頭で終了時刻設定をしてるところの「2020/12/31 23:59:00」という文字列を適宜変更してください。時刻データはDateを使って管理されますが、残り時間をミリ秒まで表示したい関係で、いったんミリ秒に変換してから現在時刻との差を計算し、それをまた時刻文字列に変換しています。なんかもっといいやり方がある気がしますが。