上一篇讲到 在后端date 和 timestamp处理的区别
本篇来了解一下对时间处理的实际使用实例 (以下代码只是做演示使用,各位看官仅做参考作用 )
实例一:
日历接口的前台适配 , 数据库已经查出10月 3,5,7,15有接待数据,没有接待数据默认不展示,但是给前端的数据必须是一个完整的日历格式,而且时间区间范围是 这个月的前15天前到下个月的15号,因此需要在Java中处理时,以日期为HashKey值,Value值,数据库有数据为1,没有数据默认为0,而且需要补齐其他数据库没有的时间
实例一代码实现:
实现的基础方法如下
/**
*前台适配.填充没有的数据,处理成日历的样式
* @param stringTimeSet 数据库查出的具体接待日期数据
* @param fifteenDaysAgo 这个月 前一月往前的时间
* @param fifteenDaysLater这个月 后一月往后的时间
* @return
*/
public List<LinkedHashMap<Integer ,String>> fillDateStates(LinkedHashSet<String> stringTimeSet , String fifteenDaysAgo, String fifteenDaysLater){
if(stringTimeSet.size()<0){return null;}
final String showCalenderStates="1";
final String dontShowCalenderStates="0";
LinkedHashMap<Integer ,String> fillDaysStatesMap=new LinkedHashMap<>();
int addDays=0;
Boolean flag=true;
while (true){
//时间按天数自增
String nextStringDay=addDay(fifteenDaysAgo , addDays);
if( flag && stringTimeSet.contains(nextStringDay)){
int nextIntegerDay=Integer.parseInt( nextStringDay.replaceAll("-" , ""));
//数据库中查出有数据,存储展示标志位 showCalenderStates
fillDaysStatesMap.put(nextIntegerDay ,showCalenderStates);
stringTimeSet.remove(nextStringDay);
if( stringTimeSet.size()==0){
flag=false; //集合为空结束循环
}
}else{
int nextIntegerDay=Integer.parseInt( nextStringDay.replaceAll("-" ,""));
//数据库中没有查出有数据,存储展示标志位 dontShowCalenderStates
fillDaysStatesMap.put( nextIntegerDay ,dontShowCalenderStates);
}
if( fifteenDaysLater.equals(nextStringDay)){
break;//自增天数和日历展示最后时间相等
}
addDays++;
}
List<LinkedHashMap<Integer ,String>> fillDateStatesList=new ArrayList<>();
fillDateStatesList.add(fillDaysStatesMap);
return fillDateStatesList;
}
/**
* 计算某月之前一个月的提前天数的日期 或者某月后一月的延后日期
* @param stringTime 某月的具体时间
* @param addDays 提前或者延后的时间 提前为 - (负数) ,延后为 + (正数)
* @return
*/
public String getDelayDates(String stringTime ,int addDays){
if(! org.apache.commons.lang.StringUtils.isNotBlank(stringTime) ){
return null ;
}
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyMM");
Calendar calendar=Calendar.getInstance();
try {
calendar.setTime(dateFormat.parse(stringTime));
} catch (ParseException e) {
e.printStackTrace();
}
if(addDays <=0){//小于0,将时间转换为改月第一天
calendar.add(Calendar.MONTH,0);
calendar.set(Calendar.DAY_OF_MONTH,1);
}else {//大于0 将时间转换为该月最后一天
calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
}
dateFormat=new SimpleDateFormat("yyyy-MM-dd");
String firstDayOfMonth=dateFormat.format(calendar.getTime());
System.out.println("firstDayOfMonth "+firstDayOfMonth);
return addDay(firstDayOfMonth,addDays);
}
/**
* 在某一天的基础上增加具体天数
* @param stringTime
* @param addDays
* @return
*/
public String addDay(String stringTime ,int addDays){
if( addDays==0){
return stringTime;
}
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar=Calendar.getInstance();
try {
calendar.setTime(dateFormat.parse(stringTime));
} catch (ParseException e) {
e.printStackTrace();
}
calendar.add(Calendar.DATE ,addDays);//增加一天
//calendar.add(Calendar.MONTH ,addDays);//增加一月
return dateFormat.format(calendar.getTime());
}
/**
* 计算两个时间的间隔日期具体天数
* @param stringTime
* @param endTime
* @return
*/
public int intervalDays(String stringTime ,String endTime){
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar=Calendar.getInstance();
try {
calendar.setTime(dateFormat.parse(stringTime));
} catch (ParseException e) {
e.printStackTrace();
}
int addDays=1;
while ( true ){
String newStringDay=addDay(stringTime,addDays);
if(newStringDay.equals(endTime)){
break;
}
addDays++;
}
return addDays;
}
前台传递一个查询10月份的预定需求请求,传进来的时间为 201810 ,对时间处理,取10月之前一个月的15天和10月之后一个月之后的15天 , 具体的调用方法
System.out.println("--- +15---- "+ new Test().getDelayDates("201806",15));
System.out.println("--- -15---- "+ new Test().getDelayDates("201806",-15));
LinkedHashSet<String> stringTimeSet=new LinkedHashSet<>();
stringTimeSet.add("2018-06-16");
stringTimeSet.add("2018-06-25");
stringTimeSet.add("2018-06-27");
stringTimeSet.add("2018-06-28");
stringTimeSet.add("2018-06-29");
stringTimeSet.add("2018-07-03");
stringTimeSet.add("2018-07-05");
stringTimeSet.add("2018-07-06");
stringTimeSet.add("2018-07-07");
stringTimeSet.add("2018-08-15");
System.out.println("日历样子 "+ new Test().fillDateStates(stringTimeSet,"2018-06-16","2018-08-15").toString());
实例二:
计算某个月的非周末日期,以及可以根据自定义时间进行过滤
实例二实现:
该实例在Java后台实现问题也不大,但是本人在百度之后发现,使用Sql可以一条语句解决,所以就直接调用数据库 from dual表生成
--查询某月非工作日所有日期
SELECT to_char( dt , 'yyyymmdd') from (select to_date(to_char(TO_DATE('20180801' ,'yyyymmdd') + LEVEL - 1 , 'yyyymmdd'),'yyyyMMdd') dt
FROM DUAL CONNECT BY LEVEL <= to_number(to_char(LAST_DAY(TO_DATE('20180801' ,'yyyymmdd')),'dd') ))
WHERE 1=1
AND to_char(dt,'d') NOT IN (1,7)
AND to_char(dt,'yyyymmdd') NOT IN ('20180801','20180803')
----level 是一个伪例
SELECT LEVEL FROM dual CONNECT BY LEVEL <=10
--获取某月最后一天
select LAST_DAY(TO_DATE('20180801' ,'yyyymmdd')) from dual
其中level 是一个伪例 , 做循环使用 , LAST_DAY() 为获取某月最后一天 ,其中两个AND条件,可以在XML中检测参数是否为空来实现选择执行
实例三:
类似于超市统计每半个小时为单位的当前人流量, 例如 , A进入超市的时间是 8:00 离开的时间是 10:00 , 那么该超市购物时间是8:00-10:00 ,也就是说数据库记录的时间, B 在超市购物的时间是 8:30-9:00 , 此时统计数据为 8:00-8:30 1人 , 8:30-9:00 2人 , 9:00-9:30 1人 .....
实例三实现:
这里也是使用level 做一个循环 , 不断拿开始时间和结束时间的区间进行比对,之后进行统计,先看Sql实现
---半小时区间 前后时间区间统计可以的
SELECT to_char(d.dt,'yyyy-MM-dd HH24:mi:ss' ),
( SELECT count(1) AS num
FROM A_HY_LOCATE3 i
WHERE 1=1 AND i.created_time<= (d.dt+(1/24)/2-(1/24)/3600)
AND i.update_TIME >=(d.dt+(1/24)/2-(1/24)/3600)
)
FROM
(
(SELECT to_date('20180801','yyyyMMdd')+(LEVEL-1)*((1/24)/2) dt
from dual connect by level <= 48) d
)
1. 其中开始时间 i.created_time 和结束时间 i.update_TIME 均减一分钟,使下一个半点时间落在下一统计区间,如00:00-00:30 的人数落在00:00这一统计里面,00:30-1:00落在00:30里,采取前闭后开,既 >=00:30 and <01:00
2. 关于时间的加减运算
select to_char(to_date('20180810','yyyyMMdd')-((1/24)/2/1800),'yyyy-MM-dd HH24:mi:ss'),to_char(to_date('20180810','yyyyMMdd'),'yyyy-MM-dd HH24:mi:ss')from dual
该语句查询的结果
可以看出第一个结果在原来的基础上减少了1秒钟,所以时间的加减法就是按照一天24小时计算 , 简单解析一下((1/24)/2/1800)
1/24 把一天分成24小时 这里代表一个小时
(1/24)/2 在分成24小时的基础上以半小时为单位把一天分成48份 , 这里代表半个小时
(1/24)/2/1800 把一天分成具体的秒数,这里代表1秒
所以这里的to_date('20180810','yyyyMMdd')-((1/24)/2/1800) 就是在原来基础上减1秒
3. 关于level以半小时为区间循环
SELECT to_char(to_date('20180801','yyyyMMdd')+(LEVEL-1)*((1/24)/2),'yyyyMMdd HH24:mi:ss') dt
from dual connect by level <= 48
4. 建表语句 以及插入Sql
create table A_HY_LOCATE3
(
MOBILE_NO VARCHAR2(32),
LOCATE_TYPE NUMBER(4),
AREA_NO VARCHAR2(32),
created_time date,
update_TIME DATE,
area_name VARCHAR2(512)
)
INSERT INTO A_HY_LOCATE3 VALUES ('1',1,'1',to_date('2018-08-01 00:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 00:30:00' ,'yyyy-MM-dd HH24:mi:ss'),'1');
INSERT INTO A_HY_LOCATE3 VALUES ('2',2,'2',to_date('2018-08-01 00:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 01:00:00' ,'yyyy-MM-dd HH24:mi:ss'),'2');
INSERT INTO A_HY_LOCATE3 VALUES ('1',1,'1',to_date('2018-08-01 23:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 23:30:00' ,'yyyy-MM-dd HH24:mi:ss'),'1');
INSERT INTO A_HY_LOCATE3 VALUES ('2',2,'2',to_date('2018-08-01 23:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-02 00:00:00' ,'yyyy-MM-dd HH24:mi:ss'),'2');
INSERT INTO A_HY_LOCATE3 VALUES ('1',1,'1',to_date('2018-08-01 00:30:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 01:30:00' ,'yyyy-MM-dd HH24:mi:ss'),'1');
INSERT INTO A_HY_LOCATE3 VALUES ('2',2,'2',to_date('2018-08-01 00:30:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 01:00:00' ,'yyyy-MM-dd HH24:mi:ss'),'2');
INSERT INTO A_HY_LOCATE3 VALUES ('3',3,'3',to_date('2018-08-01 01:30:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 02:00:00' ,'yyyy-MM-dd HH24:mi:ss'),'3');
insert into A_HY_LOCATE3 values ('4',4,'4',to_date('2018-08-01 01:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 02:30:00' ,'yyyy-MM-dd HH24:mi:ss'),'4');
INSERT INTO A_HY_LOCATE3 VALUES ('5',5,'5',to_date('2018-08-01 16:00:00' ,'yyyy-MM-dd HH24:mi:ss'),to_date('2018-08-01 17:00:00' ,'yyyy-MM-dd HH24:mi:ss'),'5');
实例四:
在这里插入一个在Java中对时间循环的坑(如何在java中区分今天00:00和第二天00:00)
因为在数据库中,23:30加半小时是加一天的零点,既假如输入时 2080810 23:30 ,加半小时是20180811 00:00 ,而不是我们一般理解的24:00 , 那么如果在Java中使用while语句循环
while(time == "24:00"){}这样 的语句是永远不会结束循环的,因为时间里只有00:00 ,没有24:00,
如果改成while(time == "00:00"){}那么我输入的时间是00:00呢? 本来是要到下一天的24:00才结束循环,结果刚进就结束了.
其实在此有一个规避今天00:00 和第二天00:00的方法,
用三目运算,如果是今天的输入的时间是00:00 ,把时间替换成 -00:00 ,没错,就是在今天输入的时间中加负号,试试会有奇迹哦,一般人可不告诉他