You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Date类两种星期计算方法出错,请求排查错误

自定义Java Date类星期计算方法错误排查

问题描述

我需要为自定义Java Date类实现两种星期计算方法:

  • 基于参考日期(2023年5月14日为周日)的周偏移法
  • 基于Zeller同余式的模运算方法

但当前代码返回结果全部错误,例如输入2030年3月17日时:

  • 参考日期法输出周三
  • Zeller算法输出周五
  • 正确结果应为周日

要求:禁止使用任何内置日期类或函数,原代码如下:

import java.util.Scanner;
import java.util.Comparator;

class DateComparator implements Comparator<Date> {
    @Override
    public int compare(Date date1, Date date2) {
        int yearComparison = Integer.compare(date1.getYear(), date2.getYear());
        if (yearComparison != 0) {
            return yearComparison;
        }

        int monthComparison = Integer.compare(date1.getMonth(), date2.getMonth());
        if (monthComparison != 0) {
            return monthComparison;
        }

        return Integer.compare(date1.getDay(), date2.getDay());
    }
}

class Month {
    private int monthNumber;
    private String name;
    private int days;

    public Month(int monthNumber, String name, int days) {
        this.monthNumber = monthNumber;
        this.name = name;
        this.days = days;
    }

    public int getMonthNumber() {
        return monthNumber;
    }

    public int getDays() {
        return days;
    }

    public void setDays(int days) {
        this.days = days;
    }
}

public class Date {
    Months monthsObj = new Months();
    private int year;
    private int month;
    private int day;

    public Date() {}

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() { return year; }
    public void setYear(int year) { this.year = year; }
    public int getMonth() { return month; }
    public void setMonth(int month) { this.month = month; }
    public int getDay() { return day; }
    public void setDay(int day) { this.day = day; }

    public void printDate() {
        System.out.println(year + "-" + month + "-" + day);
    }

    public void incrementWeek() {
        int daysInMonth = monthsObj.getDaysInMonth(year, month);
        day += 7;
        if (day > daysInMonth) {
            day -= daysInMonth;
            month++;
            if (month > 12) {
                year++;
                month = 1;
            }
        }
    }

    public void decrementWeek() {
        int daysInPreviousMonth;
        int daysToRemove = 8 - day;
        if (daysToRemove <= 0) {
            day -= 7;
        } else {
            month--;
            if (month == 0) {
                month = 12;
                year--;
            }
            daysInPreviousMonth = monthsObj.getDaysInMonth(year, month);
            day = daysInPreviousMonth + 1 - daysToRemove;
        }
    }

    public void whatDay() {
        int h = (day + 13 * (month + 1) / 5 + year % 100 + (year % 100) / 4 + (year / 100) / 4 - 2 * (year / 100)) % 7;
        String[] days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
        System.out.println(days[h]);
    }

    public void moveWeek(Date reference, Date calendar, int result) {
        String[] days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};

        if (result > 0) {
            while((reference.getYear() != calendar.getYear()) || (reference.getMonth() != calendar.getMonth()) || (reference.getDay()-calendar.getDay() >= 7)){
                calendar.incrementWeek();
                calendar.printDate();
            }
        }

        if (result < 0) {
            while((reference.getYear() != calendar.getYear()) || (reference.getMonth() != calendar.getMonth()) || ((reference.getDay()-calendar.getDay() >= 7)||(reference.getDay()- calendar.getDay()<0))){
                calendar.decrementWeek();
                calendar.printDate();
            }
        }

        int difference = reference.getDay() - calendar.getDay();
        System.out.println(days[6-difference]);
    }

    public static void main(String[] args) {
        DateComparator comparator = new DateComparator();
        Scanner sc = new Scanner(System.in);
        System.out.println("podaj dzien, miesiac i rok:");
        int day = sc.nextInt();
        int month = sc.nextInt();
        int year = sc.nextInt();

        Date reference = new Date(2023, 5, 14);
        Date calendar = new Date(year, month, day);
        calendar.moveWeek(reference, calendar, comparator.compare(reference, calendar));
        calendar.whatDay();
    }
}

class Months {
    private static final Month[] months = {
            new Month(1, "January", 31),
            new Month(2, "February", 28),
            new Month(3, "March", 31),
            new Month(4, "April", 30),
            new Month(5, "May", 31),
            new Month(6, "June", 30),
            new Month(7, "July", 31),
            new Month(8, "August", 31),
            new Month(9, "September", 30),
            new Month(10, "October", 31),
            new Month(11, "November", 30),
            new Month(12, "December", 31)
    };

    public boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 !=0) || year % 400 == 0;
    }

    public int getDaysInMonth(int year, int month) {
        if(isLeapYear(year) && month == 2){
            months[1].setDays(29);
        }
        return months[month-1].getDays();
    }
}

错误修复方案

一、Zeller同余式方法(whatDay())修复

原公式未遵循Zeller规则,且索引映射完全错误,修复后代码:

public void whatDay() {
    int y = year;
    int m = month;
    // Zeller规则:1、2月视为上一年的13、14月
    if (m < 3) {
        y--;
        m += 12;
    }
    int q = day;
    int k = y % 100; // 年份后两位
    int j = y / 100; // 年份前两位
    // 标准Zeller同余式
    int h = (q + (13 * (m + 1)) / 5 + k + k / 4 + j / 4 + 5 * j) % 7;
    // 映射结果到正确星期顺序:h=0→周六,h=1→周日,以此类推
    String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    int index = (h + 6) % 7;
    System.out.println(days[index]);
}

二、参考日期偏移法(moveWeek())修复

原循环逻辑混乱,通过日差计算星期的方式完全错误,改为计算总天数差的方案:

1. 添加总天数计算辅助方法

在Date类中新增:

// 计算从公元1年1月1日到当前日期的总天数
private long getTotalDays() {
    long total = 0;
    // 累加整年天数
    for (int i = 1; i < year; i++) {
        total += monthsObj.isLeapYear(i) ? 366 : 365;
    }
    // 累加当月前的月份天数
    for (int i = 1; i < month; i++) {
        total += monthsObj.getDaysInMonth(year, i);
    }
    // 累加当月天数
    total += day;
    return total;
}

2. 重写moveWeek()方法

public void moveWeek(Date reference) {
    String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    int refIndex = 0; // 参考日期是周日,对应数组索引0
    // 计算总天数差
    long dayDiff = this.getTotalDays() - reference.getTotalDays();
    // 处理负数偏移
    int offset = (int) (dayDiff % 7);
    if (offset < 0) {
        offset += 7;
    }
    // 计算目标星期索引
    int targetIndex = (refIndex + offset) % 7;
    System.out.println(days[targetIndex]);
}

3. 修改main方法调用

替换原调用代码:

calendar.moveWeek(reference);

三、其他潜在问题修复

  1. Months类闰年处理bug:原代码会永久修改静态数组中二月的天数,修复后:
public int getDaysInMonth(int year, int month) {
    if (month == 2 && isLeapYear(year)) {
        return 29;
    }
    return months[month-1].getDays();
}
  1. decrementWeek()逻辑错误:简化日期回退逻辑:
public void decrementWeek() {
    day -= 7;
    if (day < 1) {
        month--;
        if (month == 0) {
            month = 12;
            year--;
        }
        int daysInPreviousMonth = monthsObj.getDaysInMonth(year, month);
        day = daysInPreviousMonth + day;
    }
}

内容的提问来源于stack exchange,提问作者Ala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:46:59