-- by Wenyuan.huang
笔者在之前的某个项目中遇到个需求:用户可定义时间范围(分别指定开始时间与结束时间,这两个时间点填写格式为xx时xx分,例如开始时间为18:15,结束时间为23:15);当时间来到开始时间点(比如18:15)则模式激活,当时间来到结束时间点(如23:15)则模式关闭。该需求在实现过程中踩了一些坑,现已解决完成,故特将其做记录,供有遇到相同情况的开发者参考,也给未来的自己做个备忘。
起初实现的想法,是以接到Android平台每一分钟会发出的TIME_TICK广播后,拿当前时间的小时与分钟来与设置好的开始时间与结束时间对比。具体代码如下:
/**
* Broadcast Action: The current time haschanged. Sent every
* minute. */
public static final String ACTION_TIME_TICK = "android.intent.action.TIME_TICK"
void judgeCurrentTime(){ if(curHour == mStartHour && curMin == mStartMin){ //时间来到区间的起始点,则激活。 } else if(curHour == mEndHour && curMin == mEndMin){ //时间来到区间的结束点,则关闭。
} }
乍看之下这过程是没错的,可是这过程只能用来判断时间刚好跨入或驶出所设的开始与结束时间区间的那一刻。当用户重新设置了开始或结束时间,则无法马上判断当前时间点是否位于所设的时间区间内的。
所以更换了判断方法,直接判断当前时间是否位于某段时间区间内,步骤如下:
1.将“开始时间startTime”、“结束时间endTime”、“当前时间currentTime”都转为Unix时间戳。
2.判断当前时间的时间戳是否大于或等于开始时间的时间戳且小于结束时间的时间戳,
公式如下:
startTime≤currentTime<endTime
3.具体的代码如下:
/** * 将某一时刻转成Unix时间戳。 * * @param hour 小时 * @param minute 分钟 * @return */ public static long transfer2Timestamp(int hour, int minute) { Calendar currentDate = Calendar.getInstance(); Calendar compareDate = Calendar.getInstance(); compareDate.set(Calendar.YEAR, currentDate.get(Calendar.YEAR)); compareDate.set(Calendar.MONTH, currentDate.get(Calendar.MONTH)); compareDate.set(Calendar.DAY_OF_MONTH, currentDate.get(Calendar.DAY_OF_MONTH)); compareDate.set(Calendar.HOUR_OF_DAY, hour); compareDate.set(Calendar.MINUTE, minute); compareDate.set(Calendar.SECOND, 0); compareDate.set(Calendar.MILLISECOND, 0); return compareDate.getTimeInMillis(); }
/** * 判断当前时间是否位于某段时间区间内。 * @param startHour 开始时间的小时 * @param startMin 开始时间的分钟 * @param endHour 结束时间的小时 * @param endMin 结束时间的分钟 * @return */
public static boolean isInsideTime(int startHour, int startMin, int endHour, int endMin) { boolean isInside = false; long startTimeMiles = Tools.transfer2Timestamp(startHour, startMin); long endTimeMiles = Tools. transfer2Timestamp (endHour, endMin); Calendar currentDate = Calendar.getInstance(); if (currentDate.getTimeInMillis() >= startTimeMiles && currentDate.getTimeInMillis() < endTimeMiles) { isInside = true; }
return isInside;
}
经测试此方法能马上判断当前时间是否位于某段时间内,但只能局限在同一天内,因为用来对比的时间戳是以同一天为基准的,也就是说只有将时间区间设为 “09:00 ~ 11:00” 或者 “11:30 ~ 23:59” 这种情况时,此方法才能有效。若所设的时间属于跨天的情况呢?
当用户将时间区间设为“22:00 ~ 07:00”,此情况属于跨天的设置,表示激活时间为晚上的10点整到次日的7点整。这时候我们可以从结束时间上分析,此时结束时间属于次日的,这时我们可以借用一整天的时间戳为86400000毫秒这常量来协助加以判断。先上代码再分析:
public static boolean isInsideTime(int startHour, int startMin, int endHour, int endMin) { boolean isInside = false; long startTimeMiles = Tools.transfer2Timestamp(startHour, startMin); long endTimeMiles; //当所设的结束时间小于开始时间,则结束时间的时间戳要加上一整天的时间戳,代表为次日的。 if (endHour < startHour || ((endHour == startHour) && (endMin < startMin))) { endTimeMiles = Tools.transfer2Timestamp(endHour, endMin) + 86400000; } else { endTimeMiles = Tools.transfer2Timestamp(endHour, endMin); } Calendar currentDate = Calendar.getInstance(); if (currentDate.getTimeInMillis() >= startTimeMiles && currentDate.getTimeInMillis() < endTimeMiles) { isInside = true; } //特殊情况:开始时间大于结束时间,且当前时间过了夜间12点,需增加此情况。 else if (currentDate.getTimeInMillis() <= startTimeMiles && currentDate.getTimeInMillis() + 86400000 >= startTimeMiles && currentDate.getTimeInMillis() + 86400000 < endTimeMiles) { isInside = true; } //位于区间外则关闭 else { isInside = false; } return isInside; }
当用户所设置的结束时间小于开始时间,则说明此属于跨天的情况,故结束时间的时间戳需要加上86400000毫秒。有一点需要注意的是:当时间过了夜间12点时,此时判断得以当前时间的戳间戳加上86400000毫秒再结合开始时间的时间戳与结束时间的时间戳(注:结束时间已加上86400000毫秒)来比较。
综上,此方法用来判断当前时间是否位于某段时间内,不管这段时间是属于同一天的还是跨天的都能处理到,只需将开始时间与结束时间的小时分钟作为参数传入此方法即可。