Java工具集-日期(DateUtils)
- 2019 年 10 月 28 日
- 筆記
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42528266/article/details/102622081
简单工具类
写作初衷:由于日常开发经常需要用到很多工具类,经常根据需求自己写也比较麻烦 网上好了一些工具类例如commom.lang3或者hutool或者Jodd这样的开源工具,但是 发现他们之中虽然设计不错,但是如果我想要使用,就必须要引入依赖并且去维护依赖,有些 甚至会有存在版本编译不通过问题,故此想要写作一个每个类都可以作为独立工具类使用 每个使用者只需要复制该类,到任何项目当中都可以使用,所以需要尊从以下两个原则才能 做到.在此诚邀各位大佬参与.可以把各自用过的工具,整合成只依赖JDK,每个类都能够单独 使用的工具.每个人当遇到业务需求需要使用的时候,只需要到这里单独拷贝一个即可使用. 抛弃传统的需要引入依赖的烦恼.让大家一起来解决你所面临的业务问题吧!
介绍
遵从两大原则
- 1.绝不依赖JDK以外的源码
- 2.牺牲代码复用性,每个类都必须是单独的组件,绝不互相引用,做到完全解耦
package *; import java.io.IOException; import java.io.ObjectInputStream; import java.text.DateFormat; import java.text.DateFormatSymbols; import java.text.FieldPosition; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.TimeZone; /** * @program: simple_tools * @description: * @author: ChenWenLong * @create: 2019-06-04 16:19 **/ public class DateUtils { //无时区的格式化 public static final FastDateFormat ISO_DATETIME_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss"); //带时区的格式化 public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ"); //纯日期格式化 public static final FastDateFormat ISO_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd"); //带时区的日期格式化 public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-ddZZ"); //不带时区的时间格式化 public static final FastDateFormat ISO_TIME_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ss"); //带时区的时间格式化 public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ssZZ"); //没有T前缀的,非ISO8601规范的时间格式化 public static final FastDateFormat ISO_TIME_NO_T_FORMAT = FastDateFormat.getInstance("HH:mm:ss"); //带时区的,非ISO8601规范的时间格式化 public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT = FastDateFormat.getInstance("HH:mm:ssZZ"); public static final FastDateFormat SMTP_DATETIME_FORMAT = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; //世界时间格式 public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT"); //每秒=1000毫秒 public static final long MILLIS_PER_SECOND = 1000; //每分钟=60秒 public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; //每小时=60分钟 public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; //每天=24小时 public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; //表示半个月,这个表示是上半旬还是下半旬 public final static int SEMI_MONTH = 1001; public final static int RANGE_WEEK_SUNDAY = 1; public final static int RANGE_WEEK_MONDAY = 2; public final static int RANGE_WEEK_RELATIVE = 3; public final static int RANGE_WEEK_CENTER = 4; public final static int RANGE_MONTH_SUNDAY = 5; public final static int RANGE_MONTH_MONDAY = 6; private static final int[][] fields = { {Calendar.MILLISECOND}, {Calendar.SECOND}, {Calendar.MINUTE}, {Calendar.HOUR_OF_DAY, Calendar.HOUR}, {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM}, {Calendar.MONTH, SEMI_MONTH}, {Calendar.YEAR}, {Calendar.ERA}}; /** * 功能描述: * 〈判断是否是同一天,接受Date类型〉 * * @params : [date1, date2] * @return : boolean * @author : cwl * @date : 2019/6/6 11:00 */ public static boolean isSameDay(Date date1, Date date2) { if (date1 == null || date2 == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar cal1 = Calendar.getInstance(); cal1.setTime(date1); Calendar cal2 = Calendar.getInstance(); cal2.setTime(date2); return isSameDay(cal1, cal2); } /** * 功能描述: * 〈判断是否是同一天,接受Calendar〉 * * @params : [cal1, cal2] * @return : boolean * @author : cwl * @date : 2019/6/6 11:01 */ public static boolean isSameDay(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The date must not be null"); } return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); } /** * 功能描述: * 〈判断是否是同一时间,接受Date类型〉 * * @params : [date1, date2] * @return : boolean * @author : cwl * @date : 2019/6/6 11:02 */ public static boolean isSameTime(Date date1, Date date2) { if (date1 == null || date2 == null) { throw new IllegalArgumentException("The date must not be null"); } return date1.getTime() == date2.getTime(); } /** * 功能描述: * 〈判断是否是同一时间,接受Calendar〉 * * @params : [cal1, cal2] * @return : boolean * @author : cwl * @date : 2019/6/6 11:03 */ public static boolean isSameTime(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The date must not be null"); } return cal1.getTime().getTime() == cal2.getTime().getTime(); } /** * 功能描述: * 〈是否是同一地区是时间,即将二手Calendar类型.Date类型并没有地区这种说法〉 * * @params : [cal1, cal2] * @return : boolean * @author : cwl * @date : 2019/6/6 11:07 */ public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The date must not be null"); } return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) && cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) && cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) && cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.getClass() == cal2.getClass()); } /** * 功能描述: * 〈尝试用不同的格式去格式化字符串日期〉 * * @params : [str, parsePatterns] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:19 */ public static Date parseDate(String str, String[] parsePatterns) throws ParseException { if (str == null || parsePatterns == null) { throw new IllegalArgumentException("Date and Patterns must not be null"); } SimpleDateFormat parser = null; ParsePosition pos = new ParsePosition(0); for (int i = 0; i < parsePatterns.length; i++) { if (i == 0) { parser = new SimpleDateFormat(parsePatterns[0]); } else { parser.applyPattern(parsePatterns[i]); } pos.setIndex(0); Date date = parser.parse(str, pos); if (date != null && pos.getIndex() == str.length()) { return date; } } throw new ParseException("Unable to parse the date: " + str, -1); } /** * 功能描述: * 〈解析时间格式〉 * * @params : [str] * @return : java.util.Date * @author : cwl * @date : 2019/10/17 16:47 */ public static Date parseDate(Object str) { if (str == null) { return null; } try { return parseDate(str.toString(), parsePatterns); } catch (ParseException e) { return null; } } /** * 功能描述: * 〈加amount年〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:22 */ public static Date addYears(Date date, int amount) { return add(date, Calendar.YEAR, amount); } /** * 功能描述: * 〈加amount月〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:22 */ public static Date addMonths(Date date, int amount) { return add(date, Calendar.MONTH, amount); } /** * 功能描述: * 〈加amount月〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:23 */ public static Date addWeeks(Date date, int amount) { return add(date, Calendar.WEEK_OF_YEAR, amount); } /** * 功能描述: * 〈加amount天〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:23 */ public static Date addDays(Date date, int amount) { return add(date, Calendar.DAY_OF_MONTH, amount); } /** * 功能描述: * 〈标准格式化时间.传入毫秒数mills和pattern格式〉 * * @params : [millis, pattern] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:29 */ public static String formatUTC(long millis, String pattern) { return format(new Date(millis), pattern, UTC_TIME_ZONE, null); } /** * 功能描述: * 〈加amount小时〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:24 */ public static Date addHours(Date date, int amount) { return add(date, Calendar.HOUR_OF_DAY, amount); } /** * 功能描述: * 〈标准格式化时间,传入date时间格式,pattern格式〉 * * @params : [date, pattern] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:30 */ public static String formatUTC(Date date, String pattern) { return format(date, pattern, UTC_TIME_ZONE, null); } /** * 功能描述: * 〈加amount分钟〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:24 */ public static Date addMinutes(Date date, int amount) { return add(date, Calendar.MINUTE, amount); } /** * 功能描述: * 〈加amount秒〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:24 */ public static Date addSeconds(Date date, int amount) { return add(date, Calendar.SECOND, amount); } /** * 功能描述: * 〈加amount毫秒〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:33 */ public static Date addMilliseconds(Date date, int amount) { return add(date, Calendar.MILLISECOND, amount); } /** * 功能描述: * 〈添加年/月/日/时/分/秒/毫秒 amount为添加量〉 * * @params : [date, calendarField, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:34 */ public static Date add(Date date, int calendarField, int amount) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar c = Calendar.getInstance(); c.setTime(date); c.add(calendarField, amount); return c.getTime(); } /** * 功能描述: * 〈设置date年份,并返回一个新的日期〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:35 */ public static Date setYears(Date date, int amount) { return set(date, Calendar.YEAR, amount); } /** * 功能描述: * 〈设置date月份,返回一个新的日期〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:36 */ public static Date setMonths(Date date, int amount) { return set(date, Calendar.MONTH, amount); } /** * 功能描述: * 〈设置date日期,返回一个新的日期〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:37 */ public static Date setDays(Date date, int amount) { return set(date, Calendar.DAY_OF_MONTH, amount); } /** * 功能描述: * 〈设置时间,返回一个新的时间〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:38 */ public static Date setHours(Date date, int amount) { return set(date, Calendar.HOUR_OF_DAY, amount); } /** * 功能描述: * 〈设置时间,返回一个新的时间〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:38 */ public static Date setMinutes(Date date, int amount) { return set(date, Calendar.MINUTE, amount); } /** * 功能描述: * 〈设置时间,返回一个新的时间〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:39 */ public static Date setSeconds(Date date, int amount) { return set(date, Calendar.SECOND, amount); } /** * 功能描述: * 〈设置时间,返回一个新的时间〉 * * @params : [date, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:39 */ public static Date setMilliseconds(Date date, int amount) { return set(date, Calendar.MILLISECOND, amount); } /** * 功能描述: * 〈设置时间〉 * * @params : [date, calendarField, amount] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 11:40 */ private static Date set(Date date, int calendarField, int amount) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } // getInstance() returns a new object, so this method is thread safe. Calendar c = Calendar.getInstance(); c.setLenient(false); c.setTime(date); c.set(calendarField, amount); return c.getTime(); } /** * 功能描述: * 〈对日期Date类型进行四舍五入〉 * * @params : [date, field] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 13:58 */ public static Date round(Date date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar gval = Calendar.getInstance(); gval.setTime(date); modify(gval, field, true); return gval.getTime(); } /** * 功能描述: * 〈对日历类Calander类型进行四舍五入〉 * * @params : [date, field] * @return : java.util.Calendar * @author : cwl * @date : 2019/6/6 13:58 */ public static Calendar round(Calendar date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar rounded = (Calendar) date.clone(); modify(rounded, field, true); return rounded; } /** * 功能描述: * 〈对Date类型或者Calendar类型进行四舍五入〉 * * @params : [date, field] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 14:02 */ public static Date round(Object date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } if (date instanceof Date) { return round((Date) date, field); } else if (date instanceof Calendar) { return round((Calendar) date, field).getTime(); } else { throw new ClassCastException("Could not round " + date); } } /** * 功能描述: * 〈截断日期,例如可以对分钟数进行取整截断,或者对小时进行取整截断,或者对秒数取整截断.仅接受日期类Date〉 * * @params : [date, field] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 14:04 */ public static Date truncate(Date date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar gval = Calendar.getInstance(); gval.setTime(date); modify(gval, field, false); return gval.getTime(); } /** * 功能描述: * 〈截断日期,例如可以对分钟数进行取整截断,或者对小时进行取整截断,或者对秒数取整截断.仅接受日历类Calendar〉 * * @params : [date, field] * @return : java.util.Calendar * @author : cwl * @date : 2019/6/6 14:06 */ public static Calendar truncate(Calendar date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar truncated = (Calendar) date.clone(); modify(truncated, field, false); return truncated; } /** * 功能描述: * 〈截断日期,例如可以对分钟数进行取整截断,或者对小时进行取整截断,或者对秒数取整截断.接受日历类和日期类〉 * * @params : [date, field] * @return : java.util.Date * @author : cwl * @date : 2019/6/6 14:09 */ public static Date truncate(Object date, int field) { if (date == null) { throw new IllegalArgumentException("The date must not be null"); } if (date instanceof Date) { return truncate((Date) date, field); } else if (date instanceof Calendar) { return truncate((Calendar) date, field).getTime(); } else { throw new ClassCastException("Could not truncate " + date); } } private static void modify(Calendar val, int field, boolean round) { if (val.get(Calendar.YEAR) > 280000000) { throw new ArithmeticException("Calendar value too large for accurate calculations"); } if (field == Calendar.MILLISECOND) { return; } // 手动截断毫秒、秒和分钟,而不是使用日历方法。 Date date = val.getTime(); long time = date.getTime(); boolean done = false; // 截断毫秒 int millisecs = val.get(Calendar.MILLISECOND); if (!round || millisecs < 500) { time = time - millisecs; } if (field == Calendar.SECOND) { done = true; } // 截断秒 int seconds = val.get(Calendar.SECOND); if (!done && (!round || seconds < 30)) { time = time - (seconds * 1000L); } if (field == Calendar.MINUTE) { done = true; } // 截断分钟 int minutes = val.get(Calendar.MINUTE); if (!done && (!round || minutes < 30)) { time = time - (minutes * 60000L); } // 重新设置时间 if (date.getTime() != time) { date.setTime(time); val.setTime(date); } // ----------------- Fix for LANG-59 ----------------------- END ---------------- boolean roundUp = false; for (int i = 0; i < fields.length; i++) { for (int j = 0; j < fields[i].length; j++) { if (fields[i][j] == field) { //This is our field... we stop looping if (round && roundUp) { if (field == SEMI_MONTH) { //判断这是每个月的上半旬还是下半旬,如果是上半旬,那么就加上15天减去1个月 if (val.get(Calendar.DATE) == 1) { val.add(Calendar.DATE, 15); } else { val.add(Calendar.DATE, -15); val.add(Calendar.MONTH, 1); } } else { //这里需要+1,因为最后一个数字是四舍五入的 val.add(fields[i][0], 1); } } return; } } // 对各种不同的类型进行四舍五入 int offset = 0; boolean offsetSet = false; switch (field) { case SEMI_MONTH: if (fields[i][0] == Calendar.DATE) { offset = val.get(Calendar.DATE) - 1; //如果offset大于15,那么说明是在下半个月 if (offset >= 15) { offset -= 15; } //记录下我们是在这个范围的上半部分还是下半部分 roundUp = offset > 7; offsetSet = true; } break; case Calendar.AM_PM: if (fields[i][0] == Calendar.HOUR_OF_DAY) { //对小时字段的值进行处理 offset = val.get(Calendar.HOUR_OF_DAY); if (offset >= 12) { offset -= 12; } roundUp = offset > 6; offsetSet = true; } break; } if (!offsetSet) { int min = val.getActualMinimum(fields[i][0]); int max = val.getActualMaximum(fields[i][0]); //从允许的最小值计算偏移量 offset = val.get(fields[i][0]) - min; //如果这是介于最小值和最大值之间的一半以上,则设置汇总 roundUp = offset > ((max - min) / 2); } //我们需要移除这个字段 if (offset != 0) { val.set(fields[i][0], val.get(fields[i][0]) - offset); } } throw new IllegalArgumentException("The field " + field + " is not supported"); } /** * 功能描述: * 〈通过毫秒数millis,指定地区Locale,指定格式pattern 标准格式化时间〉 * * @params : [millis, pattern, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:31 */ public static String formatUTC(long millis, String pattern, Locale locale) { return format(new Date(millis), pattern, UTC_TIME_ZONE, locale); } /** * 功能描述: * 〈返回一个从focus开始的迭代器〉 * * @params : [focus, rangeStyle] * @return : java.util.Iterator * @author : cwl * @date : 2019/6/6 14:38 */ public static Iterator iterator(Date focus, int rangeStyle) { if (focus == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar gval = Calendar.getInstance(); gval.setTime(focus); return iterator(gval, rangeStyle); } /** * 功能描述: * 〈返回一个从focus开始的迭代器〉 * * @params : [focus, rangeStyle] * @return : java.util.Iterator * @author : cwl * @date : 2019/6/6 14:54 */ public static Iterator iterator(Calendar focus, int rangeStyle) { if (focus == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar start = null; Calendar end = null; int startCutoff = Calendar.SUNDAY; int endCutoff = Calendar.SATURDAY; switch (rangeStyle) { case RANGE_MONTH_SUNDAY: case RANGE_MONTH_MONDAY: // 从fucus当中截取它的月份作为起始月 start = truncate(focus, Calendar.MONTH); // 拷贝起始月作为结束月,并且对结束月进行加一个月减一天的操作 end = (Calendar) start.clone(); end.add(Calendar.MONTH, 1); end.add(Calendar.DATE, -1); // 循环开始到开始到开始时间的前一个周一或者是周日 if (rangeStyle == RANGE_MONTH_MONDAY) { startCutoff = Calendar.MONDAY; endCutoff = Calendar.SUNDAY; } break; case RANGE_WEEK_SUNDAY: case RANGE_WEEK_MONDAY: case RANGE_WEEK_RELATIVE: case RANGE_WEEK_CENTER: // 从fucus当中截取它的月份作为起始月 start = truncate(focus, Calendar.DATE); end = truncate(focus, Calendar.DATE); switch (rangeStyle) { case RANGE_WEEK_SUNDAY: // already set by default break; case RANGE_WEEK_MONDAY: startCutoff = Calendar.MONDAY; endCutoff = Calendar.SUNDAY; break; case RANGE_WEEK_RELATIVE: startCutoff = focus.get(Calendar.DAY_OF_WEEK); endCutoff = startCutoff - 1; break; case RANGE_WEEK_CENTER: startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3; endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3; break; } break; default: throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid."); } if (startCutoff < Calendar.SUNDAY) { startCutoff += 7; } if (startCutoff > Calendar.SATURDAY) { startCutoff -= 7; } if (endCutoff < Calendar.SUNDAY) { endCutoff += 7; } if (endCutoff > Calendar.SATURDAY) { endCutoff -= 7; } while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) { start.add(Calendar.DATE, -1); } while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) { end.add(Calendar.DATE, 1); } return new DateIterator(start, end); } /** * 功能描述: * 〈获取一个日期类date或者是日历类Calendar迭代器对象〉 * * @params : [focus, rangeStyle] * @return : java.util.Iterator * @author : cwl * @date : 2019/6/6 14:59 */ public static Iterator iterator(Object focus, int rangeStyle) { if (focus == null) { throw new IllegalArgumentException("The date must not be null"); } if (focus instanceof Date) { return iterator((Date) focus, rangeStyle); } else if (focus instanceof Calendar) { return iterator((Calendar) focus, rangeStyle); } else { throw new ClassCastException("Could not iterate based on " + focus); } } //============================分割时间-仅Date类型============================== /** * 功能描述: * 〈分割出对应时间点的毫秒数〉 * * @params : [date, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:03 */ public static long getFragmentInMilliseconds(Date date, int fragment) { return getFragment(date, fragment, Calendar.MILLISECOND); } /** * 功能描述: * 〈分割出对应时间的秒数〉 * * @params : [date, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:03 */ public static long getFragmentInSeconds(Date date, int fragment) { return getFragment(date, fragment, Calendar.SECOND); } /** * 功能描述: * 〈分割出对应时间的秒数〉 * * @params : [date, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:08 */ public static long getFragmentInMinutes(Date date, int fragment) { return getFragment(date, fragment, Calendar.MINUTE); } /** * 功能描述: * 〈分割出对应时间段的小时数〉 * * @params : [date, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:08 */ public static long getFragmentInHours(Date date, int fragment) { return getFragment(date, fragment, Calendar.HOUR_OF_DAY); } /** * 功能描述: * 〈分割出对应时间的天数〉 * * @params : [date, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:10 */ public static long getFragmentInDays(Date date, int fragment) { return getFragment(date, fragment, Calendar.DAY_OF_YEAR); } //============================分割时间-仅Date类型============================== //==========================分割时间-仅Calendar类型============================ /** * 功能描述: * 〈分割时间毫秒数〉 * * @params : [calendar, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:12 */ public static long getFragmentInMilliseconds(Calendar calendar, int fragment) { return getFragment(calendar, fragment, Calendar.MILLISECOND); } /** * 功能描述: * 〈分割时间秒数〉 * * @params : [calendar, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:13 */ public static long getFragmentInSeconds(Calendar calendar, int fragment) { return getFragment(calendar, fragment, Calendar.SECOND); } /** * 功能描述: * 〈分割时间分钟数〉 * * @params : [calendar, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:13 */ public static long getFragmentInMinutes(Calendar calendar, int fragment) { return getFragment(calendar, fragment, Calendar.MINUTE); } /** * 功能描述: * 〈分割时间小时数〉 * * @params : [calendar, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:14 */ public static long getFragmentInHours(Calendar calendar, int fragment) { return getFragment(calendar, fragment, Calendar.HOUR_OF_DAY); } /** * 功能描述: * 〈分割时间天数〉 * * @params : [calendar, fragment] * @return : long * @author : cwl * @date : 2019/6/6 15:14 */ public static long getFragmentInDays(Calendar calendar, int fragment) { return getFragment(calendar, fragment, Calendar.DAY_OF_YEAR); } /** * 功能描述: * 〈任意单元碎片的进行切割日期〉 * * @params : [date, fragment, unit] * @return : long * @author : cwl * @date : 2019/6/6 15:16 */ private static long getFragment(Date date, int fragment, int unit) { if(date == null) { throw new IllegalArgumentException("The date must not be null"); } Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return getFragment(calendar, fragment, unit); } /** * 功能描述: * 〈任意单元碎片的进行切割日历类时间〉 * * @params : [calendar, fragment, unit] * @return : long * @author : cwl * @date : 2019/6/6 15:17 */ private static long getFragment(Calendar calendar, int fragment, int unit) { if(calendar == null) { throw new IllegalArgumentException("The date must not be null"); } long millisPerUnit = getMillisPerUnit(unit); long result = 0; // 大于一天的情况都分解成天来计算 switch (fragment) { case Calendar.YEAR: result += (calendar.get(Calendar.DAY_OF_YEAR) * MILLIS_PER_DAY) / millisPerUnit; break; case Calendar.MONTH: result += (calendar.get(Calendar.DAY_OF_MONTH) * MILLIS_PER_DAY) / millisPerUnit; break; } switch (fragment) { // Number of days already calculated for these cases case Calendar.YEAR: case Calendar.MONTH: // The rest of the valid cases case Calendar.DAY_OF_YEAR: case Calendar.DATE: result += (calendar.get(Calendar.HOUR_OF_DAY) * MILLIS_PER_HOUR) / millisPerUnit; case Calendar.HOUR_OF_DAY: result += (calendar.get(Calendar.MINUTE) * MILLIS_PER_MINUTE) / millisPerUnit; case Calendar.MINUTE: result += (calendar.get(Calendar.SECOND) * MILLIS_PER_SECOND) / millisPerUnit; case Calendar.SECOND: result += (calendar.get(Calendar.MILLISECOND) * 1) / millisPerUnit; break; case Calendar.MILLISECOND: break;//never useful default: throw new IllegalArgumentException("The fragment " + fragment + " is not supported"); } return result; } /** * 功能描述: * 〈返回任意单元对应的毫秒数〉 * * @params : [unit] * @return : long * @author : cwl * @date : 2019/6/6 15:19 */ private static long getMillisPerUnit(int unit) { long result; switch (unit) { case Calendar.DAY_OF_YEAR: case Calendar.DATE: result = MILLIS_PER_DAY; break; case Calendar.HOUR_OF_DAY: result = MILLIS_PER_HOUR; break; case Calendar.MINUTE: result = MILLIS_PER_MINUTE; break; case Calendar.SECOND: result = MILLIS_PER_SECOND; break; case Calendar.MILLISECOND: result = 1; break; default: throw new IllegalArgumentException("The unit " + unit + " cannot be represented is milleseconds"); } return result; } /** * 功能描述: * 〈指定日期date格式化〉 * * @params : [date, pattern, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:32 */ public static String formatUTC(Date date, String pattern, Locale locale) { return format(date, pattern, UTC_TIME_ZONE, locale); } /** * 功能描述: * 〈指定格式pattern进行毫秒数格式化〉 * * @params : [millis, pattern] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:32 */ public static String format(long millis, String pattern) { return format(new Date(millis), pattern, null, null); } /** * 功能描述: * 〈指定pattern格式化date日期〉 * * @params : [date, pattern] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:33 */ public static String format(Date date, String pattern) { return format(date, pattern, null, null); } /** * 功能描述: * 〈指定格式化Calendar日历类〉 * * @params : [calendar, pattern] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:33 */ public static String format(Calendar calendar, String pattern) { return format(calendar, pattern, null, null); } /** * 功能描述: * 〈指定时区和格式pattern格式化millis〉 * * @params : [millis, pattern, timeZone] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:34 */ public static String format(long millis, String pattern, TimeZone timeZone) { return format(new Date(millis), pattern, timeZone, null); } /** * 功能描述: * 〈指定日期date和timeZone时区以及格式pattern进行格式化〉 * * @params : [date, pattern, timeZone] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:35 */ public static String format(Date date, String pattern, TimeZone timeZone) { return format(date, pattern, timeZone, null); } /** * 功能描述: * 〈指定时区timeZone,格式pattern,日历类calendar格式化时间〉 * * @params : [calendar, pattern, timeZone] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:35 */ public static String format(Calendar calendar, String pattern, TimeZone timeZone) { return format(calendar, pattern, timeZone, null); } /** * 功能描述: * 〈指定格式和地区格式化date〉 * * @params : [date, pattern, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 18:00 */ public static String format(Date date, String pattern, Locale locale) { return format(date, pattern, null, locale); } /** * 功能描述: * 〈指定地区和格式,格式化毫秒数〉 * * @params : [millis, pattern, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 17:37 */ public static String format(long millis, String pattern, Locale locale) { return format(new Date(millis), pattern, null, locale); } /** * 功能描述: * 〈指定格式和地区格式化日历类〉 * * @params : [calendar, pattern, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 18:01 */ public static String format(Calendar calendar, String pattern, Locale locale) { return format(calendar, pattern, null, locale); } /** * 功能描述: * 〈指定格式时区和地区格式化毫秒数〉 * * @params : [millis, pattern, timeZone, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 18:02 */ public static String format(long millis, String pattern, TimeZone timeZone, Locale locale) { return format(new Date(millis), pattern, timeZone, locale); } /** * 功能描述: * 〈指定格式/时区/地区格式化日期〉 * * @params : [date, pattern, timeZone, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 18:04 */ public static String format(Date date, String pattern, TimeZone timeZone, Locale locale) { FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale); return df.format(date); } /** * 功能描述: * 〈指定格式/时区/地区格式化日历类〉 * * @params : [calendar, pattern, timeZone, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/5 18:05 */ public static String format(Calendar calendar, String pattern, TimeZone timeZone, Locale locale) { FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale); return df.format(calendar); } //迭代日期的构造器 static class DateIterator implements Iterator { private final Calendar endFinal; private final Calendar spot; /** * 功能描述: * 〈从开始日期startFinal到结束日期endFinal的迭代器〉 * * @params : [startFinal, endFinal] * @return : * @author : cwl * @date : 2019/6/6 14:43 */ DateIterator(Calendar startFinal, Calendar endFinal) { super(); this.endFinal = endFinal; spot = startFinal; spot.add(Calendar.DATE, -1); } /** * 功能描述: * 〈迭代器是否已经达到了结束日期〉 * * @params : [] * @return : boolean * @author : cwl * @date : 2019/6/6 14:44 */ public boolean hasNext() { return spot.before(endFinal); } /** * 功能描述: * 〈在迭代器循环当中,返回下一个日历对象〉 * * @params : [] * @return : java.lang.Object * @author : cwl * @date : 2019/6/6 14:45 */ public Object next() { if (spot.equals(endFinal)) { throw new NoSuchElementException(); } spot.add(Calendar.DATE, 1); return spot.clone(); } /** * 功能描述: * 〈覆盖于父类的方法,用于抛出一个不可操作的异常〉 * * @params : [] * @return : void * @author : cwl * @date : 2019/6/6 14:46 */ public void remove() { throw new UnsupportedOperationException(); } } //快速日期格式化 public static class FastDateFormat extends Format{ //支持序列化 private static final long serialVersionUID = 1L; //全样式模式的常量,表示日期格式为全样式 public static final int FULL = DateFormat.FULL; //长区域的时间样式 public static final int LONG = DateFormat.LONG; //中间地区地区的时间样式 public static final int MEDIUM = DateFormat.MEDIUM; //短区域的时间样式 public static final int SHORT = DateFormat.SHORT; //默认的时间样式 private static String cDefaultPattern; //对象缓存 private static final Map cInstanceCache = new HashMap(7); private static final Map cDateInstanceCache = new HashMap(7); private static final Map cTimeInstanceCache = new HashMap(7); private static final Map cDateTimeInstanceCache = new HashMap(7); private static final Map cTimeZoneDisplayCache = new HashMap(7); private final String mPattern;//日期样式 private final TimeZone mTimeZone;//时区 private final boolean mTimeZoneForced;//是否使用默认时区 private final Locale mLocale;//地区 private final boolean mLocaleForced;//是否使用默认地区 private transient int mMaxLengthEstimate;//预计的最大长度 private transient Rule[] mRules; /** * 功能描述: * 〈获取一个默认的日期格式化对象〉 * * @params : [] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:21 */ public static FastDateFormat getInstance() { return getInstance(getDefaultPattern(), null, null); } /** * 功能描述: * 〈获取一个指定的日期格式化对象,指定格式为pattern〉 * * @params : [pattern] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:22 */ public static FastDateFormat getInstance(String pattern) { return getInstance(pattern, null, null); } /** * 功能描述: * 〈创建一个指定格式pattern与时区timeZone的日期格式化对象〉 * * @params : [pattern, timeZone] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:23 */ public static FastDateFormat getInstance(String pattern, TimeZone timeZone) { return getInstance(pattern, timeZone, null); } /** * 功能描述: * 〈创建一个指定格式pattern和指定地区locale的日期格式化对象〉 * * @params : [pattern, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:24 */ public static FastDateFormat getInstance(String pattern, Locale locale) { return getInstance(pattern, null, locale); } /** * 功能描述: * 〈创建一个指定格式pattern,指定时区timeZone,指定地区locale的日期格式化对象,为了避免重复创建,使用synchronize同步方法〉 * * @params : [pattern, timeZone, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:25 */ public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) { FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale); FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat); if (format == null) { format = emptyFormat; format.init(); // convert shell format into usable one cInstanceCache.put(format, format); // this is OK! } return format; } /** * 功能描述: * 〈获得指定日期样式的日期格式化对象〉 * * @params : [style] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:26 */ public static FastDateFormat getDateInstance(int style) { return getDateInstance(style, null, null); } /** * 功能描述: * 〈获得指定日期样式style和地区locale的日期格式化对象〉 * * @params : [style, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:27 */ public static FastDateFormat getDateInstance(int style, Locale locale) { return getDateInstance(style, null, locale); } /** * 功能描述: * 〈获得指定日期样式style和时区timeZone的日期格式化对象〉 * * @params : [style, timeZone] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:28 */ public static FastDateFormat getDateInstance(int style, TimeZone timeZone) { return getDateInstance(style, timeZone, null); } /** * 功能描述: * 〈获得指定日期样式style和时区timeZone以及指定地区locale的日期格式化对象〉 * * @params : [style, timeZone, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:29 */ public static synchronized FastDateFormat getDateInstance(int style, TimeZone timeZone, Locale locale) { Object key = new Integer(style); if (timeZone != null) { key = new Pair(key, timeZone); } if (locale == null) { locale = Locale.getDefault(); } key = new Pair(key, locale); FastDateFormat format = (FastDateFormat) cDateInstanceCache.get(key); if (format == null) { try { SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateInstance(style, locale); String pattern = formatter.toPattern(); format = getInstance(pattern, timeZone, locale); cDateInstanceCache.put(key, format); } catch (ClassCastException ex) { throw new IllegalArgumentException("No date pattern for locale: " + locale); } } return format; } /** * 功能描述: * 〈获得指定时间样式style的日期格式化对象〉 * * @params : [style] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:30 */ public static FastDateFormat getTimeInstance(int style) { return getTimeInstance(style, null, null); } /** * 功能描述: * 〈获得指定地区locale和样式style的时间格式化对象〉 * * @params : [style, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:31 */ public static FastDateFormat getTimeInstance(int style, Locale locale) { return getTimeInstance(style, null, locale); } /** * 功能描述: * 〈获得指定样式style和指定时区timeZone的时间格式化对象〉 * * @params : [style, timeZone] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:31 */ public static FastDateFormat getTimeInstance(int style, TimeZone timeZone) { return getTimeInstance(style, timeZone, null); } /** * 功能描述: * 〈获得指定样式style和指定时区timeZone以及指定地区locale的时间格式化对象〉 * * @params : [style, timeZone, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:32 */ public static synchronized FastDateFormat getTimeInstance(int style, TimeZone timeZone, Locale locale) { Object key = new Integer(style); if (timeZone != null) { key = new Pair(key, timeZone); } if (locale != null) { key = new Pair(key, locale); } FastDateFormat format = (FastDateFormat) cTimeInstanceCache.get(key); if (format == null) { if (locale == null) { locale = Locale.getDefault(); } try { SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getTimeInstance(style, locale); String pattern = formatter.toPattern(); format = getInstance(pattern, timeZone, locale); cTimeInstanceCache.put(key, format); } catch (ClassCastException ex) { throw new IllegalArgumentException("No date pattern for locale: " + locale); } } return format; } /** * 功能描述: * 〈获得时间与日期格式化对象,指定日期样式dateStyle和指定时间样式timeStyle〉 * * @params : [dateStyle, timeStyle] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:33 */ public static FastDateFormat getDateTimeInstance( int dateStyle, int timeStyle) { return getDateTimeInstance(dateStyle, timeStyle, null, null); } /** * 功能描述: * 〈获得时间与日期格式化对象,指定日期样式dateStyle和指定时间样式timeStyle,指定地区locale〉 * * @params : [dateStyle, timeStyle, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:34 */ public static FastDateFormat getDateTimeInstance( int dateStyle, int timeStyle, Locale locale) { return getDateTimeInstance(dateStyle, timeStyle, null, locale); } /** * 功能描述: * 〈获得时间与日期格式化对象,指定日期样式dateStyle和指定时间样式timeStyle,指定时区timeZone〉 * * @params : [dateStyle, timeStyle, timeZone] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:34 */ public static FastDateFormat getDateTimeInstance( int dateStyle, int timeStyle, TimeZone timeZone) { return getDateTimeInstance(dateStyle, timeStyle, timeZone, null); } /** * 功能描述: * 〈获得时间与日期格式化对象,指定日期样式dateStyle和指定时间样式timeStyle,指定时区timeZone,指定地区locale〉 * * @params : [dateStyle, timeStyle, timeZone, locale] * @return : com.simple.util.time.DateUtils.FastDateFormat * @author : cwl * @date : 2019/6/4 17:35 */ public static synchronized FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, TimeZone timeZone, Locale locale) { Object key = new Pair(new Integer(dateStyle), new Integer(timeStyle)); if (timeZone != null) { key = new Pair(key, timeZone); } if (locale == null) { locale = Locale.getDefault(); } key = new Pair(key, locale); FastDateFormat format = (FastDateFormat) cDateTimeInstanceCache.get(key); if (format == null) { try { SimpleDateFormat formatter = (SimpleDateFormat) DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale); String pattern = formatter.toPattern(); format = getInstance(pattern, timeZone, locale); cDateTimeInstanceCache.put(key, format); } catch (ClassCastException ex) { throw new IllegalArgumentException("No date time pattern for locale: " + locale); } } return format; } /** * 功能描述: * 〈获取时区显示名称,使用缓存以提高性能.daylight为是否是白天,style选择样式,locale选择地区〉 * * @params : [tz, daylight, style, locale] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:37 */ public static synchronized String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) { Object key = new TimeZoneDisplayKey(tz, daylight, style, locale); String value = (String) cTimeZoneDisplayCache.get(key); if (value == null) { // This is a very slow call, so cache the results. value = tz.getDisplayName(daylight, style, locale); cTimeZoneDisplayCache.put(key, value); } return value; } /** * 功能描述: * 〈获得默认的日期格式〉 * * @params : [] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:38 */ private static synchronized String getDefaultPattern() { if (cDefaultPattern == null) { cDefaultPattern = new SimpleDateFormat().toPattern(); } return cDefaultPattern; } /** * 功能描述: * 〈创建一个指定样式pattern,指定时区timeZone,指定地区locale的日期格式化对象〉 * * @params : [pattern, timeZone, locale] * @return : * @author : cwl * @date : 2019/6/4 17:39 */ private FastDateFormat(String pattern, TimeZone timeZone, Locale locale) { super(); if (pattern == null) { throw new IllegalArgumentException("The pattern must not be null"); } mPattern = pattern; mTimeZoneForced = (timeZone != null); if (timeZone == null) { timeZone = TimeZone.getDefault(); } mTimeZone = timeZone; mLocaleForced = (locale != null); if (locale == null) { locale = Locale.getDefault(); } mLocale = locale; } /** * 功能描述: * 〈初始化日期格式〉 * * @params : [] * @return : void * @author : cwl * @date : 2019/6/4 17:44 */ private void init() { List rulesList = parsePattern(); mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]); int len = 0; for (int i=mRules.length; --i >= 0; ) { len += mRules[i].estimateLength(); } mMaxLengthEstimate = len; } /** * 功能描述: * 〈获得给定模式的规则集合〉 * * @params : [] * @return : java.util.List * @author : cwl * @date : 2019/6/4 17:45 */ private List parsePattern() { DateFormatSymbols symbols = new DateFormatSymbols(mLocale); List rules = new ArrayList(); String[] ERAs = symbols.getEras(); String[] months = symbols.getMonths(); String[] shortMonths = symbols.getShortMonths(); String[] weekdays = symbols.getWeekdays(); String[] shortWeekdays = symbols.getShortWeekdays(); String[] AmPmStrings = symbols.getAmPmStrings(); int length = mPattern.length(); int[] indexRef = new int[1]; for (int i = 0; i < length; i++) { indexRef[0] = i; String token = parseToken(mPattern, indexRef); i = indexRef[0]; int tokenLen = token.length(); if (tokenLen == 0) { break; } Rule rule; char c = token.charAt(0); switch (c) { case 'G': // era designator (text) rule = new TextField(Calendar.ERA, ERAs); break; case 'y': // year (number) if (tokenLen >= 4) { rule = selectNumberRule(Calendar.YEAR, tokenLen); } else { rule = TwoDigitYearField.INSTANCE; } break; case 'M': // month in year (text and number) if (tokenLen >= 4) { rule = new TextField(Calendar.MONTH, months); } else if (tokenLen == 3) { rule = new TextField(Calendar.MONTH, shortMonths); } else if (tokenLen == 2) { rule = TwoDigitMonthField.INSTANCE; } else { rule = UnpaddedMonthField.INSTANCE; } break; case 'd': // day in month (number) rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); break; case 'h': // hour in am/pm (number, 1..12) rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); break; case 'H': // hour in day (number, 0..23) rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); break; case 'm': // minute in hour (number) rule = selectNumberRule(Calendar.MINUTE, tokenLen); break; case 's': // second in minute (number) rule = selectNumberRule(Calendar.SECOND, tokenLen); break; case 'S': // millisecond (number) rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); break; case 'E': // day in week (text) rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); break; case 'D': // day in year (number) rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); break; case 'F': // day of week in month (number) rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); break; case 'w': // week in year (number) rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); break; case 'W': // week in month (number) rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); break; case 'a': // am/pm marker (text) rule = new TextField(Calendar.AM_PM, AmPmStrings); break; case 'k': // hour in day (1..24) rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); break; case 'K': // hour in am/pm (0..11) rule = selectNumberRule(Calendar.HOUR, tokenLen); break; case 'z': // time zone (text) if (tokenLen >= 4) { rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG); } else { rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.SHORT); } break; case 'Z': // time zone (value) if (tokenLen == 1) { rule = TimeZoneNumberRule.INSTANCE_NO_COLON; } else { rule = TimeZoneNumberRule.INSTANCE_COLON; } break; case ''': // literal text String sub = token.substring(1); if (sub.length() == 1) { rule = new CharacterLiteral(sub.charAt(0)); } else { rule = new StringLiteral(sub); } break; default: throw new IllegalArgumentException("Illegal pattern component: " + token); } rules.add(rule); } return rules; } /** * 功能描述: * 〈解析格式pattern〉 * * @params : [pattern, indexRef] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:47 */ private String parseToken(String pattern, int[] indexRef) { StringBuffer buf = new StringBuffer(); int i = indexRef[0]; int length = pattern.length(); char c = pattern.charAt(i); if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { // Scan a run of the same character, which indicates a time // pattern. buf.append(c); while (i + 1 < length) { char peek = pattern.charAt(i + 1); if (peek == c) { buf.append(c); i++; } else { break; } } } else { // This will identify token as text. buf.append('''); boolean inLiteral = false; for (; i < length; i++) { c = pattern.charAt(i); if (c == ''') { if (i + 1 < length && pattern.charAt(i + 1) == ''') { // '' is treated as escaped ' i++; buf.append(c); } else { inLiteral = !inLiteral; } } else if (!inLiteral && (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { i--; break; } else { buf.append(c); } } } indexRef[0] = i; return buf.toString(); } /** * 功能描述: * 〈获取所需要的数字规则〉 * * @params : [field, padding] * @return : com.simple.util.time.DateUtils.FastDateFormat.NumberRule * @author : cwl * @date : 2019/6/4 17:48 */ private NumberRule selectNumberRule(int field, int padding) { switch (padding) { case 1: return new UnpaddedNumberField(field); case 2: return new TwoDigitNumberField(field); default: return new PaddedNumberField(field, padding); } } /** * 功能描述: * 〈格式化Date或者Calender日期类〉 * * @params : [obj, toAppendTo, pos] * @return : java.lang.StringBuffer * @author : cwl * @date : 2019/6/4 17:50 */ @Override public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { if (obj instanceof Date) { return format((Date) obj, toAppendTo); } else if (obj instanceof Calendar) { return format((Calendar) obj, toAppendTo); } else if (obj instanceof Long) { return format(((Long) obj).longValue(), toAppendTo); } else { throw new IllegalArgumentException("Unknown class: " + (obj == null ? "<null>" : obj.getClass().getName())); } } /** * 功能描述: * 〈格式化毫秒数〉 * * @params : [millis] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:50 */ public String format(long millis) { return format(new Date(millis)); } /** * 功能描述: * 〈格式化date日期类〉 * * @params : [date] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:51 */ public String format(Date date) { Calendar c = new GregorianCalendar(mTimeZone); c.setTime(date); return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString(); } /** * 功能描述: * 〈格式化Clalendar日期〉 * * @params : [calendar] * @return : java.lang.String * @author : cwl * @date : 2019/6/4 17:52 */ public String format(Calendar calendar) { return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString(); } /** * 功能描述: * 〈格式化毫秒数,结果缓存到buf当中〉 * * @params : [millis, buf] * @return : java.lang.StringBuffer * @author : cwl * @date : 2019/6/4 17:52 */ public StringBuffer format(long millis, StringBuffer buf) { return format(new Date(millis), buf); } /** * 功能描述: * 〈格式化Date日期类型,并且将结果缓存到buf当中〉 * * @params : [date, buf] * @return : java.lang.StringBuffer * @author : cwl * @date : 2019/6/4 17:53 */ public StringBuffer format(Date date, StringBuffer buf) { Calendar c = new GregorianCalendar(mTimeZone); c.setTime(date); return applyRules(c, buf); } /** * 功能描述: * 〈格式化Calendar日期类型,并且将结果缓存到buf当中〉 * * @params : [calendar, buf] * @return : java.lang.StringBuffer * @author : cwl * @date : 2019/6/4 17:54 */ public StringBuffer format(Calendar calendar, StringBuffer buf) { if (mTimeZoneForced) { calendar = (Calendar) calendar.clone(); calendar.setTimeZone(mTimeZone); } return applyRules(calendar, buf); } /** * 功能描述: * 〈通过将规则应用于指定的日历来执行格式化〉 * * @params : [calendar, buf] * @return : java.lang.StringBuffer * @author : cwl * @date : 2019/6/4 17:55 */ private StringBuffer applyRules(Calendar calendar, StringBuffer buf) { Rule[] rules = mRules; int len = mRules.length; for (int i = 0; i < len; i++) { rules[i].appendTo(buf, calendar); } return buf; } public String getmPattern() { return mPattern; } public TimeZone getmTimeZone() { return mTimeZone; } public boolean ismTimeZoneForced() { return mTimeZoneForced; } public Locale getmLocale() { return mLocale; } public boolean ismLocaleForced() { return mLocaleForced; } public int getmMaxLengthEstimate() { return mMaxLengthEstimate; } @Override public boolean equals(Object obj) { if (obj instanceof FastDateFormat == false) { return false; } FastDateFormat other = (FastDateFormat) obj; if ( (mPattern == other.mPattern || mPattern.equals(other.mPattern)) && (mTimeZone == other.mTimeZone || mTimeZone.equals(other.mTimeZone)) && (mLocale == other.mLocale || mLocale.equals(other.mLocale)) && (mTimeZoneForced == other.mTimeZoneForced) && (mLocaleForced == other.mLocaleForced) ) { return true; } return false; } @Override public int hashCode() { int total = 0; total += mPattern.hashCode(); total += mTimeZone.hashCode(); total += (mTimeZoneForced ? 1 : 0); total += mLocale.hashCode(); total += (mLocaleForced ? 1 : 0); return total; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); init(); } @Override public String toString() { return "FastDateFormat[" + mPattern + "]"; } //用于定义一个规则的接口 private interface Rule { /** * 功能描述: * 〈返回预计的长度〉 * * @params : [] * @return : int * @author : cwl * @date : 2019/6/4 16:47 */ int estimateLength(); /** * 功能描述: * 〈根据规则实现将指定日历的值添加到StringBuffer缓存当中〉 * * @params : [buffer, calendar] * @return : void * @author : cwl * @date : 2019/6/4 16:48 */ void appendTo(StringBuffer buffer, Calendar calendar); } //定义一个数字的规则 private interface NumberRule extends Rule { /** * 功能描述: * 〈将指定值添加到buffer当中〉 * * @params : [buffer, value] * @return : void * @author : cwl * @date : 2019/6/4 16:50 */ void appendTo(StringBuffer buffer, int value); } //输出一个常量的字符 private static class CharacterLiteral implements Rule { private final char mValue; CharacterLiteral(char value) { mValue = value; } public int estimateLength() { return 1; } public void appendTo(StringBuffer buffer, Calendar calendar) { buffer.append(mValue); } } @Override public Object parseObject(String source, ParsePosition pos) { pos.setIndex(0); pos.setErrorIndex(0); return null; } //用于输出一个常量字符 private static class StringLiteral implements Rule { private final String mValue; StringLiteral(String value) { mValue = value; } public int estimateLength() { return mValue.length(); } public void appendTo(StringBuffer buffer, Calendar calendar) { buffer.append(mValue); } } //输出一组值当中的一个 private static class TextField implements Rule { private final int mField; private final String[] mValues; TextField(int field, String[] values) { mField = field; mValues = values; } public int estimateLength() { int max = 0; for (int i=mValues.length; --i >= 0; ) { int len = mValues[i].length(); if (len > max) { max = len; } } return max; } public void appendTo(StringBuffer buffer, Calendar calendar) { buffer.append(mValues[calendar.get(mField)]); } } //输出年份 private static class UnpaddedNumberField implements NumberRule { static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(Calendar.YEAR); private final int mField; UnpaddedNumberField(int field) { mField = field; } public int estimateLength() { return 4; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(mField)); } public final void appendTo(StringBuffer buffer, int value) { if (value < 10) { buffer.append((char)(value + '0')); } else if (value < 100) { buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } else { buffer.append(Integer.toString(value)); } } } //输出月份 private static class UnpaddedMonthField implements NumberRule { static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); UnpaddedMonthField() { super(); } public int estimateLength() { return 2; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(Calendar.MONTH) + 1); } public final void appendTo(StringBuffer buffer, int value) { if (value < 10) { buffer.append((char)(value + '0')); } else { buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } } } //用于填充两位数的内部类 private static class PaddedNumberField implements NumberRule { private final int mField; private final int mSize; PaddedNumberField(int field, int size) { if (size < 3) { // Should use UnpaddedNumberField or TwoDigitNumberField. throw new IllegalArgumentException(); } mField = field; mSize = size; } public int estimateLength() { return 4; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(mField)); } public final void appendTo(StringBuffer buffer, int value) { if (value < 100) { for (int i = mSize; --i >= 2; ) { buffer.append('0'); } buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } else { int digits; if (value < 1000) { digits = 3; } else { if(value <= -1){ throw new IllegalArgumentException("Negative values should not be possible" + value); } digits = Integer.toString(value).length(); } for (int i = mSize; --i >= digits; ) { buffer.append('0'); } buffer.append(Integer.toString(value)); } } } //用来输出两位数的内部类 private static class TwoDigitNumberField implements NumberRule { private final int mField; TwoDigitNumberField(int field) { mField = field; } public int estimateLength() { return 2; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(mField)); } public final void appendTo(StringBuffer buffer, int value) { if (value < 100) { buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } else { buffer.append(Integer.toString(value)); } } } //用来输出两位数字的年份的内部类 private static class TwoDigitYearField implements NumberRule { static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); TwoDigitYearField() { super(); } public int estimateLength() { return 2; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(Calendar.YEAR) % 100); } public final void appendTo(StringBuffer buffer, int value) { buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } } //用来输出两位数字的月份的内部类 private static class TwoDigitMonthField implements NumberRule { static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); TwoDigitMonthField() { super(); } public int estimateLength() { return 2; } public void appendTo(StringBuffer buffer, Calendar calendar) { appendTo(buffer, calendar.get(Calendar.MONTH) + 1); } public final void appendTo(StringBuffer buffer, int value) { buffer.append((char)(value / 10 + '0')); buffer.append((char)(value % 10 + '0')); } } //用来输出12小时字段的内部类 private static class TwelveHourField implements NumberRule { private final NumberRule mRule; TwelveHourField(NumberRule rule) { mRule = rule; } public int estimateLength() { return mRule.estimateLength(); } public void appendTo(StringBuffer buffer, Calendar calendar) { int value = calendar.get(Calendar.HOUR); if (value == 0) { value = calendar.getLeastMaximum(Calendar.HOUR) + 1; } mRule.appendTo(buffer, value); } public void appendTo(StringBuffer buffer, int value) { mRule.appendTo(buffer, value); } } //用来输出24小时字段的内部类 private static class TwentyFourHourField implements NumberRule { private final NumberRule mRule; TwentyFourHourField(NumberRule rule) { mRule = rule; } public int estimateLength() { return mRule.estimateLength(); } public void appendTo(StringBuffer buffer, Calendar calendar) { int value = calendar.get(Calendar.HOUR_OF_DAY); if (value == 0) { value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; } mRule.appendTo(buffer, value); } public void appendTo(StringBuffer buffer, int value) { mRule.appendTo(buffer, value); } } //用来输出时区名称的内部类 private static class TimeZoneNameRule implements Rule { private final TimeZone mTimeZone; private final boolean mTimeZoneForced; private final Locale mLocale; private final int mStyle; private final String mStandard; private final String mDaylight; TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) { mTimeZone = timeZone; mTimeZoneForced = timeZoneForced; mLocale = locale; mStyle = style; if (timeZoneForced) { mStandard = getTimeZoneDisplay(timeZone, false, style, locale); mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); } else { mStandard = null; mDaylight = null; } } public int estimateLength() { if (mTimeZoneForced) { return Math.max(mStandard.length(), mDaylight.length()); } else if (mStyle == TimeZone.SHORT) { return 4; } else { return 40; } } public void appendTo(StringBuffer buffer, Calendar calendar) { if (mTimeZoneForced) { if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { buffer.append(mDaylight); } else { buffer.append(mStandard); } } else { TimeZone timeZone = calendar.getTimeZone(); if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale)); } else { buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale)); } } } } //将时区作为数字输出的内部类 private static class TimeZoneNumberRule implements Rule { static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); final boolean mColon; TimeZoneNumberRule(boolean colon) { mColon = colon; } public int estimateLength() { return 5; } public void appendTo(StringBuffer buffer, Calendar calendar) { int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); if (offset < 0) { buffer.append('-'); offset = -offset; } else { buffer.append('+'); } int hours = offset / (60 * 60 * 1000); buffer.append((char)(hours / 10 + '0')); buffer.append((char)(hours % 10 + '0')); if (mColon) { buffer.append(':'); } int minutes = offset / (60 * 1000) - 60 * hours; buffer.append((char)(minutes / 10 + '0')); buffer.append((char)(minutes % 10 + '0')); } } //时区名称作为Key值的内部类 private static class TimeZoneDisplayKey { private final TimeZone mTimeZone; private final int mStyle; private final Locale mLocale; TimeZoneDisplayKey(TimeZone timeZone, boolean daylight, int style, Locale locale) { mTimeZone = timeZone; if (daylight) { style |= 0x80000000; } mStyle = style; mLocale = locale; } public int hashCode() { return mStyle * 31 + mLocale.hashCode(); } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof TimeZoneDisplayKey) { TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj; return mTimeZone.equals(other.mTimeZone) && mStyle == other.mStyle && mLocale.equals(other.mLocale); } return false; } } // 用于创建复合对象的Helper类 private static class Pair { private final Object mObj1; private final Object mObj2; public Pair(Object obj1, Object obj2) { mObj1 = obj1; mObj2 = obj2; } public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Pair)) { return false; } Pair key = (Pair)obj; return (mObj1 == null ? key.mObj1 == null : mObj1.equals(key.mObj1)) && (mObj2 == null ? key.mObj2 == null : mObj2.equals(key.mObj2)); } public int hashCode() { return (mObj1 == null ? 0 : mObj1.hashCode()) + (mObj2 == null ? 0 : mObj2.hashCode()); } public String toString() { return "[" + mObj1 + ':' + mObj2 + ']'; } } } }