[Java] 201712-3 Crontab

  • 代码比较长,300+行,核心逻辑倒不复杂
  • 参考了java time库的LocalDateTime源码设计
  • 还有一个有趣的数学函数是直接根据年、月、日求解出星期几
  • 样例输入
3 201711170032 201711222352
0 7 * * 1,3-5 get_up
30 23 * * Sat,Sun go_to_bed
15 12,18 * * * have_dinner
  • 样例输出
201711170700 get_up
201711171215 have_dinner
201711171815 have_dinner
201711181215 have_dinner
201711181815 have_dinner
201711182330 go_to_bed
201711191215 have_dinner
201711191815 have_dinner
201711192330 go_to_bed
201711200700 get_up
201711201215 have_dinner
201711201815 have_dinner
201711211215 have_dinner
201711211815 have_dinner
201711220700 get_up
201711221215 have_dinner
201711221815 have_dinner
import java.io.*;
import java.util.*;

class Crontab
{
	// map供月份与星期的英文缩写对照
	private static Map<String, Integer> map = new HashMap<String, Integer>() {
		{
			put("jan", 1);
			put("feb", 2);
			put("mar", 3);
			put("apr", 4);
			put("may", 5);
			put("jun", 6);
			put("jul", 7);
			put("aug", 8);
			put("sep", 9);
			put("oct", 10);
			put("nov", 11);
			put("dec", 12);
			put("sun", 0);
			put("mon", 1);
			put("tue", 2);
			put("wed", 3);
			put("thu", 4);
			put("fri", 5);
			put("sat", 6);
		}
	};

	private Set<Integer> min = new HashSet<>();
	private Set<Integer> h = new HashSet<>();
	private Set<Integer> dm = new HashSet<>();
	private Set<Integer> mon = new HashSet<>();
	private Set<Integer> dw = new HashSet<>();
	private String command;

	// 这里是用来处理减号的
	private void dealMinusSign(Set<Integer> set, String str)
	{
		int idx = str.indexOf('-');
		String start = str.substring(0, idx);
		String end = str.substring(idx + 1);
		int i = map.containsKey(start) ? map.get(start) : Integer.parseInt(start);
		int j = map.containsKey(end) ? map.get(end) : Integer.parseInt(end);
		while (i <= j) {
			set.add(i++);
		}
	}

	private void initial(Set<Integer> set, String str) 
	{
		if (str.contains(",")) {
			String[] arr_set = str.split(",");
			for (String s : arr_set) {
				if (s.contains("-")) {
					dealMinusSign(set, s);
				}
				else {
					set.add(map.containsKey(s) ? map.get(s) : Integer.parseInt(s));
				}
			}
		}
		else if (str.contains("-")) {
			dealMinusSign(set, str);
		}
		else {
			set.add(map.containsKey(str) ? map.get(str) : Integer.parseInt(str));
		}
	}

	// 配置信息格式:
	// <minutes> <hours> <day of month> <month> <day of Week> <command>
	public Crontab(String config) 
	{
		String[] arr = config.split(" ");
		String minutes		= arr[0]; // 可能有前导0
		String hours 		= arr[1]; // 可能有前导0
		String dayOfMonth 	= arr[2];
		// 不区分大小写,之前没有注意到,改完从80分到100分
		String month 		= arr[3].toLowerCase();
		String dayOfWeek	= arr[4].toLowerCase();
		this.command		= arr[5];

		if (minutes.equals("*")) {
			for (int i = 0; i < 60; i++) {
				min.add(i);
			}
		}
		else {
			initial(min, minutes);
		}

		if (hours.equals("*")) {
			for (int i = 0; i < 24; i++) {
				h.add(i);
			}
		}
		else {
			initial(h, hours);
		}

		if (dayOfMonth.equals("*")) {
			for (int i = 1; i < 32; i++) {
				dm.add(i);
			}
		}
		else {
			initial(dm, dayOfMonth);
		}
	
		if (month.equals("*")) {
			for (int i = 1; i < 13; i++) {
				mon.add(i);
			}
		}
		else {
			initial(mon, month);
		}

		if (dayOfWeek.equals("*")) {
			for (int i = 0; i < 7; i++) {
				dw.add(i);
			}
		}
		else {
			initial(dw, dayOfWeek);
		}
	}

	public boolean fitTheTime(MyTime currentTime)
	{
		if (!dw.contains(currentTime.getDayOfWeek())) {
			return false;
		}
		if (!min.contains(currentTime.getMinute())) {
			return false;
		}
		if (!h.contains(currentTime.getHour())) {
			return false;
		}
		if (!dm.contains(currentTime.getDayOfMonth())) {
			return false;
		}
		if (!mon.contains(currentTime.getMonth())) {
			return false;
		}
		return true;
	}

	public String getCommand() {
		return command;
	}
}

class MyTime {
	private int year;
	private int month;
	private int dayOfMonth;
	private int hour;
	private int minute;
	private int dayOfWeek;

	public int getYear() {
		return year;
	}

	public int getMonth() {
		return month;
	}

	public int getDayOfMonth() {
		return dayOfMonth;
	}

	public int getHour() {
		return hour;
	}

	public int getMinute() {
		return minute;
	}

	public int getDayOfWeek() {
		return dayOfWeek;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + year;
		result = prime * result + month;
		result = prime * result + dayOfMonth;
		result = prime * result + hour;
		result = prime * result + minute;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MyTime other = (MyTime) obj;
		if (year != other.year)
			return false;
		if (month != other.month)
			return false;
		if (dayOfMonth != other.dayOfMonth)
			return false;
		if (hour != other.hour)
			return false;
		if (minute != other.minute)
			return false;
		return true;
	}

	// 题目给出的时间格式:yyyyMMddHHmm
	public MyTime(String str) {
		this.year	= Integer.parseInt(str.substring(0, 4));
		this.month	= Integer.parseInt(str.substring(4, 6));
		this.dayOfMonth = Integer.parseInt(str.substring(6, 8));
		this.hour	= Integer.parseInt(str.substring(8, 10));
		this.minute	= Integer.parseInt(str.substring(10, 12));
		this.dayOfWeek = initialDayOfWeek();
	}

	// Sakamoto's methods
	private int initialDayOfWeek() {
		int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
		int y = year;
		if (month < 3) {
			y--;
		}
		return (y + y/4 - y/100 + y/400 + t[month - 1] + dayOfMonth) % 7;
	}

	@Override
	public String toString() {
		// 输出格式这里调整好后,5分到80分
		return "" + year + String.format("%02d%02d%02d%02d", month, dayOfMonth, hour, minute);
	}

	public void plusMinute() {
		minute++;
		if (minute == 60) {
			minute = 0;
			hour++;
			if (hour == 24) {
				hour = 0;
				dayOfMonth++;
				dayOfWeek = (dayOfWeek + 1) % 7; 
				switch (month) 
				{
					case 2:
						if (isLeapYear() && dayOfMonth == 30) {
							dayOfMonth = 1;
							month++;
						}
						else if (!isLeapYear() && dayOfMonth == 29) {
							dayOfMonth = 1;
							month++;
						}
						break;
					case 1:
					case 3:
					case 5:
					case 7:
					case 8:
					case 10:
					case 12:
						if (dayOfMonth == 32) {
							dayOfMonth = 1;
							month++;
						}
						break;
					case 4:
					case 6:
					case 9:
					case 11:
						if (dayOfMonth == 31) {
							dayOfMonth = 1;
							month++;
						}
						break;
				}
				if (month == 13) {
					month = 1;
					year++;
				}
			}
		}
	}

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

public class Main {

    public static void main(String[] args) throws IOException {
		// Use BufferedReader rather than RandomAccessFile; it's much faster
		BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

		// Use StringTokenizer vs. readLine/split -- lots faster
		StringTokenizer st = new StringTokenizer(f.readLine());
	    int n = Integer.parseInt(st.nextToken());

		// 创建属于自建的时间格式
		MyTime currentTime = new MyTime(st.nextToken());
		MyTime endTime = new MyTime(st.nextToken());
		// System.out.println(new MyTime("197001012321").getDayOfWeek());

		Crontab[] crontabs = new Crontab[n];
		for (int i = 0; i < n; i++)
		{
			String config = f.readLine();
			crontabs[i] = new Crontab(config);
		}

		while (!currentTime.equals(endTime)) {
			for (int i = 0; i < n; i++) {
				if (crontabs[i].fitTheTime(currentTime)) {
					out.println(currentTime + " " + crontabs[i].getCommand());
				}
			}
			currentTime.plusMinute();
		}
	    out.close();
	    f.close();
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值