2つの日付の間の日数を見つける必要があります。1つはレポートからのもので、もう1つは現在の日付です。私のスニペット:
int age=calculateDifference(agingDate, today);
calculateDifference
はプライベートメソッドであり、agingDate
およびtoday
はDate
オブジェクトであり、明確にするためです。 Javaフォーラムの2つの記事 Thread 1 / Thread 2 をフォローしました。
スタンドアロンプログラムでは正常に動作しますが、これをロジックに含めてレポートから読み取ると、値に異常な違いが生じます。
なぜそれが起こっているのですか、どうすれば修正できますか?
編集:
実際の日数と比較して、日数が増えています。
public static int calculateDifference(Date a, Date b)
{
int tempDifference = 0;
int difference = 0;
Calendar earlier = Calendar.getInstance();
Calendar later = Calendar.getInstance();
if (a.compareTo(b) < 0)
{
earlier.setTime(a);
later.setTime(b);
}
else
{
earlier.setTime(b);
later.setTime(a);
}
while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR))
{
tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR));
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR))
{
tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR);
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
return difference;
}
注:
残念ながら、どの回答も私が問題を解決するのに役立ちませんでした。 この問題Joda-time ライブラリの助けを借りて達成しました。
欠陥のあるJava.util.Dateや友人の代わりに、優れた Joda Time ライブラリを使用することをお勧めします。あなたは単に書くことができます
import Java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.Days;
Date past = new Date(110, 5, 20); // June 20th, 2010
Date today = new Date(110, 6, 24); // July 24th
int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34
ゲームに参加するには遅すぎるかもしれませんが、一体何でしょう? :)
これはスレッドの問題だと思いますか?たとえば、このメソッドの出力をどのように使用していますか?または
コードを変更して、次のような簡単なことを実行できますか?
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(<your earlier date>);
calendar2.set(<your current date>);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffSeconds = diff / 1000;
long diffMinutes = diff / (60 * 1000);
long diffHours = diff / (60 * 60 * 1000);
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("\nThe Date Different Example");
System.out.println("Time in milliseconds: " + diff
+ " milliseconds.");
System.out.println("Time in seconds: " + diffSeconds
+ " seconds.");
System.out.println("Time in minutes: " + diffMinutes
+ " minutes.");
System.out.println("Time in hours: " + diffHours
+ " hours.");
System.out.println("Time in days: " + diffDays
+ " days.");
}
Diff /(24 *など)はタイムゾーンを考慮しないため、デフォルトのタイムゾーンにDSTが含まれている場合、計算がスローされる可能性があります。
この link にはすてきな実装があります。
リンクがダウンした場合の上記リンクのソースは次のとおりです。
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
//assert: startDate must be before endDate
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
そして
/** Using Calendar - THE CORRECT (& Faster) WAY**/
public static long daysBetween(final Calendar startDate, final Calendar endDate)
{
//assert: startDate must be before endDate
int MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
long endInstant = endDate.getTimeInMillis();
int presumedDays =
(int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY);
Calendar cursor = (Calendar) startDate.clone();
cursor.add(Calendar.DAY_OF_YEAR, presumedDays);
long instant = cursor.getTimeInMillis();
if (instant == endInstant)
return presumedDays;
final int step = instant < endInstant ? 1 : -1;
do {
cursor.add(Calendar.DAY_OF_MONTH, step);
presumedDays += step;
} while (cursor.getTimeInMillis() != endInstant);
return presumedDays;
}
Java 8以降では、 Java.timeフレームワーク (- チュートリアル )を使用します。
Duration
Duration
クラスは、時間の長さを秒数と小数秒で表したものです。日、時間、分、秒をカウントできます。
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println(duration.toDays());
ChronoUnit
必要なのが日数だけの場合は、代わりに ChronoUnit
enum を使用できます。計算メソッドがlong
ではなくint
を返すことに注意してください。
long days = ChronoUnit.DAYS.between( then, now );
import Java.util.Calendar;
import Java.util.Date;
public class Main {
public static long calculateDays(String startDate, String endDate)
{
Date sDate = new Date(startDate);
Date eDate = new Date(endDate);
Calendar cal3 = Calendar.getInstance();
cal3.setTime(sDate);
Calendar cal4 = Calendar.getInstance();
cal4.setTime(eDate);
return daysBetween(cal3, cal4);
}
public static void main(String[] args) {
System.out.println(calculateDays("2012/03/31", "2012/06/17"));
}
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
}
違いとして定義するものに依存します。真夜中の2つの日付を比較することができます。
long day1 = ...; // in milliseconds.
long day2 = ...; // in milliseconds.
long days = (day2 - day1) / 86400000;
DST日付の正しい丸めを使用して、ミリ秒の時刻の差を使用するソリューション:
public static long daysDiff(Date from, Date to) {
return daysDiff(from.getTime(), to.getTime());
}
public static long daysDiff(long from, long to) {
return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24
}
1つの注:もちろん、日付は特定のタイムゾーンである必要があります。
重要なコード:
Math.round( (to - from) / 86400000D )
丸めたくない場合は、UTC日付を使用できます。
問題の説明:(私のコードは数週間でデルタを計算していますが、数日でデルタにも同じ問題が当てはまります)
非常に合理的な外観の実装を次に示します。
public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L;
static public int getDeltaInWeeks(Date latterDate, Date earlierDate) {
long deltaInMillis = latterDate.getTime() - earlierDate.getTime();
int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK);
return deltaInWeeks;
}
ただし、このテストは失敗します。
public void testGetDeltaInWeeks() {
delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23);
assertEquals("weeks between Feb23 and Mar09", 2, delta);
}
その理由は:
2009年3月9日00:00:00 EDT 2009 = 1,236,571,200,000
月2月23日00:00:00 EST 2009 = 1,235,365,200,000
MillisPerWeek = 604,800,000
副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example、
(3月9日-2月23日)/ MillisPerWeek =
1,206,000,000/604,800,000 = 1.994 ...
カレンダーを見る人は誰でも答えが2であることに同意するでしょう。
私はこの機能を使用します:
DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days
myfunction:
import Java.util.Date;
public long DATEDIFF(String date1, String date2) {
long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000;
long days = 0l;
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss");
Date dateIni = null;
Date dateFin = null;
try {
dateIni = (Date) format.parse(date1);
dateFin = (Date) format.parse(date2);
days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY;
} catch (Exception e) { e.printStackTrace(); }
return days;
}
@Mad_Trollの回答に基づいて、このメソッドを開発しました。
これに対して約30のテストケースを実行しましたが、これはサブデイタイムフラグメントを正しく処理する唯一の方法です。
例:今&今+ 1ミリ秒を過ぎた場合、それは同じ日になります。 1-1-13 23:59:59.098
を1-1-13 23:59:59.099
にすると、0日が正しく返されます。ここに投稿された他のメソッドの多くは、これを正しく行いません。
それはあなたがそれらをどのように入れるかを気にしません、あなたの終了日があなたの開始日より前である場合、それは逆算されます。
/**
* This is not quick but if only doing a few days backwards/forwards then it is very accurate.
*
* @param startDate from
* @param endDate to
* @return day count between the two dates, this can be negative if startDate is after endDate
*/
public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) {
//Forwards or backwards?
final boolean forward = startDate.before(endDate);
// Which direction are we going
final int multiplier = forward ? 1 : -1;
// The date we are going to move.
final Calendar date = (Calendar) startDate.clone();
// Result
long daysBetween = 0;
// Start at millis (then bump up until we go back a day)
int fieldAccuracy = 4;
int field;
int dayBefore, dayAfter;
while (forward && date.before(endDate) || !forward && endDate.before(date)) {
// We start moving slowly if no change then we decrease accuracy.
switch (fieldAccuracy) {
case 4:
field = Calendar.MILLISECOND;
break;
case 3:
field = Calendar.SECOND;
break;
case 2:
field = Calendar.MINUTE;
break;
case 1:
field = Calendar.HOUR_OF_DAY;
break;
default:
case 0:
field = Calendar.DAY_OF_MONTH;
break;
}
// Get the day before we move the time, Change, then get the day after.
dayBefore = date.get(Calendar.DAY_OF_MONTH);
date.add(field, multiplier);
dayAfter = date.get(Calendar.DAY_OF_MONTH);
// This shifts lining up the dates, one field at a time.
if (dayBefore == dayAfter && date.get(field) == endDate.get(field))
fieldAccuracy--;
// If day has changed after moving at any accuracy level we bump the day counter.
if (dayBefore != dayAfter) {
daysBetween += multiplier;
}
}
return daysBetween;
}
@NotNull
アノテーションを削除できます。これらはIntellijがコード分析をオンザフライで実行するために使用します
このApache commons-langクラスDateUtils
のgetFragmentInDaysメソッドを見てください。
この基本的な機能のための何百行ものコード???
簡単な方法:
protected static int calculateDayDifference(Date dateAfter, Date dateBefore){
return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24);
// MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
}
Vitalii Fedorenkoによる回答 は正しい、 Java.time クラス( Duration
& ChronoUnit
)Java 8以降に組み込み(および Java 6および7にバックポート および にAndroid )。
Days
コードで日数を日常的に使用している場合、単なる整数をクラスの使用に置き換えることができます。 Days
クラスは、Java.timeの拡張であり、Java.timeへの将来の追加の可能性を証明する ThreeTen-Extra プロジェクトにあります。 Days
クラスは、アプリケーションで日数を表すタイプセーフな方法を提供します。クラスには、 ZERO
および ONE
の便利な定数が含まれています。
質問内の古い時代遅れの Java.util.Date
オブジェクトを考えると、まずそれらを現代の Java.time.Instant
オブジェクトに変換してください。古い日時クラスには、Java.timeへの変換を容易にするためのメソッドが新しく追加されました( Java.util.Date::toInstant
など)。
Instant start = utilDateStart.toInstant(); // Inclusive.
Instant stop = utilDateStop.toInstant(); // Exclusive.
両方のInstant
オブジェクトを org.threeten.extra.Days
のファクトリメソッドに渡します。
現在の実装(2016-06)では、これは Java.time.temporal.ChronoUnit.DAYS.between
を呼び出すラッパーです。詳細については、ChronoUnit
クラスのドキュメントを参照してください。明確にするために、すべての大文字のDAYS
はenum ChronoUnit
にありますが、initial-cap Days
はThreeTen-Extraのクラスです。
Days days = Days.between( start , stop );
これらのDays
オブジェクトを独自のコードの周りに渡すことができます。 toString
を呼び出すことにより、標準の ISO 8601 形式の文字列にシリアル化できます。この形式のPnD
は、P
を使用して開始をマークし、D
は「日」を意味し、その間に日数が入ります。 Java.timeクラスとThreeTen-Extraは両方とも、日時値を表す文字列を生成および解析するときに、デフォルトでこれらの標準形式を使用します。
String output = days.toString();
P3D
Days days = Days.parse( "P3D" );
public static int getDifferenceIndays(long timestamp1, long timestamp2) {
final int SECONDS = 60;
final int MINUTES = 60;
final int HOURS = 24;
final int MILLIES = 1000;
long temp;
if (timestamp1 < timestamp2) {
temp = timestamp1;
timestamp1 = timestamp2;
timestamp2 = temp;
}
Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
endDate.setTimeInMillis(timestamp1);
startDate.setTimeInMillis(timestamp2);
if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
int day1 = endDate.get(Calendar.DAY_OF_MONTH);
int day2 = startDate.get(Calendar.DAY_OF_MONTH);
if (day1 == day2) {
return 0;
} else {
return 1;
}
}
int diffDays = 0;
startDate.add(Calendar.DAY_OF_MONTH, diffDays);
while (startDate.before(endDate)) {
startDate.add(Calendar.DAY_OF_MONTH, 1);
diffDays++;
}
return diffDays;
}
「スタンドアロンプログラムでは問題なく動作します」と言いますが、「これをレポートに読み込むためのロジックに含める」と「異常な差分値」を取得します。これは、レポートに正しく機能しない値がいくつかあり、スタンドアロンプログラムにはこれらの値がないことを示しています。スタンドアロンプログラムの代わりに、テストケースをお勧めします。 JUnitのTestCaseクラスからサブクラス化して、スタンドアロンプログラムと同じようにテストケースを作成します。これで、非常に具体的な例を実行して、期待する値を知ることができます(また、今日は時間とともに変化するため、今日はテスト値として与えないでください)。スタンドアロンプログラムで使用した値を入力すると、おそらくテストに合格します。それは素晴らしいことです-あなたはそれらのケースが動作し続けたいです。次に、正しく機能しない値をレポートから追加します。新しいテストはおそらく失敗します。失敗の理由を把握し、修正して、グリーンになります(すべてのテストに合格します)。レポートを実行します。まだ壊れているものを確認してください。テストを書く;それを通過させます。すぐにレポートが機能していることがわかります。
このコードは、2つの日付文字列間の日数を計算します。
static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24;
static final String DATE_FORMAT = "dd-MM-yyyy";
public long daysBetween(String fromDateStr, String toDateStr) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
Date fromDate;
Date toDate;
fromDate = format.parse(fromDateStr);
toDate = format.parse(toDateStr);
return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY;
}
Java Util Dateが誤った値を返すことがあるため、Joda Timeライブラリを使用する必要があります。
Joda vs Java Util Date
たとえば、昨日(dd-mm-yyyy、12-07-2016)と1957年の初日(dd-mm-yyyy、01-01-1957)の間の日:
public class Main {
public static void main(String[] args) {
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date date = null;
try {
date = format.parse("12-07-2016");
} catch (ParseException e) {
e.printStackTrace();
}
//Try with Joda - prints 21742
System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date));
//Try with Java util - prints 21741
System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date));
}
private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) {
DateTime jodaDateTime = new DateTime(date);
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy");
DateTime y1957 = formatter.parseDateTime("01-01-1957");
return Days.daysBetween(y1957 , jodaDateTime).getDays();
}
private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) {
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date y1957 = null;
try {
y1957 = format.parse("01-01-1957");
} catch (ParseException e) {
e.printStackTrace();
}
return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS);
}
Joda Timeライブラリを使用することをお勧めします。
間の適切な数または日数を返すソリューションを探している場合11/30/2014 23:59
および12/01/2014 00:01
は、Joda Timeを使用したソリューションです。
private int getDayDifference(long past, long current) {
DateTime currentDate = new DateTime(current);
DateTime pastDate = new DateTime(past);
return currentDate.getDayOfYear() - pastDate.getDayOfYear();
}
この実装は、1
を日数の差として返します。ここに掲載されているソリューションのほとんどは、2つの日付の差をミリ秒単位で計算します。これらの2つの日付の差は2分しかないため、0
が返されることを意味します。
私はすでにそれについて書きました。これは 2つのJava日付インスタンスの差を計算する からの再投稿です。
public int getDiffernceInDays(long timeAfter, long timeBefore) {
Calendar calendarAfter = Calendar.getInstance();
calendarAfter.setTime(new Date(timeAfter));
Calendar calendarNewAfter = Calendar.getInstance();
calendarNewAfter.set(calendarAfter.get(Calendar.YEAR), calendarAfter.get(Calendar.MONTH), calendarAfter.get(Calendar.DAY_OF_MONTH));
Calendar calendarBefore = Calendar.getInstance();
calendarBefore.setTime(new Date(timeBefore));
Calendar calendarNewBefore = Calendar.getInstance();
calendarNewBefore.set(calendarBefore.get(Calendar.YEAR), calendarBefore.get(Calendar.MONTH), calendarBefore.get(Calendar.DAY_OF_MONTH));
return (int) ((calendarNewAfter.getTime().getTime() - calendarNewBefore.getTime().getTime()) / (24 * 60 * 60 * 1000));
}