04 JAVA 常用类补充 Scanner和日历

本文探讨了懒人的日常习惯,如沉迷娱乐节目和通宵达旦,以及如何通过正则表达式、日期处理和日历来提高时间管理能力。文章还提供了关于日期格式转换和日历可视化的实用技巧。

哎哎哎,我好懒啊,整天watch variety shows and stay up all night for nothing meaningful,又没有钱去玩~(天气好热,科科~贱人就是矫情,还不想去找工作,自己这么说自己也是够了,双重人格~)—— bulltrue少年


一、Scanner

Scanner可以从特定文件(我们需要提供文件或者文件路径),输入流,字符串等产生对应值(使用正则表达式parse原语类型和字符串)

主要方法:

- hasNext() 假如输入还有别的token返回布尔值

- hasNext(正则表达式) 假如下个完整的token匹配这个正则表达式返回布尔值

- hasNextLine() 可以加入正则表达式

- hasNextInt() 可以加入正则表达式

- hasNextDouble() 可以加入正则表达式

- String next() 返回下一个token

String next(正则表达式)

- int nextInt() 可以加入正则表达式

- double nextDouble() 可以加入正则表达式

- String nextLine() 返回当前行

- close()

- useDelimiter(分隔符)

import java.util.*;


public class testScanner {
	public static void main(String[] args) {
		String c = "";
		Scanner sc1 = new Scanner(System.in);

		while(sc1.hasNext()){
			c = sc1.next();
			if(c.equals("*")){
				break;
			}
			System.out.println(c);
		}
		sc1.close();
	}
}

结果:

Amy Mark Anna Terrisa *

Amy

Mark

Anna

Terrisa


二、日期

- Date (时刻<->Date对象)

获取一个特定的瞬间时刻(精确到毫秒,long类型,从1970.1.1 00.00.00开始)并构造成Date类型对象

Date() //默认使用当前时间

Date(long)

主要方法:

- long getTime() 返回某个时刻

- setTime(long time) 设置Date对象来表示某个时刻

- boolean after(Date)

- boolean before(Date)

System.currentTimeMillis() 获取当前时刻


- DateFormat(抽象类,字符串<->Date对象)

子类SimpleDateFormat

SimpleDateFormat()

SimpleDateFormat(String pattern)

Date and Time PatternResult
"yyyy.MM.dd G 'at' HH:mm:ss z"2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy"Wed, Jul 4, '01
"h:mm a"12:08 PM
"hh 'o''clock' a, zzzz"12 o'clock PM, Pacific Daylight Time
"K:mm a, z"0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa"02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z"Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ"010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ"2001-07-04T12:08:56.235-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"2001-07-04T12:08:56.235-07:00
"YYYY-'W'ww-u"2001-W27-3

- String format(Date)

- Date parse(String)

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class testDate {
	public static void main(String[] args) {
		Date d = new Date();
		long ts = d.getTime();
		
		System.out.println(ts+"--"+System.currentTimeMillis());
		d.setTime(1345777767889L);
		System.out.println(d);
		
		DateFormat df = new SimpleDateFormat("yyyy.MM.dd");
		System.out.println(df.format(d));
		String date = "2015.8.1"; //要注意格式的统一,比如2015-8-1就不可以啦
		try {
			System.out.println(df.parse(date));
		} catch (ParseException e) {
			e.printStackTrace();
		}
结果:

1437999349348--1437999349348

Fri Aug 24 11:09:27 CST 2012

2012.08.24

Sat Aug 01 00:00:00 CST 2015


- Calendar(抽象类)

执行与日期处理有关的操作,它的子类GregorianCalendar表示的是阳历

主要方法:

- Date getTime() 获取表达日历时间值得日期对象

- setTime(Date)

- long getTimeInMillis() 获取表达日历时间的long值

- setTimeInMillis(long)

- getTimeZone() 获取时区

- add(区域,数值)

- set(区域,数值)

- get(区域)

import java.util.*;

public class testCalendar {
	public static void main(String[] args) {
		//Calendar c1 = new GregorianCalendar();
		Calendar c = Calendar.getInstance(); //用默认的timezone和locale来创建日历
		Date date = new Date();
		c.setTime(date);
		System.out.println(c.get(Calendar.DAY_OF_WEEK));	//一周的第几天
		System.out.println(c.get(Calendar.DAY_OF_YEAR));	//一年中的第几天
		System.out.println(c.get(Calendar.DAY_OF_MONTH));	//一月中的第一天
		System.out.println(c.get(Calendar.DATE));	//日期
		System.out.println(c.get(Calendar.HOUR));	//显示目前几点
		System.out.println(c.get(Calendar.YEAR));
		System.out.println(c.get(Calendar.WEEK_OF_MONTH));	//一个月中的第几周
		System.out.println(c.get(Calendar.WEEK_OF_YEAR));	//一年中的第几周
	}
}

习题:可视化日历

import java.text.*;
import java.util.*;

public class VisualCalendar {
	public static void main(String[] args) {
		System.out.print("输入日期,格式为YYYY-MM-DD:");
		Scanner sn = new Scanner(System.in);
		String s = sn.next();
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		
		try {
			Date date = df.parse(s);
			System.out.println(date+"\n");
			Calendar c = new GregorianCalendar();
			c.setTime(date);
			int day = c.get(Calendar.DATE);
			c.set(Calendar.DATE, 1);
			int day_week = c.get(Calendar.DAY_OF_WEEK);
			int month = c.getActualMaximum(Calendar.DATE);
			System.out.println("日\t一\t二\t三\t四\t五\t六");
			
			for(int j = 1; j < day_week; j++) {
				System.out.print(" \t");
			}
			
			for(int i = 1; i <= month; i++) {
				if(day == i) 
					System.out.print("*");
				System.out.print(i+"\t");
				if((i+day_week-1)%7 == 0)
					System.out.println("\n");
			}
		} catch (ParseException e) {
			System.out.println("格式错误!");
		}
	}
}

结果:


<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、付费专栏及课程。

余额充值