JavaのSimpleDateFormatを使用してミリ秒数をNice "hh:mm:ss:SSS"形式に変換するストップウォッチを作成しています。問題は、時間フィールドに常に乱数が含まれていることです。私が使用しているコードは次のとおりです。
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
String strDate = sdf.format(millis);
return strDate;
}
Hhの部分を外すと、うまくいきます。それ以外の場合、hh部分では、渡された引数(ミリ秒数)がゼロであっても、「07」のようなランダムなものが表示されます。
ただし、SimpleDateFormatクラスについてはあまり知りません。助けてくれてありがとう。
標準JDKのみを使用してこれを実行した方法を次に示します(これは、Java 1.1でStringBuilder
をStringBuffer
に戻すことで機能します):
static public String formatMillis(long val) {
StringBuilder buf=new StringBuilder(20);
String sgn="";
if(val<0) { sgn="-"; val=Math.abs(val); }
append(buf,sgn,0,(val/3600000)); val%=3600000;
append(buf,":",2,(val/ 60000)); val%= 60000;
append(buf,":",2,(val/ 1000)); val%= 1000;
append(buf,".",3,(val ));
return buf.toString();
}
/** Append a right-aligned and zero-padded numeric value to a `StringBuilder`. */
static private void append(StringBuilder tgt, String pfx, int dgt, long val) {
tgt.append(pfx);
if(dgt>1) {
int pad=(dgt-1);
for(long xa=val; xa>9 && pad>0; xa/=10) { pad--; }
for(int xa=0; xa<pad; xa++ ) { tgt.append('0'); }
}
tgt.append(val);
}
TimeUnit
と呼ばれるあまり知られていないクラスを持つ最新のJDKに組み込まれています。使用したいのは Java.util.concurrent.TimeUnitintervalsで作業することです。
SimpleDateFormat
は、Java.util.Date
のインスタンスをフォーマットします。または、あなたの場合、long
値をJava.util.Date
のコンテキストに変換します。 intervalsで何をすべきかわかりません。
JodaTimeなどの外部ライブラリに頼ることなく、これを簡単に行うことができます。
import Java.util.concurrent.TimeUnit;
public class Main
{
private static String formatInterval(final long l)
{
final long hr = TimeUnit.MILLISECONDS.toHours(l);
final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}
public static void main(final String[] args)
{
System.out.println(formatInterval(Long.parseLong(args[0])));
}
}
出力は次のようにフォーマットされます
13:00:00.000
これを行う簡単な方法は、- Apache Commons Lang で DurationFormatUtils クラスを使用することです。
public static String formatTime(long millis) {
return DurationFormatUtils.formatDuration(millis, "HH:mm:ss.S");
}
どうしてですか?
public static String GetFormattedInterval(final long ms) {
long millis = ms % 1000;
long x = ms / 1000;
long seconds = x % 60;
x /= 60;
long minutes = x % 60;
x /= 60;
long hours = x % 24;
return String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
}
これは、JDKのサポートよりも退屈なように思われるJodaの最初の作業です。要求された形式のJoda実装(ゼロフィールドについていくつかの仮定を行う)は次のとおりです。
public void printDuration(long milliSecs)
{
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroIfSupported()
.appendHours()
.appendSeparator(":")
.minimumPrintedDigits(2)
.appendMinutes()
.appendSeparator(":")
.appendSecondsWithMillis()
.toFormatter();
System.out.println(formatter.print(new Period(milliSecs)));
}
他の答えを見て、この機能を思いつきました...
public static String formatInterval(final long interval, boolean millisecs )
{
final long hr = TimeUnit.MILLISECONDS.toHours(interval);
final long min = TimeUnit.MILLISECONDS.toMinutes(interval) %60;
final long sec = TimeUnit.MILLISECONDS.toSeconds(interval) %60;
final long ms = TimeUnit.MILLISECONDS.toMillis(interval) %1000;
if( millisecs ) {
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
} else {
return String.format("%02d:%02d:%02d", hr, min, sec );
}
}
これが何が起こっているかです。ミリ秒を渡すと、その数値は1970年1月1日を基準にしたものになります。0を渡すと、その日付が取得され、ローカルタイムゾーンに変換されます。中央時間にいる場合は、午後7時です。これを実行すると、すべてが理にかなっています。
new SimpleDateFormat().format(0) => 12/31/69 7:00 PM
編集、あなたがしたいことは経過時間を取得することだと思います。このために JodaTime を使用することをお勧めします。あなたは次のようなことをします
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSuffix(" hour", " hours")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
String formattedText = formatter.print(new Period(elapsedMilliSeconds));
フォーマットはローカルタイムゾーンに従って行われるため、0を渡すと0 GMTと見なされ、ローカルタイムゾーンで変換されます。
これは実際に機能しますが、メソッドの意図を微調整しているようです:-)。
public static String formatTime(long millis) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
String strDate = sdf.format(millis - 3600000);
return strDate;
}
実際にがこれがどのように機能するかを知っている人にとっては、おそらくいくつかの警告を見つけるでしょう。
別の方法があります。完全に自己完結型であり、完全に下位互換性があります。無制限の日数。
private static String slf(double n) {
return String.valueOf(Double.valueOf(Math.floor(n)).longValue());
}
public static String timeSpan(long timeInMs) {
double t = Double.valueOf(timeInMs);
if(t < 1000d)
return slf(t) + "ms";
if(t < 60000d)
return slf(t / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 3600000d)
return slf(t / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
if(t < 86400000d)
return slf(t / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
return slf(t / 86400000d) + "d " +
slf((t % 86400000d) / 3600000d) + "h " +
slf((t % 3600000d) / 60000d) + "m " +
slf((t % 60000d) / 1000d) + "s " +
slf(t % 1000d) + "ms";
}
経過時間が24時間未満の単純な書式設定。 24時間を超えると、コードは翌日の時間のみを表示し、経過日を時間に追加しません。
public static String formatElapsedTime(long milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
}
サンプルコードに不足している機能:
public static String formatElapsedTimeOver24h(long milliseconds) {
// Compiler will take care of constant arithmetics
if (24 * 60 * 60 * 1000 > milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
} else {
SimpleDateFormat sdf = new SimpleDateFormat(":mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Keep long data type
// Compiler will take care of constant arithmetics
long hours = milliseconds / (60L * 60L * 1000L);
return hours + sdf.format(milliseconds);
}
}
1日(24時間)までの間隔にJava Calendar
)を使用すると、質問に対する私の回答が表示されます。 Javaで時間間隔をフォーマットする方法 =
LocalTime // Represents a time-of-day, without date and without time zone.
.ofNanoOfDay( // Convert a count of nanoseconds into a time-of-day in a generic 24-hour day, ignoring real-world anomalies such as Daylight Saving Time (DST).
Duration // Class that represents a span-of-time not attached to the timeline.
.of( milliseconds ) // Parse your count of milliseconds as a span-of-time.
.toNanos() // Extract total number of nanoseconds in this span-of-time.
) // Returns a `LocalDate` object.
.toString() // Generate text in standard ISO 8601 format for a time-of-day (*not* recommended by me).
Java.time.Duration
時間-分-秒のスケールでタイムラインに関連付けられていない期間を表す適切なクラスは Duration
です。年-月-日のスケールの場合、 Period
を使用します。
Duration d = Duration.of( milliseconds ) ;
HH:MM:SSの時刻形式を使用した期間の報告は避けることをお勧めします。固有のあいまいさが実世界のビジネスアプリの誤解と混乱につながることを見てきました。
そのような値を報告するための標準があります 定義 in ISO 8601 :PnYnMnDTnHnMnS
。 P
は開始を示し、T
は年月日部分と時分秒部分を区切ります。
Java.timeクラスは、文字列の解析/生成時にデフォルトでISO 8601標準形式を使用します。これにはDuration
クラスが含まれます。
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toString() ;
こちらをご覧ください コードはIdeOne.comでライブ実行 。
PT1H23M45.678S
これらのISO 8601文字列は、解析だけでなく生成もできます。
Duration d = Duration.parse( "PT1H23M45.678S" ) ;
ただし、期間に時刻形式を使用することを主張する場合は、to…Part
Duration
オブジェクトのメソッド。
Duration d = Duration.ofMillis( 5_025_678L ) ;
String output = d.toHoursPart() + ":" + d.toMinutesPart() + ":" + d.toSecondsPart() + "." + TimeUnit.NANOSECONDS.toMillis( d.toNanosPart() ) ;
1:23:45.678
または、LocalTime
クラスを悪用して文字列を作成することもできます。
Duration d = Duration.ofMillis( 5_025_678L ) ;
long nanoOfDay = d.toNanos() ;
LocalTime localTimeBogus = LocalTime.ofNanoOfDay( nanoOfDay ) ;
String output = localTimeBogus.toString() ;
繰り返しになりますが、これは IdeOne.comでのコードの実行 です。
01:23:45.678