
本文详解如何使用 Java 的 printf 格式化输出修复日历打印中日期列不对齐的问题,通过统一字段宽度、调整首行缩进和居中标题,使星期与日期严格按列对齐。
本文详解如何使用 java 的 `printf` 格式化输出修复日历打印中日期列不对齐的问题,通过统一字段宽度、调整首行缩进和居中标题,使星期与日期严格按列对齐。
在实现控制台日历打印时,一个常见但易被忽视的问题是:日期数字未能与星期标题(Sun/Mon/Tue…)垂直对齐。例如,原始代码输出中,4月2020日历的“1”出现在“Mon”下方而非“Sun”,导致视觉混乱——根本原因在于空格填充方式不一致:用多个 " " 字符拼接无法保证等宽对齐,尤其当数字从个位过渡到十位时(如 1 vs 10),字符数差异直接破坏列结构。
✅ 正确解决方案:统一使用 printf 控制字段宽度
Java 的 System.out.printf() 支持格式化占位符,可精确指定输出宽度与对齐方式。核心思路是:所有日期均占用固定 4 字符宽度(%4s),右对齐(默认行为),并确保首行空格也按相同单位补足。
1. 修正首行缩进(补齐起始空白)
原代码用 for (i = 0; i 仅输出单个空格,但星期标题(如 <code>" Sun")实际宽度为 4 字符(含前导空格)。应改为:
// 每个星期列宽为 4 字符(" Sun" → 4 chars),故用 4 空格对齐
for (int i = 0; i < startDay; i++) {
System.out.print(" "); // 4 个空格
}2. 统一日期输出格式
替换原 System.out.print(" " + i) 逻辑,全部使用 %4s:
for (int day = 1; day <= numberOfDaysInMonth; day++) {
System.out.printf("%4d", day); // %4d 自动右对齐,不足补空格
if ((day + startDay) % 7 == 0) { // 每满 7 天换行
System.out.println();
}
}
// 补全最后一行末尾换行(避免末尾无换行导致格式错乱)
if ((numberOfDaysInMonth + startDay) % 7 != 0) {
System.out.println();
}✅ 优势:
%4d对1输出" 1",对10输出" 10",始终占 4 位,完美匹配" Sun"的列宽。
3. (可选)优化标题居中显示
当前月份名称左对齐,可借助 printf 居中提升美观度。已知日历总宽度为 29 字符("-----------------------------" 长度),标题居中需计算偏移量:
static void printMonthTitle(int year, int month) {
String title = getMonthName(month) + " " + year;
int totalWidth = 29;
int padding = (totalWidth - title.length()) / 2;
System.out.printf("%" + padding + "s%s%n", "", title);
System.out.println("-----------------------------");
System.out.println(" Sun Mon Tue Wed Thu Fri Sat");
}? 提示:
%" + padding + "s表示左侧填充padding个空格,再输出title;%n是平台安全的换行符。
⚠️ 注意事项
-
方法声明顺序:确保
getStartDay()及其依赖的getTotalNumberOfDays()、getNumberOfDaysInMonth()、isLeapYear()在调用前已定义(当前代码结构已满足,无需调整)。 -
闰年逻辑验证:
isLeapYear()实现正确(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)),但需注意getTotalNumberOfDays()中对 1800 年起始日的假设(1800-01-01 为星期三)是否符合需求。 -
边界测试:务必验证 1 月、2 月(闰年/平年)、12 月及跨年场景,确保
startDay计算无偏差。
通过上述三步改造,日历输出将严格对齐,兼具专业性与可维护性——格式化输出不仅是“看起来更整齐”,更是构建健壮文本界面的基础实践。

















