我使用这两个网站来衡量我的代码的接近程度。
我使用零年以来的天数来标准化两个输入的日期,然后找到这些日期之间的差异。
import java.util.Scanner;
public class DateDiff {
private static final int[] monthsDay = {31,28,31,30,31,30,31,31,30,31,30,31};
public static String dateChecker() {
boolean b = true;
int dateC = 0;
String date = "";
do {
Scanner scanner = new Scanner(System.in);
date = scanner.nextLine();
try {
if (date.charAt(2) == '/' && date.charAt(5) == '/') {
date = date.replace("/", "");
dateC = Integer.parseInt(date);
b = false;
} else {
System.out.println("Reenter date in the dd/mm/yyyy format");
}
} catch (Exception e) {
System.out.println("Reenter date in the dd/mm/yyyy format");
}
} while (b);
return date;
}
public static int daysForMonth(int months, int year) {
int days = 0;
for (int i = 0; i < months; i++)
if (i == 1)
days += ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
? monthsDay[i] + 1
: monthsDay[i];
else
days += monthsDay[i];
return days;
}
public static int daysForYears(int year) {
int days = 0;
for (int i = 0; i < year; i++)
if ((i % 4 == 0 && (i % 100 != 0)) || (i % 400 == 0))
days += 366;
else
days += 365;
return days;
}
public static int daysSinceYearZero(String date) {
int day = Integer.parseInt(date.substring(0,2));
int month = Integer.parseInt(date.substring(2,4));
int year = Integer.parseInt(date.substring(4,8));
int daysMonth = daysForMonth(month-1, year);
int daysYear = daysForYears(year);
return day + daysMonth + daysYear;
}
public static void main(String[] args) {
System.out.println("Enter first date");
String date1 = dateChecker();
System.out.println("Enter second date");
String date2 = dateChecker();
int firstDate = daysSinceYearZero(date1);
int secondDate = daysSinceYearZero(date2);
System.out.println("First Date days since Year Zero: " + firstDate);
System.out.println("Second Date days since Year Zero: " + secondDate);
System.out.println("Difference: " + Math.abs(firstDate-secondDate));
}
}
我的代码很接近,但似乎总是会错过几天,我不明白为什么。我已经确认 days 和 daysMonth 是正确的,但不明白使用年份(daysYear 变量)计算自零年以来的天数时出错的地方
编辑:不允许使用任何库。不过,扫描仪很好,因为它仅用于用户输入。
最佳答案
由于您没有解释任何要求或限制,您可以这样做。
LocalDate earliest = LocalDate.parse("2012-05-17");
LocalDate latest = LocalDate.parse("2022-06-22");
System.out.println(latest.toEpochDay()-earliest.toEpochDay());
打印
3688 (exclusive of the latest date day)
但是,这是一种在家种植它的方法。我使用 lambda 来简化该过程。并且计算中不需要循环。所以这会以恒定的时间运行。
- 首先,我创建了一个
IntTrinaryOperator
接口(interface)。
interface IntTrinaryOperator {
public int applyAsInt(int a, int b, int c);
}
然后创建了一个月日数组(闰年稍后处理),第一个单元格将被忽略,但以下操作是必需的。
int daysPerMonth[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int monthSums[] = daysPerMonth.clone();
// this creates a running sum
// looks like [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]
// the last cell is not used.
Arrays.parallelPrefix(monthSums, (a, b) -> a + b);
闰年函数
Function<Integer, Boolean> isLeapYear =
a -> a % 400 == 0 || (a % 100 != 0 && a % 4 == 0);
以及定义的用于实际计算的 Trinary。
(y-1)*365-(y-1)/100+(y-1)/4 +(y-1)/400
- 计算从上一年开始的总闰年。- 每年 365 天的第一个总天数
- 然后减去世纪年
- 然后添加可被 400 整除的年份。
monthSums[m-1]+d
- 添加今年的天数((m > 2) && isLeapYear.apply(y) ? 1 : 0) - 1
- 如果在二月
之后,则再添加一天,但减去1
排除当前日期(如 Java 中的大多数范围)
IntTrinaryOperator daysToEpoch = (y, m, d) -> (y - 1) * 365
- (y - 1) / 100 + (y - 1) / 4 + (y - 1) / 400 +
+ monthSums[m - 1] + d
+ ((m > 2) && isLeapYear.apply(y) ? 1 : 0) - 1;
测试
- 生成一些日期。日期不是按时间顺序排列的,因此天数可能为负数,因此
Math.abs()
Random r = new Random();
for (int i = 0; i < 10; i++) {
int eYear = r.nextInt(2022) + 1;
int eMonth = r.nextInt(12) + 1;
int eDay = r.nextInt(daysPerMonth[eMonth])
+ (eMonth == 2 && isLeapYear.apply(eYear) ? 1 :
0);
int sYear = r.nextInt(2022) + 1;
int sMonth = r.nextInt(12) + 1;
int sDay = r.nextInt(daysPerMonth[sMonth])
+ (sMonth == 2 && isLeapYear.apply(sYear) ? 1 :
0);
int eDaysToEpoch =
daysToEpoch.applyAsInt(eYear, eMonth, eDay);
int sDaysToEpoch =
daysToEpoch.applyAsInt(sYear, sMonth, sDay);
System.out.printf("%02d/%02d/%04d - %02d/%02d/%04d - %,9d total days%n",
eMonth, eDay, eYear, sMonth, sDay, sYear, Math.abs(eDaysToEpoch-sDaysToEpoch));
}
以及原始日期
System.out.println(daysToEpoch.applyAsInt(2022, 6, 22)-
daysToEpoch.applyAsInt(2012, 5, 17));
打印类似的内容。
04/10/1377 - 12/03/1486 - 40,048 total days
02/12/0727 - 03/27/0196 - 193,899 total days
11/26/0457 - 12/09/0307 - 54,775 total days
02/25/0691 - 10/23/1596 - 330,785 total days
03/28/0404 - 01/16/1567 - 424,705 total days
10/18/0372 - 01/15/1316 - 344,512 total days
08/01/1374 - 01/23/1484 - 39,986 total days
03/21/0622 - 07/24/0495 - 46,260 total days
02/05/1167 - 08/05/1558 - 142,991 total days
12/02/1824 - 07/21/0976 - 309,859 total days
3688
这已经使用上面首先显示的 API 方法进行了测试。经过超过 100 万次随机测试,没有发现任何差异。
这是一个日期验证方法。它检查闰年和闰日与月份。它还允许使用个位数表示月份和日期。它不会产生详细的错误消息。我继续重新提示,直到输入有效日期。否则,日、月、年将以数组形式返回。
public static int[] getDate(Scanner scanner) {
String stringDate = "\\d\\d?/\\d\\d?/\\d{4}";
while (true) {
System.out.println(
"Please enter date in dd/mm/yyyy format.");
String date = scanner.nextLine();
if (date.matches(stringDate)) {
int[] dmy = Arrays.stream(date.split("/"))
.mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(dmy));
int d = dmy[0];
int m = dmy[1];
int y = dmy[2];
if (d > 0 && m > 0 && m < 13 && y > 0) {
boolean isLeap = isLeapYear.apply(y);
if (isLeap && d <= 29 && m == 2) {
return dmy;
}
if (d <= daysPerMonth[m]) {
return dmy;
}
}
}
System.out.print("Illegal date: ");
}
}
关于java - 我试图手动计算两个日期之间的天数差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71717253/