はじめに (対象読者・この記事でわかること)
本記事は、Javaで数値として扱われるミリ秒(long 型)を hh:mm:ss SSS という人が読みやすい形式へ変換したい開発者を対象としています。
- Java の基本的な構文は理解しているが、時間のフォーマット変換はやったことがない、という方。
- 既存プロジェクトでログやレポートにミリ秒単位のタイムスタンプを表示したいが、手間がかかっているという方。
この記事を読むことで、以下が実現できるようになります。
java.time.Durationとjava.time.format.DateTimeFormatterを組み合わせたシンプルな変換ロジックが書ける。- ライブラリ(Apache Commons など)に依存せず、標準 API だけで hh:mm:ss SSS 形式の文字列を取得できる。
- 実装例をもとに、自分のプロジェクトに合わせたカスタマイズが即座にできる。
背景として、過去に業務システムのパフォーマンス計測でミリ秒単位の計測結果を人間が直感的に把握できる形で保存したい場面がありました。その際、毎回文字列操作でフォーマットしていたため、コードが冗長になりがちでした。本記事ではその課題を根本から解決する方法をご紹介します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Java 8 以降の java.time パッケージ(
Instant,Duration,LocalTimeなど)の基本的な使い方 - 基本的な文字列操作(
String.formatやStringBuilder)の理解 - IDE(IntelliJ IDEA や Eclipse)でのデバッグ手法(任意)
ミリ秒をhh:mm:ss SSSに変換する概要
なぜ変換が必要か
システム内部では時間を ミリ秒 で保持することが多く、これは計算や比較に適しています。一方、ユーザー向けの UI やログでは hh:mm:ss SSS(例:01:23:45 678)という形式が直感的です。
- 可読性:誰が見ても「1 時間 23 分 45 秒 678 ミリ秒」とすぐに理解できる。
- 整合性:他のツールやレポートと形式を合わせやすい。
変換に使える標準 API
Java 8 で導入された java.time 系の API は、タイムゾーンや桁数の調整を意識せずに時間演算が可能です。主に以下を使用します。
| API | 主な役割 |
|---|---|
Duration |
ミリ秒を hours, minutes, seconds, millis に分解 |
LocalTime |
時・分・秒・ナノ秒を保持し、DateTimeFormatter で文字列化 |
DateTimeFormatter |
出力フォーマット(HH:mm:ss SSS)を指定 |
この組み合わせにより、1 行のコードで変換ロジックを書けます。次のセクションで実装手順を詳しく解説します。
ミリ秒をhh:mm:ss SSSに変換する実装手順
ステップ1:Duration オブジェクトに変換
まず、ロング型のミリ秒 (long millis) を Duration に変換します。Duration.ofMillis が直接利用可能です。
Javalong millis = 5023678L; // 例: 5,023,678ミリ秒 Duration duration = Duration.ofMillis(millis);
この duration からは、toHoursPart(), toMinutesPart(), toSecondsPart(), toMillisPart()(Java 9 以降) といったメソッドで各要素を取得できます。Java 8 でも duration.toHours() などのメソッドで手動計算できますが、ここでは Java 9 以降 を前提に話を進めます。
ステップ2:LocalTime にマッピング
LocalTime は「時間帯なし」の時刻を表現します。Duration の各パートを使って LocalTime.of でインスタンス化します。
Javaint hours = duration.toHoursPart(); int minutes = duration.toMinutesPart(); int seconds = duration.toSecondsPart(); int millisPart = duration.toMillisPart(); LocalTime time = LocalTime.of(hours, minutes, seconds, millisPart * 1_000_000);
LocalTime のコンストラクタはナノ秒単位まで受け取るため、ミリ秒は 1_000_000 を掛けてナノ秒に変換します。
ステップ3:フォーマッタで文字列化
DateTimeFormatter を使って LocalTime を hh:mm:ss SSS 形式に整形します。SSS はミリ秒 3 桁を意味し、DateTimeFormatter では SSS ではなく SSS(パターンは SSS)で指定します。
JavaDateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss SSS"); String formatted = time.format(formatter); System.out.println(formatted); // 例: 01:23:45 678
完全版サンプルコード
上記ステップをすべてまとめた実装例を以下に示します。
Javaimport java.time.Duration; import java.time.LocalTime; import java.time.format.DateTimeFormatter; public class MillisToTimeFormatter { /** * ミリ秒を "HH:mm:ss SSS" 形式の文字列に変換する * * @param millis ミリ秒 * @return フォーマット済み文字列 */ public static String format(long millis) { // 1. Duration に変換 Duration duration = Duration.ofMillis(millis); // 2. 各パートを取得(Java 9 以降) int hours = duration.toHoursPart(); int minutes = duration.toMinutesPart(); int seconds = duration.toSecondsPart(); int milli = duration.toMillisPart(); // 3. LocalTime にマッピング(ナノ秒に変換) LocalTime time = LocalTime.of(hours, minutes, seconds, milli * 1_000_000); // 4. フォーマッタで文字列化 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss SSS"); return time.format(formatter); } // デモ用 main メソッド public static void main(String[] args) { long[] testValues = {0L, 123L, 6543L, 5023678L, 86_400_000L + 12_345L}; // 1日+12.345秒例 for (long v : testValues) { System.out.println(v + " ms => " + format(v)); } } }
実行結果(例)
0 ms => 00:00:00 000
123 ms => 00:00:00 123
6543 ms => 00:00:06 543
5023678 ms => 01:23:45 678
86400123 ms => 24:00:01 123
ハマった点やエラー解決
| 発生した問題 | 内容 | 解決策 |
|---|---|---|
DateTimeException が発生 |
LocalTime.of に 24 時間以上の値を渡した |
Duration の toHoursPart() は 0-23 の範囲になるが、Duration が 24 時以上の場合は toHours() を使用し、LocalTime では扱えないため LocalTime に変換する前に duration.toHours() で日数を除外したか、LocalTime の代わりに LocalDateTime を使う |
| ミリ秒が 3 桁未満で左詰めになる | DateTimeFormatter のパターン SSS が「ゼロ埋め」ではなく「数値の桁数」になるケース |
String.format("%03d", milli) で手動ゼロ埋めし、formatter に組み込むか、DateTimeFormatterBuilder で appendValue に padNext(3) を使用 |
Java 8 で toHoursPart() が存在しない |
API バージョンが古い | duration.toHours() で総時間を取得し、int hours = (int) (duration.toMillis() / 3_600_000); など手動で算出し、残りを minutes、seconds、millis に分割 |
主なエラー例と対処コード(Java 8 対応版)
Javalong totalMillis = duration.toMillis(); int hours = (int) (totalMillis / 3_600_000); int minutes = (int) ((totalMillis % 3_600_000) / 60_000); int seconds = (int) ((totalMillis % 60_000) / 1_000); int millis = (int) (totalMillis % 1_000);
このように、Java のバージョンに応じて実装を切り替えることで、どの環境でも安定して動作させられます。
まとめ
本記事では、Java の標準 API(Duration・LocalTime・DateTimeFormatter)だけを使って、ミリ秒を hh:mm:ss SSS 形式に変換する具体的手順 を解説しました。
- Duration でミリ秒を時間単位に分解
- LocalTime に変換し、DateTimeFormatter で希望の文字列に整形
- Java バージョン差や 24 時間以上のケースに対するエラーハンドリング方法も紹介
この手法を採用すれば、外部ライブラリに依存せず、シンプル且つ高速にタイムスタンプを人間可読形式へ変換できます。今後は、タイムゾーン対応や日付付きフォーマット(yyyy-MM-dd HH:mm:ss SSS) といった拡張や、マルチスレッド環境でのスレッドセーフ実装 についても記事にする予定です。
参考資料
- Java SE 11 Documentation – java.time.Duration
- Java SE 11 Documentation – java.time.format.DateTimeFormatter
- 「Effective Java」 第3版, Joshua Bloch, Addison-Wesley, 2018
- Stack Overflow – Formatting duration in Java
