2017-01-10 4 views
-1

私はJavaカレンダーで不快な問題を経験しました。私は、日付として数週間の最初の日を取得したい、週が数年の間になるまでうまくいきます。 どうすればいいですか?Javaカレンダーの開始年

Calendar cal = Calendar.getInstance(); 
cal.set(2017,0,1); 
cal.setFirstDayOfWeek(Calendar.MONDAY); 
Calendar first = (Calendar) cal.clone(); 
first.add(Calendar.DAY_OF_WEEK, 
first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK)); 
Calendar last = (Calendar) first.clone(); 
last.add(Calendar.DAY_OF_YEAR, 6); 
System.out.println(first.getTime()); 
System.out.println(last.getTime()); 

出力

月1月2日午前22時30分26秒GMT 2017

日1月8日午前22時30分26秒GMT 2017

出力は

する必要があります

月12月26日22:30:26 GMT 2016

日1月1日午前22時30分26秒GMT 2017

+4

「first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK)」は、週の初めに調整する方法はなぜですか? firstDayOfWeekが2(MONDAY)でdayOfWeekが1(SUNDAY)の場合、 '2 - 1 = + 1'となり、つまり* add * 1日になります。それはあなたが見ているものです。問題を解決するためにこのロジックを調整する方法を理解するために、あなたに任せておきます。 BTW:単にそれらの値を印刷すると、これはあなたに伝えられたでしょう。 – Andreas

+1

問題は年の変更のためではありません。 DayOfWeekの数についてのあなたの理解は間違っています。 FirstDayOfWeekを月曜日に設定しても、月曜日の数は2で、DayOfWeekの数は2017年1月1日から日曜日/ 1です。したがって、2-1 = 1、2017年1月1日+1 = 2017年1月2日。2017年1月2日+6 = 2017年1月8日。 –

+0

助けてくれてありがとう、私は特定の問題のためにより良い実装がされているので、Joda Time APIを使用します – Tuby

答えて

2

カレンダーを使用しないでください、それは(see this answer)を使用するために非常に悪いAPIであることが知られています。代わりにtime apiを使用してください(java8を使用していない場合は、ThreeTen backportを使用してください)。それと

、あなたのコードは次のようになります。あなたはあなたが必要とするゾーンで交換するのは簡単、UTCを想定して(それを変換するためにDate.from(ld.atStartOfDay().atZone(ZoneId.of("UTC")).toInstant())を使用し、Dateで終わるために必要がある場合

LocalDate ld = LocalDate.of(2017,1,1); 
ld = ld.with(ChronoField.DAY_OF_WEEK, 1); 
System.out.println(ld); 
System.out.println(ld.plusDays(6)); 

+0

いいえ、 APIを使用することができます」OPが間違っていたことを誰がどのくらい早く認識したかでわかるように、これは良いAPIです。 – VGR

+0

Java 6または7を実行している場合でも、Joda-Timeは必要ありません。 java.timeの機能の多くは、[ThreeTen-Extra](http://www.threeten.org/threetenbp/)プロジェクトでバックポートされており、[ThreeTenABP](https:// github .com/JakeWharton/ThreeTenABP)プロジェクト。 Joda-Timeプロジェクトは現在メンテナンスモードにあり、java.timeへの移行をアドバイスします。 –

+0

@BasilBourqueありがとう、私はそれを知らなかった。答えを修正しました。 –

2

tl; dr

accepted Answer by Hendrickxが正しい。ここに私はもう少し読みやすいと思う選択肢です。

LocalDate.of(2017 , Month.JANUARY , 1) 
    .with(TemporalAdjusters.previous(DayOfWeek.MONDAY)) 

TemporalAdjuster

TemporalAdjusterインタフェースはjava.timeオブジェクトを操作するクラスを提供します。実装はTemporalAdjustersクラスにあります。 previousOrSameアジャスターは、前の曜日が見つかった場合、または曜日がすでにその曜日の場合は、同じ日付を使用します。

LocalDate target = LocalDate.of(2017 , Month.JANUARY , 1); 
LocalDate ld = target.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); 

target.toString():2017年1月1日| ld.toString():2016年12月26日

あなたは常に日付が既に月曜日であったとしても、前の月曜日たい場合は、アジャスターpreviousを使用しています。

LocalDate ld = target.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); 

nextOrSameアジャスターを使用して、週の終わりを取得します。

LocalDate nextOrSameSunday = target.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); 

文字列で曜日を表示できます。

ZoneId z = ZoneId.of("America/Montreal"); 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.CANADA); 
System.out.println("target: " + target.format(f) + " | ld: " + ld.format(f)); 

対象:2017年1月1日(日曜日)| ld:2016年12月26日月曜日

このcode live in IdeOne.comを参照してください。

enums,DayOfWeekおよびMonthの使用にも注意してください。 Tutorialsを参照してください。 java.timeについて


java.timeフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは、java.util.DateCalendar、& SimpleDateFormatなど、面倒な古いlegacy日時クラスに取って代わります。

maintenance modeにあるJoda-Timeプロジェクトは、java.timeクラスへの移行を推奨しています。

詳しくはOracle Tutorialをご覧ください。そして、多くの例と説明のためにStack Overflowを検索してください。仕様はJSR 310です。

ここで、java.timeクラスを取得するには?

  • Java SE 8SE 9以降
    • 内蔵しています。
    • バンドルされた実装の標準Java APIの一部です。
    • Java 9には、いくつかのマイナーな機能と修正が加えられています。
  • Java SE 6SE 7
    • java.time機能の多くはThreeTen-BackportのJava 6 & 7に戻って、移植されます。
  • Android
      ThreeTenABP
    • プロジェクトは、具体的にはAndroid用(上記)ThreeTen-バックポートを適応させます。
    • How to use ThreeTenABP…を参照してください。

ThreeTen-Extraプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、将来のjava.timeへの追加の可能性を証明する土台です。ここでは、IntervalYearWeekYearQuartermoreなどの便利なクラスがあります。

+0

本当に詳細な回答ありがとう、私はアンドロイドプロジェクトでJava 8時間を使用してみましたが、最新のAPIが必要です。私はJoda Timeで私の問題を解決しました。それは本当にマイナーで、ちょうど1行のコードでした。あなたはThreeTenBackportについて言及しましたが、私の特定のケースでは、あまりマイナーなのですが、Backport libに移行する価値はないと思います。 – Tuby

+1

実際に必要なコードが1行だけであれば十分です。通常、日々の仕事をしている人は、それをたくさんしています。それが事実になった場合、私の答えの最後のセクションをより注意深く読んでください。 Java 6&7のバックポートは1つのプロジェクト(ThreeTen-Backport)であり、そのプロジェクトは別のプロジェクト(ThreeTenABP)でAndroidに適応していました。古いレガシークラスは本当に悪いので、ライブラリを追加することでその価値を取り戻すことができます。 –

関連する問題