質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

4回答

1441閲覧

時刻が重複して表示されてしまう。

aaaa_

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/09/01 11:00

前提・実現したいこと

大学の課題で1秒毎に現在の日時を表示させ20秒間表示したら終了と言う課題が出ています。

課題の注意事項として1秒毎の日時を表示させる為にsleep等を使わず、取得した日時から算出しろと書かれています。
1秒毎に日時の表示をさせる事は出来たのですが、1秒後から19秒後までの日時が重複して出力されてしまっているので、何が原因なのか、どうすれば重複せずに出力出来るのか教えていただきたいです。

ソースコードの形はこのままで教えていただきたいです。

発生している問題・エラーメッセージ

2020/09/01 19:39:00 2020/09/01 19:39:01 2020/09/01 19:39:01 2020/09/01 19:39:02 2020/09/01 19:39:02 2020/09/01 19:39:03 2020/09/01 19:39:03 2020/09/01 19:39:04 2020/09/01 19:39:04 2020/09/01 19:39:05 2020/09/01 19:39:05 2020/09/01 19:39:06 2020/09/01 19:39:06 2020/09/01 19:39:07 2020/09/01 19:39:07 2020/09/01 19:39:08 2020/09/01 19:39:08 2020/09/01 19:39:09 2020/09/01 19:39:09 2020/09/01 19:39:10 2020/09/01 19:39:10 2020/09/01 19:39:11 2020/09/01 19:39:11 2020/09/01 19:39:12 2020/09/01 19:39:12 2020/09/01 19:39:13 2020/09/01 19:39:13 2020/09/01 19:39:14 2020/09/01 19:39:14 2020/09/01 19:39:15 2020/09/01 19:39:15 2020/09/01 19:39:16 2020/09/01 19:39:16 2020/09/01 19:39:17 2020/09/01 19:39:17 2020/09/01 19:39:18 2020/09/01 19:39:18 2020/09/01 19:39:19

該当のソースコード

import java.text.SimpleDateFormat; import java.util.Calendar; public class Sample{ public static void main(String[]args){ SimpleDateFormat d = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Calendar c1 = Calendar.getInstance(); int s1 = c1.get(Calendar.SECOND); Calendar c2 = Calendar.getInstance(); int s2 = c2.get(Calendar.SECOND); long s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); while(c2.getTimeInMillis() < c1.getTimeInMillis() + 19000){ c2 = Calendar.getInstance(); s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); if(s3 == 0){ System.out.println(d.format(c2.getTime())); }else if(s3 == 1000){ System.out.println(d.format(c2.getTime())); }else if(s3 == 2000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 3000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 4000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 5000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 6000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 7000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 8000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 9000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 10000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 11000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 12000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 13000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 14000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 15000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 16000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 17000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 18000){ System.out.println(d.format(c2.getTime())) }else if(s3 == 19000){ System.out.println(d.format(c2.getTime())) } } } }

補足情報(FW/ツールのバージョンなど)

java

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

余計な部分を全部省くと、

Calendar c1 = Calendar.getInstance(); 一つ目の時刻を取得
Calendar c2 = Calendar.getInstance(); 二つ目の時刻を取得
while(c2.getTimeInMillis() < c1.getTimeInMillis() + 19000){ 一つ目から19秒後未満まで繰り返す
c2 = Calendar.getInstance(); 二つ目の時刻を更新
s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); 差分をとる。
以下ifの山。たまたま、差分が1000とうの切りのいい瞬間だけ、出力する。

というロジックなので、
システムの分解能以上の速度でループが回ると、c2の値が変わらず、差分も変わらず、
そのまま繰り返出力される、みたいな感じでしょうか?

ifでたまたま切りのいいタイミングを抜くのではなく、
1秒単位に、閾値を用意しておいて、それを超えていたら、表示して、閾値を次の1秒単位に更新。
みたいな感じにするといいのではないでしょうか。

例えばこんなとか。

JAVA

1import java.text.SimpleDateFormat; 2import java.util.Calendar; 3public class Main{ 4 public static void main(String[]args){ 5 SimpleDateFormat d = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 6 Calendar c2; 7 long s3 = Calendar.getInstance().getTimeInMillis(); 8 for(int i=0; i<20; i++){ 9 while((c2 = Calendar.getInstance()).getTimeInMillis() < s3 + i*1000); 10 System.out.println(d.format(c2.getTime())); 11 } 12 } 13}

ほんとにそんなに早いのかなとおもって、paiza.ioで

JAVA

1import java.text.SimpleDateFormat; 2import java.util.Calendar; 3public class Main{ 4 public static void main(String[]args){ 5 SimpleDateFormat d = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 6 Calendar c1 = Calendar.getInstance(); 7 Calendar c2 = Calendar.getInstance(); 8 long s3; 9 while(c2.getTimeInMillis() < c1.getTimeInMillis() + 3){ // 3ミリ秒実行 10 c2 = Calendar.getInstance(); 11 s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); 12 System.out.print(s3); 13 } 14 } 15}

とかやってみたら、
00000000000000000000001111111111111111111111111111111222222222222222222222223
とかの結果になったので、1ミリ秒の間に20回以上もループするのね。
ループの中の処理を増やすとその分回数は減ります。

投稿2020/09/01 11:30

編集2020/09/01 12:03
amiya

総合スコア1218

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Java

1import java.text.SimpleDateFormat; 2import java.util.Calendar; 3 4public class Main { 5 public static void main(String[]args) throws Exception { 6 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 7 for (int prev = -1, k = 0; k < 20; /* Thread.sleep(100) */) { 8 Calendar cal = Calendar.getInstance(); 9 for (int sec = cal.get(Calendar.SECOND); sec != prev; prev = sec) { 10 System.out.println(sdf.format(cal.getTime())); 11 k++; 12 } 13 } 14 } 15}

これで動きますが、
Calendar.getInstance() を 1秒間に何百万回も実行して CPU の無駄遣いになります。
コメントになっている Thread.sleep(100) があると、1秒間に 10回程度しか実行しなくなります。

投稿2020/09/01 22:39

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

できるだけコードを変えないようにしてみました。

java

1import java.text.SimpleDateFormat; 2import java.util.Calendar; 3public class Sample{ 4 public static void main(String[]args){ 5 SimpleDateFormat d = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 6 Calendar c1 = Calendar.getInstance(); 7 int s1 = c1.get(Calendar.SECOND); 8 Calendar c2 = Calendar.getInstance(); 9 int s2 = c2.get(Calendar.SECOND); 10 long s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); 11 12 // 最後に処理したミリ秒を覚えておく。-1なのは最初の0を通すため 13 long lastShoriS3 = -1; 14 15 while(c2.getTimeInMillis() < c1.getTimeInMillis() + 19000){ 16 c2 = Calendar.getInstance(); 17 s3 = c2.getTimeInMillis() - c1.getTimeInMillis(); 18 19 // 重複を防ぐ部分 20 if (s3 == 0 || String.valueOf(s3).endsWith("000")) { 21 if (s3 <= lastShoriS3) { 22 continue; // 1ms以内に処理が回ってきたので何もしない 23 } 24 lastShoriS3 = s3; 25 } 26 27 if(s3 == 0){ 28 System.out.println(d.format(c2.getTime())); 29 }else if(s3 == 1000){ 30 System.out.println(d.format(c2.getTime())); 31 }else if(s3 == 2000){ 32 System.out.println(d.format(c2.getTime())); 33 }else if(s3 == 3000){ 34 System.out.println(d.format(c2.getTime())); 35 }else if(s3 == 4000){ 36 System.out.println(d.format(c2.getTime())); 37 }else if(s3 == 5000){ 38 System.out.println(d.format(c2.getTime())); 39 }else if(s3 == 6000){ 40 System.out.println(d.format(c2.getTime())); 41 }else if(s3 == 7000){ 42 System.out.println(d.format(c2.getTime())); 43 }else if(s3 == 8000){ 44 System.out.println(d.format(c2.getTime())); 45 }else if(s3 == 9000){ 46 System.out.println(d.format(c2.getTime())); 47 }else if(s3 == 10000){ 48 System.out.println(d.format(c2.getTime())); 49 }else if(s3 == 11000){ 50 System.out.println(d.format(c2.getTime())); 51 }else if(s3 == 12000){ 52 System.out.println(d.format(c2.getTime())); 53 }else if(s3 == 13000){ 54 System.out.println(d.format(c2.getTime())); 55 }else if(s3 == 14000){ 56 System.out.println(d.format(c2.getTime())); 57 }else if(s3 == 15000){ 58 System.out.println(d.format(c2.getTime())); 59 }else if(s3 == 16000){ 60 System.out.println(d.format(c2.getTime())); 61 }else if(s3 == 17000){ 62 System.out.println(d.format(c2.getTime())); 63 }else if(s3 == 18000){ 64 System.out.println(d.format(c2.getTime())); 65 }else if(s3 == 19000){ 66 System.out.println(d.format(c2.getTime())); 67 } 68 } 69 } 70}

投稿2020/09/01 14:22

YakumoSaki

総合スコア2027

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Timerを使うというのは反則なんでしょうか?

Java

1public static void main(String[] args) { 2 Timer timer = new Timer(); 3 timer.scheduleAtFixedRate(new TimerTask() { 4 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss"); 5 int counter = 0; 6 7 @Override 8 public void run() { 9 System.out.println(LocalDateTime.now().format(formatter)); 10 if (++counter == 20) { 11 timer.cancel(); 12 } 13 } 14 }, 0, 1000); 15}

元々の質問は、重複する原因と対策だと思いますが、
載せられているコードを実行しても、1秒毎に表示されることもなく、
全く動いてないように見えたので、質問者さんのコードを参考にしたバージョンも書いてみました。

Java

1import java.time.LocalDateTime; 2import java.time.format.DateTimeFormatter; 3import java.time.temporal.ChronoUnit; 4 5public class Sample { 6 private static final int LIMIT = 20; 7 public static void main(String[] args) throws Exception { 8 int counter = 0; 9 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss"); 10 LocalDateTime previous = LocalDateTime.now(); 11 while (true) { 12 LocalDateTime now = LocalDateTime.now(); 13 if (ChronoUnit.MILLIS.between(previous, now) >= 1000) { 14 previous = now; 15 System.out.println(now.format(formatter)); 16 if (++counter == LIMIT) { 17 break; 18 } 19 } 20 } 21 } 22}

投稿2020/09/01 13:24

編集2020/09/01 13:50
root_jp

総合スコア4666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問