私はこのトピックに関して多くの質問と回答を見てきましたが、私の特定の問題に対処したものはありませんでした。 Javaカレンダークラス(標準-サードパーティライブラリなし))を拡張し、2つの任意の日付間の日の違いを見つける必要がありました。
方法:
そして、そうであることもあれば、そうでないこともあります。同じ日のテストでさえ、1つずれることがあります。どうしたの?
他のユーザーが提案しているように、日付のみを比較するには、カレンダーのミリ秒値もゼロに設定する必要があります。これは、次のコードスニペットで実現できます。
someCalendar.set(Calendar.MILLISECOND, 0)
また、タイムゾーンの変更(冬時間から夏時間への移動など)は、1日あたり86,400,000ミリ秒より多いまたは少ないことを意味する場合があることに注意してください。
Joda Time ライブラリはこのような問題を非常によくサポートしています。
LocalDate d1 = new LocalDate(calendar1.getTimeInMillis());
LocalDate d2 = new LocalDate(calendar2.getTimeInMillis());
int days = Days.daysBetween(d1, d2).getDays();
更新(@ basil-bourqueからのフィードバック):
Java 8の時点で新しい時間ライブラリJava.time
が導入され、外部依存関係のない同様のオプションが利用可能になりました。
int days = Duration.between(calendar1.toInstant(), calendar2.toInstant()).toDays();
ChronoUnit.DAYS.between( then , now )
コードでは、毎日が正確に24時間であると想定しています。違います。 夏時間(DST) などの異常は、23時間、25時間、またはその他の数値など、日が異なる可能性があることを意味します。タイムゾーンのまさに意味は、これらの異常の履歴を追跡することです。
また、1日が深夜に始まると想定します。違います。異常のため、01:00
などの他の時刻から始まる日もあります。
Java.util.Date
、 Java.util.Calendar
、Java.text.SimpleTextFormat
などの厄介な古い日時クラスを使用しています レガシー 、 Java.time クラスに置き換えられました。
適切なタイムゾーン名 をcontinent/region
の形式で指定します。たとえば、 America/Montreal
、 Africa/Casablanca
、またはPacific/Auckland
。 EST
やIST
などの3〜4文字の省略形は、そのままでは使用しないでくださいnot真のタイムゾーンであり、標準化されておらず、一意でもありません(!)。
Java.timeクラスを拡張(サブクラス化)しないでください(これらはfinal
とマークされています)。
また、ビジネスロジックのインターフェイスに一般化しないでください。このフレームワークの具体的なクラスに固執します。一般化は Javaコレクション などの他のフレームワークでは意味がありますが、Java.timeではそうではありません。
この作業は、Java.timeクラスを使用するとはるかに簡単になります。
ZonedDateTime
は、タイムライン上でタイミングゾーン(ZoneId
)が割り当てられた瞬間を表します。
ZoneId z = ZoneId.of( "America/Montreal" );
// of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone)
ZonedDateTime then = ZonedDateTime.of( 2017 , 1 , 23 , 12 , 34 , 56 , 123456789 , z );
ZonedDateTime now = ZonedDateTime.now( z );
ChronoUnit
列挙型は、モーメントのペア間の経過時間を計算できます。
long days = ChronoUnit.DAYS.between( then , now );
このコードはIdeOne.comでライブで実行されます を参照してください。
then.toString():2017-01-23T12:34:56.123456789-05:00 [南北アメリカ/モントリオール]
now.toString():2017-03-01T21:26:04.884-05:00 [南北アメリカ/モントリオール]
日:37
GregorianCalendar
オブジェクトが与えられた場合は、古いクラスに追加された新しいメソッドを使用してJava.timeに変換します。
ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
Calendar
インスタンスが実際にはGregorianCalendar
であることがわかっている場合は、それをキャストします。
GregorianCalendar myGregCal = (GregorianCalendar) myCal ;
Java.timeクラスは、開始がinclusiveで、終了がexclusiveである、Half-Openアプローチによって期間を定義します。
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、厄介な古い legacy などの日時クラスに取って代わります。 Java.util.Date
、 Calendar
、& SimpleDateFormat
。
Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行をアドバイスします。
詳細については、 Oracleチュートリアル を参照してください。そして、StackOverflowで多くの例と説明を検索してください。仕様は JSR 31 です。
Java.timeクラスはどこで入手できますか?
ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある試験場です。 Interval
、 YearWeek
、 YearQuarter
などの便利なクラスがここにあります。 、および more 。
私はこの問題に取り組むためのはるかに簡単な方法を書きましたが、いくつかの日付に1日余分にかかるという同じ問題に直面しました。
これが現在の私のアプローチです、
public long getDays(long currentTime, long endDateTime) {
Calendar endDateCalendar;
Calendar currentDayCalendar;
//expiration day
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
endDateCalendar.setTimeInMillis(endDateTime);
endDateCalendar.set(Calendar.MILLISECOND, 0);
endDateCalendar.set(Calendar.MINUTE, 0);
endDateCalendar.set(Calendar.HOUR, 0);
//current day
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
currentDayCalendar.setTimeInMillis(currentTime);
currentDayCalendar.set(Calendar.MILLISECOND, 0);
currentDayCalendar.set(Calendar.MINUTE, 0);
currentDayCalendar.set(Calendar.HOUR, 0);
long remainingDays = Math.round((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()) / (24 * 60 * 60 * 1000));
return remainingDays;
}
以前はこの線を使用していましたが、残りは同じです:-
long remainingDays = TimeUnit.MILLISECONDS.toDays(
Math.abs(expiryCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()));
しかし、私にはうまくいかないようです。
手順1で、時刻を深夜に設定することで問題を認識しました。これにより、すべての時間、分、秒がゼロになっていることが確認されました。しかし、あなたは十分に行きませんでした!また、millisecondsもゼロになっていることを確認する必要があります。
これを正確に行うためのコードを次に示します。
protected long truncate_to_seconds (long date_in_millis) {
long l = date_in_millis / 1000L;
l *= 1000L;
return l;
}
時間部分を切り捨てる必要があると思います以下のように差を計算する前の日付から:
DateFormat formatter= new SimpleDateFormat("MM/dd/yyyy");
String truncatedDateString1 = formatter.format(date1);
Date truncatedDate1 = formatter.parse(truncatedDateString1);
String truncatedDateString2 = formatter.format(date2);
Date truncatedDate2 = formatter.parse(truncatedDateString2);
long timeDifference = truncatedDate2.getTime()- truncatedDate1.getTime();
int daysInBetween = timeDifference / (24*60*60*1000);
これがうまくいくことを願っています。
私はあなたの要求に応じて目的として私の機能を持っています。カレンダーを使用していたので、比較する前にすべての時間部分を0に設定しました。
int countDays(Date dateBegin, Date dateEnd) {
if (dateBegin == null || dateEnd == null)
return 0;
Calendar from = asCalendar(dateBegin); // asCalendar() Initialise a Calendar from a Date
Calendar to = asCalendar(dateEnd);
// Set the time part to 0
from.set(Calendar.MILLISECOND, 0);
from.set(Calendar.SECOND, 0);
from.set(Calendar.MINUTE, 0);
from.set(Calendar.HOUR_OF_DAY, 0);
to.set(Calendar.MILLISECOND, 0);
to.set(Calendar.SECOND, 0);
to.set(Calendar.MINUTE, 0);
to.set(Calendar.HOUR_OF_DAY, 0);
int nbJours = 0;
for (Calendar c = from ; c.before(to) ; c.add(Calendar.DATE, +1))
{
nbJours++;
}
for (Calendar c = from ; c.after(to) ; c.add(Calendar.DATE, -1))
{
nbJours--;
}
return nbJours;
}