输出一个万年历

 

C#代码

 1 static void Date(int year)
 2 {
 3     int lastDays = 0;//定义一个偏移量用来计算每个月的第一天是星期几
 4 
 5     for (int i = 1900; i < year; i++)//1900年1月1日正好是星期一
 6     {
 7         if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)//判断闰年,给偏移赋值
 8         {
 9             lastDays += 366;
10         }
11         else
12         {
13             lastDays += 365;
14         }
15     }
16 
17     for (int j = 1; j <= 12; j++)//用for循环打印每个月份
18     {
19         //判断每个月的第一天是星期几(前面有多少空格)
20         int weekSpace = lastDays % 7;
21         //每个月的天数
22         int monthDays = 0;
23 
24         //输出表头
25         if (j < 10)
26             Console.WriteLine("===========0" + j + "" + "===========");
27         else
28             Console.WriteLine("===========" + j + "" + "===========");
29         Console.WriteLine("" + "" + "" + "" + "" + "" + "");
30 
31         //输出每个月第一天前面的空位
32         for (int m_weekSpace = 1; m_weekSpace <= weekSpace; m_weekSpace++)
33             Console.Write("    ");
34 
35         switch (j)//判断当月天数
36         {
37             case 1: case 3: case 5: case 7: case 8: case 10: case 12:
38                 monthDays = 31; break;
39             case 4: case 6: case 9: case 11:
40                 monthDays = 30; break;
41             case 2:
42                 if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)//判断闰年,给偏移赋值
43                 {
44                     monthDays = 29; 
45                     break;
46                 }
47                 else
48                 {
49                     monthDays = 28; 
50                     break;
51                 }
52         }
53 
54         //打印每一天
55         for (int m_monthDays = 1; m_monthDays <= monthDays; m_monthDays++)
56         {
57             //控制排版
58             if (m_monthDays < 10)
59             {
60                 //判断当前天的下一天是否星期一(是否换行)
61                 if ((m_monthDays + weekSpace) % 7 == 0 && (m_monthDays + weekSpace) >= 7)
62                     Console.WriteLine("0" + m_monthDays);
63                 else
64                     Console.Write("0" + m_monthDays + "  ");
65             }
66             else
67             {
68                 if ((m_monthDays + weekSpace) % 7 == 0 && (m_monthDays + weekSpace) >= 7)
69                     Console.WriteLine(m_monthDays);
70                 else
71                     Console.Write(m_monthDays + "  ");
72             }
73         }
74         Console.WriteLine();
75         Console.WriteLine();
76         lastDays += monthDays;
77     }
78 }

 

 

打印结果:

转载于:https://www.cnblogs.com/wq-KingStrong/p/10268113.html

<think>好的,我现在需要帮用户解决如何用Java写一个万年历的问题。首先,我得理清楚用户的需求。万年历通常需要显示某年某月的日历,包括日期和对应的星期。用户可能希望输入年份和月份,然后程序输出该月的日历表。 首先,我应该考虑如何计算某个月的第一天是星期几。这里可能需要使用Java的日期类,比如Calendar或者LocalDate。不过,考虑到Calendar类在旧版本中常用,而LocalDate是Java 8引入的,更现代,可能更推荐使用LocalDate。不过,用户可能对旧版本的代码更熟悉,需要确认兼容性。但假设用户使用的是较新的Java版本,使用LocalDate会更简洁。 接下来,确定该月的天数。LocalDate有方便的方法可以直接获取月份的天数,比如lengthOfMonth(),这能省去手动计算的麻烦。 然后,需要确定该月1号的星期几,这样才知道在打印日历时前面需要留多少空格。比如,如果1号是星期三,那么前面需要空三个位置(星期日到星期二)。 接下来,考虑如何格式化输出。通常日历的格式是每周七天,每天占固定宽度,比如每个日期占4个字符,这样一行可以放七天。需要按周换行,确保每周的日期对齐。 步骤可能包括: 1. 获取用户输入的年份和月份。 2. 创建LocalDate对象表示该月的第一天。 3. 获取该月的天数。 4. 确定第一天是星期几,计算前面的空格数。 5. 打印星期标题(日 一 二 三 四 五 六)。 6. 循环打印日期,每七天换行,同时处理第一行的空格。 需要注意的问题: - 输入验证:确保年份和月份是有效的,比如月份在1-12之间。 - 星期的排列顺序:中国的习惯通常是从星期日开始还是星期一开始?这里可能需要确认,但一般日历显示周日到周六,或者周一到周日。需要根据常见习惯调整。例如,中国的标准可能将星期一作为一周的第一天,但很多日历显示周日到周六。需要明确用户的需求。例如,使用LocalDate.getDayOfWeek().getValue(),但要注意,LocalDate中周一的值是1,周日是7。可能需要调整。 例如,假设用户希望按照周日到周六的顺序显示,那么当getDayOfWeek()返回SUNDAY时,对应的值是7,但需要转换成0(如果周日是第一天),或者调整计算方法。可能需要将星期几转换为从0开始的索引,比如周日是0,周一到周六是1-6。 例如,LocalDate的getDayOfWeek()返回DayOfWeek枚举,可以通过调整来得到正确的偏移量。例如,如果第一天是2023-10-1(假设是周日),那么其getDayOfWeek().getValue()在Java中是7(因为周一=1,周日=7)。所以,为了得到正确的空格数,可能需要计算(dayOfWeekValue % 7)来将周日转换为0,周一到周六为1-6。或者根据具体情况进行调整。 例如,假设该月的第一天是星期三,那么需要打印三个空格(每个日期占4字符的话),然后在星期三的位置开始打印1号,接着依次排列到该月结束,每七天换行。 然后,如何循环打印日期?例如,先打印前面的空格,然后从1到该月最后一天,每打印一个日期后,判断是否到了周六,如果是则换行。 另一个问题,如何处理输入?用户可能需要通过命令行输入年份和月份,可以使用Scanner类来读取输入。 现在,把这些思路整理成代码步骤: 1. 导入必要的类:LocalDate、Scanner等。 2. 读取用户输入的年份和月份。 3. 创建该年该月的LocalDate对象(例如,使用LocalDate.of(year, month, 1))。 4. 获取该月的天数。 5. 获取该月第一天是星期几,并计算需要前面的空格数。 6. 打印星期标题。 7. 打印空格,然后依次打印日期,每七天换行。 编写代码时需要注意的细节: - 月份的处理:LocalDate的月份是1-12,与用户输入一致。 - 星期几的处理:调整周日的值为0,其他按顺序排列。 - 格式化输出,每个日期占4位,右对齐,例如使用System.out.printf("%4d", day)。 - 处理第一行前面的空格,例如,如果第一天是星期三(即前面需要3个位置),则打印3个空位,每个占4字符,所以总共有3*4=12空格。 - 当打印到周六时换行,即每打印一个日期后,判断是否是该周的第六天(因为周日是0,周六是6),如果是则换行。 例如,假设空格数为空格数,初始值为dayOfWeek的值(周日=0,周一=1等),那么前面的空格数为该值乘以4字符的空格? 或者,假设每个日期占4字符,第一行前面需要dayOfWeek * 4的空格?例如,如果第一天是周三(3),则前面有3个空格,每个占4字符,即总共有3*4=12空格。但可能这里的计算需要更准确,比如,假设周日的索引是0,那么第一天是周三,索引为3,前面需要3个位置的空格,每个位置4字符,那么总共有3 * 4个空格。 然后,在打印日期时,每打印一个日期后,判断当前的位置是否是周六(索引6),如果是,则换行。 现在,具体代码: 例如: import java.time.LocalDate; import java.time.DayOfWeek; import java.util.Scanner; public class万年历 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入年份:"); int year = scanner.nextInt(); System.out.print("请输入月份:"); int month = scanner.nextInt(); LocalDate date = LocalDate.of(year, month, 1); int daysInMonth = date.lengthOfMonth(); DayOfWeek firstDayOfWeek = date.getDayOfWeek(); int firstDayValue = firstDayOfWeek.getValue(); // 周一=1,周日=7 // 转换为周日=0,周一=1,...周六=6 int emptyDays = (firstDayValue % 7); // 例如,周日7%7=0,周一1%7=1,周六6%7=6 System.out.println("日 一 二 三 四 五 六"); // 打印前面的空格,每个占4字符(因为每个日期用%4d) for (int i = 0; i < emptyDays; i++) { System.out.print(" "); // 四个空格 } for (int day = 1; day <= daysInMonth; day++) { System.out.printf("%4d", day); // 判断是否需要换行:当前的位置(emptyDays + day) %7 ==0? // 或者,每次打印后,检查是否是周六(即emptyDays + day-1) %7 ==6? // 因为第一天是emptyDays个空格,之后day从1开始,每打印一个,总位置是 emptyDays + day的位置? // 例如,假设emptyDays=3(周三),那么第一个day=1的位置是3+1=4,即周四,对吗?可能需要重新考虑。 // 或者,每次打印后,判断当前是否是星期六,即(当前的空格数 + day -1) %7 ==6? // 这里可能比较复杂,可以采用另一种方法:维护一个计数器,记录当前打印的位置(0-6) int currentPosition = (emptyDays + day -1) %7; if (currentPosition ==6) { System.out.println(); } } // 打印完后换行,如果最后一行未满 if ((emptyDays + daysInMonth) %7 !=0) { System.out.println(); } } } 但这里可能存在错误。例如,假设emptyDays是周日(0),那么第一天是周日,打印1,位置0,此时currentPosition是0+1-1=0,判断是否是6?显然不对。这说明我的计算有误。 可能我需要重新考虑如何计算换行。例如,假设第一天是周日(emptyDays=0),那么当打印1时,位置是0(周日),之后每次打印,currentPosition递增。例如,每打印一个日期,currentPosition = (emptyDays + day -1) %7。例如,当emptyDays=0,day=1时,0+1-1=0,即周日,正确。当day=2,0+2-1=1,即周一,直到day=7时,0+7-1=6,即周六,此时换行。这似乎正确。 例如,假设emptyDays=3(周三),day=1,则3+1-1=3(周三),打印后判断是否3%7=3,不是6,所以不换行。继续到day=4,3+4-1=6 →6%7=6 →换行。所以,在周三的位置开始,1号的位置是3,当打印到4号时,是周六,换行。这样是否正确? 例如,假设该月有31天,第一天是周三: 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 ... 那么,第一个行打印了1(周三)、2(周四)、3(周五)、4(周六)后换行。然后5是周日,下一行开始。但按照上述代码逻辑,当day=4时,3+4-1=6 →6%7=6 →换行。这会导致在4号后面换行,正确。然后day=5开始新的一行。是的,这样是对的。 那代码中的换行条件是正确的。所以,代码中的判断条件应该是: if ((emptyDays + day -1) %7 ==6) →换行。 这样就能在每周六之后换行。 但是,在计算emptyDays的时候,是否正确? 原来的emptyDays的计算是:firstDayValue %7。这里,firstDayValue是DayOfWeek的getValue(),即周一到周日对应1-7。例如,当第一天是周日时,firstDayValue=7 →7%7=0 →emptyDays=0。周一的话是1%7=1 →emptyDays=1。这是正确的,因为周日作为第一天,不需要空格,而周一则需要一个空格(前面有一个位置的空格,即周日的位置)。 所以,代码中的emptyDays的计算是正确的。 接下来,打印星期标题是否正确?用户可能需要的是“日 一 二 三 四 五 六”,每个字之间用空格分隔,这样显示更清晰。例如,System.out.println("日 一 二 三 四 五 六"); 每个占两个字符宽度,但实际每个日期用%4d,可能对不齐。可能需要调整,比如每个星期标题的每个部分占4字符,例如: System.out.println(" 日 一 二 三 四 五 六 "); 这样每个标题占4字符,与下面的日期对齐。但这样可能更美观。例如: System.out.printf("%s%n", " 日 一 二 三 四 五 六"); 或者,用更精确的格式,每个占3字符(包括空格),比如: System.out.println("日 一 二 三 四 五 六"); 但实际打印的日期是4字符宽度,这样可能导致标题和日期列不对齐。例如,日期用%4d,每个日期占4字符,如“ 1”,而标题中的“日”占一个字符,后面三个空格。这样可能对不齐。因此,可能需要让标题的每个星期几也占4字符宽度。例如: System.out.print(" 日 "); System.out.print(" 一 "); ... 但这样会比较麻烦。或者使用格式化的方式: System.out.printf("%4s%4s%4s%4s%4s%4s%4s%n", "日", "一", "二", "三", "四", "五", "六"); 这样每个星期几占4字符宽度,与下面的日期对齐。这样更整齐。 修改这部分代码: System.out.printf("%4s%4s%4s%4s%4s%4s%4s%n", "日", "一", "二", "三", "四", "五", "六"); 然后,打印空格的时候,每个占4字符,例如: for (int i = 0; i < emptyDays; i++) { System.out.print(" "); // 四个空格 } 这样,当emptyDays是3的时候,会打印12个空格,正好对应三个4字符的位置。然后打印日期时,每个日期占4字符,这样就能对齐。 例如,当emptyDays=3,打印三个4字符空格,接着1号在第4个位置(周三的位置)。这样,整个日历的列就能对齐。 现在,测试代码是否正确: 假设输入2023年10月,1号是周日? 例如,2023-10-1是周日吗?根据实际日期,可能需要验证。但假设用户输入的是2023年10月,那么: LocalDate date = LocalDate.of(2023, 10, 1); DayOfWeek firstDay = date.getDayOfWeek(); →应该是SUNDAY吗? 在Java中,2023年10月1日的星期天?实际查日历的话,2023年10月1日是星期日。所以,firstDayValue=7,emptyDays=7%7=0,所以无需空格。打印1号在周日的位置,之后每7天换行。 这样代码是否正确? 是的,此时emptyDays=0,循环打印日期时,每个日期的currentPosition是 (0 + day -1) %7。例如,day=1 →0 →周日,打印后,currentPosition=0,不是6,不换行。直到day=7 →0+7-1=6 →6%7=6 →换行。这样,第一行打印1-7号,周日到周六,然后换行。第二行从8号(周日)开始。这样是否正确? 是的。那代码应该正确。 另一个测试案例,比如2023年12月1日是星期五。那emptyDays的值: LocalDate.of(2023,12,1).getDayOfWeek().getValue() →星期五对应的getValue()是5(周一=1,周五=5),所以 firstDayValue=5 →5%7=5 →emptyDays=5。所以,需要打印5个4字符的空格,即5*4=20空格。然后日期从第6个位置(周六的位置)开始?这可能有问题。因为如果1号是周五,那么前面的空格数应该是5(周日到周四共5天),所以emptyDays=5。例如: 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 ... 这样是否正确?是的。因为周五是第五个位置(假设周日是0,周一到周四为1-4,所以emptyDays=5)。然后1号在周五的位置,即第五个位置(从0开始数的话,0是周日,1周一,2周二,3周三,4周四,5周五,6周六)。所以,当emptyDays=5时,前面打印5个空格,每个占4字符,这样1号的位置是第五个,对应周五。然后2号是周六,打印后换行。之后3号是周日,换到下一行。这样对吗? 是的。所以代码中的逻辑是正确的。 现在,如何处理输入验证?例如,用户输入月份13,或者0,应该如何处理?此时LocalDate.of会抛出DateTimeException。所以需要添加try-catch块来处理异常,提示用户输入正确的月份。 例如: try { LocalDate date = LocalDate.of(year, month, 1); } catch (DateTimeException e) { System.out.println("输入的月份无效,请输入1-12之间的数字。"); return; } 同样,年份可能有范围,但LocalDate支持很大的年份范围,所以可能不需要处理,除非用户输入非常大的数值导致内存问题,但一般不需要。 所以,在代码中添加异常处理: import java.time.DateTimeException; ... try { LocalDate date = LocalDate.of(year, month, 1); } catch (DateTimeException e) { System.out.println("输入的月份或年份无效,请重新输入。"); scanner.close(); return; } 然后,继续执行后续代码。 综上,完整的代码应该包括输入处理、异常处理、正确的空格计算、日期打印和换行逻辑。 最后,还需要在打印完所有日期后检查是否需要换行,避免最后一行未满时光标留在行中间,导致命令行提示符出现在同一行。例如,在代码最后添加: // 打印完后换行,如果最后一行未满 if ((emptyDays + daysInMonth) %7 !=0) { System.out.println(); } 例如,假设emptyDays + daysInMonth = 31 + emptyDays。假设emptyDays=3,总共有31天,则3+31=34 →34%7=34-7*4=34-28=6 →不等于0,所以需要换行。这样,最后一天打印后,如果没有换行,则添加换行。 这样,整个代码的结构就比较完整了。</think>以下是使用Java编写万年历的步骤及示例代码: ### 实现思路 1. **获取输入**:读取用户输入的年份和月份。 2. **计算首日星期**:确定该月第一天是星期几。 3. **计算总天数**:获取该月的总天数。 4. **格式化输出**:按周排列日期,对齐星期。 ### 代码示例 ```java import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Scanner; public class PerpetualCalendar { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入年份:"); int year = scanner.nextInt(); System.out.print("请输入月份:"); int month = scanner.nextInt(); try { // 创建日期对象,指向该月第一天 LocalDate firstDayOfMonth = LocalDate.of(year, month, 1); // 获取该月天数 int daysInMonth = firstDayOfMonth.lengthOfMonth(); // 计算第一天是星期几(调整后:周日=0,周一=1,...周六=6) int firstDayOfWeek = firstDayOfMonth.getDayOfWeek().getValue() % 7; // 打印表头 System.out.printf("%4s%4s%4s%4s%4s%4s%4s%n", "日", "一", "二", "三", "四", "五", "六"); // 打印首行缩进 for (int i = 0; i < firstDayOfWeek; i++) { System.out.print(" "); } // 打印日期并换行 for (int day = 1; day <= daysInMonth; day++) { System.out.printf("%4d", day); // 判断是否换行:当前总位置(首日缩进+已打印天数)是否为周六 if ((firstDayOfWeek + day) % 7 == 0) { System.out.println(); } } // 若最后一行未满,补充换行 if ((firstDayOfWeek + daysInMonth) % 7 != 0) { System.out.println(); } } catch (Exception e) { System.out.println("输入错误,请确保月份为1-12的整数!"); } finally { scanner.close(); } } } ``` ### 关键步骤说明 1. **输入处理** - 使用`Scanner`读取用户输入的年份和月份。 - 通过`try-catch`捕获非法输入(如月份为13)。 2. **日期计算** - `LocalDate.of(year, month, 1)`生成该月第一天的日期对象。 - `lengthOfMonth()`直接获取该月天数,避免手动计算闰年。 - `getDayOfWeek().getValue() % 7`将星期转换为**周日=0,周一=1,...周六=6**的格式。 3. **排版对齐** - **表头**:使用`%4s`格式化每个星期名称,确保列宽一致。 - **首行缩进**:根据首日星期数打印对应空格(每个占4字符)。 - **换行逻辑**:每打印7个日期后换行,通过`(firstDayOfWeek + day) % 7 == 0`判断。 ### 示例输出 输入`2023年10月`时,输出如下: ``` 请输入年份:2023 请输入月份:10 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ``` ### 注意事项 - **输入验证**:确保月份为1-12,年份为合理值。 - **日期库选择**:使用`java.time.LocalDate`(Java 8+)简化日期计算。 - **对齐优化**:若需更紧凑的排版,可将`%4d`改为`%3d`并调整空格数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值