论坛首页 Java企业应用论坛

时间工具类,主要用于sql的时间段查询

浏览 13915 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-12-28   最后修改:2010-12-28
   该类主要服务于sql中基于时间的统计查询,在写sql的过程中建议不要使用to_char或者to_date等oracle函数这样不利用索引(除非你对to_char进行了类似索引的操作),比如:在表的logintime字段上建立了索引,但是在sql中使用to_char(logintime,'yyyy-MM-dd')作为检索条件的时候,数据库在logintime上建立的索引就没用了。在数据量很大的时候会影响检索的速度。
   该类提供如下方法:
   1、获取系统按天截取时间 getSystemTranceDay();
   2、根据指定时间提供天、周、旬、月、季度、年的开始时间,结束时间(时间格式采java.util.Date),以Date数组的形式返回开始和结束时间。
   3、给定字符串类型的startTime和endTime,工具类负责类型的转换(String转换成Date)
   注意:
   1、在sql中使用开始时间和最后时间的时候,为了保证统计数据的正确性,
     sql按给出的例子组织:t.logintime >= startTime and t.loginTime <= entTime
   2、时间的字符串格式采用 yyyy-MM-dd
   3、使用该类的时候,注意返回结果的正确性,虽然单元测试通过,还是担心有数据不正确的问题。
   4、工具类以附件形式提供。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.DataFormatException;

import org.apache.commons.lang.time.DateUtils;
import com.pengsy.commons.stringutil.StringUtil;

/**
 * 该类主要服务于sql中基于时间的统计查询,在写sql的过程中建议不要使用to_char或者to_date等oracle函数
 * 这样不利用索引(除非你对to_char进行了类似索引的操作
 * ),比如:在表的logintime字段上建立了索引,但是在sql中使用to_char(logintime,'yyyy-MM-dd')
 * 作为检索条件的时候,数据库在logintime上建立的索引就没用了。在数据量很大的时候会影响检索的速度。
 *  提供如下方法: 
 *  1、获取当前时间(按天截取时间)
 *  2、根据指定时间提供天、周、旬、月、季度、年的开始时间,结束时间(时间格式采java.util.Date)
 *  3、给定字符串类型的startTime和endTime,工具类负责类型的转换(String转换成Date) 
 *  注意:
 *  1、在sql中使用开始时间和最后时间的时候,为了保证统计数据的正确性,
 *    sql按给出的例子组织:t.logintime >= startTime and t.loginTime <= entTime 
 *  2、时间的字符串格式采用 yyyy-MM-dd
 * 
 */

public final class DateUtil {

	private static SimpleDateFormat sDateFormat = new SimpleDateFormat(
			"yyyy-MM-dd");

	public static final int FIRSTTEN = 1 ;
	public static final int MIDTEN = 2;
	public static final int LASTTEN = 3;
	
	public static final int FIRSTQUARTER = 1;
	public static final int SECONDQUARTER = 2;
	public static final int THIRDQUARTER = 3;
	public static final int FORTHQUARTER = 4;
	
	private static Pattern pattern = Pattern
			.compile("^[1-9]\\d{3}-[01]?\\d-[0|1|2|3]?\\d$"); // 2010-12-22

	/**
	 * 获取当前系统时间按天截取的时间
	 * @return
	 */
	public static Date getSystemTranceDay(){
		return DateUtils.truncate(new Date(), Calendar.DATE);
	}
	
	/**
	 * 功能:根据指定时间获取当前天的开始和结束时间,以date数组返回
	 * 逻辑:
	 * 1、appointDate is null ,set default value sysdate
	 * 2、get date[]
	 * @param appointDate
	 * @return
	 */
	public static Date[] getDateArrByDay(Date appointDate){
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		//未完
		if(appointDate == null){
			appointDate = new Date();
		}
		stime = DateUtils.truncate(appointDate,Calendar.DATE);
		etime = DateUtils.addSeconds(DateUtils.truncate(DateUtils.addDays(appointDate, 1), Calendar.DATE),-1);
		
		date[0] = stime;
		date[1] = etime;
		return date;
	}
	
	/**
	 * 功能:根据指定时间获取当前星期的开始和结束时间,以date数组返回
	 * @param appointDate
	 * @return
	 */
	public static Date[] getDateArrByWeek(Date appointDate){
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		if(appointDate == null){
			appointDate = new Date();
		}
		
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(appointDate);
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		System.out.println(dayOfWeek);
		
		calendar.add(Calendar.DAY_OF_MONTH, -dayOfWeek+2);
		
		stime = DateUtils.truncate(calendar.getTime(), Calendar.DATE);
		calendar.add(Calendar.DAY_OF_MONTH, 7);
		etime = DateUtils.addSeconds(DateUtils.truncate(calendar.getTime(), Calendar.DATE), -1);
		
		date[0] = stime;
		date[1] = etime;
		
		return date;
	}
	
	/**
	 * 功能:根据指定的时间和上中下旬的其中一个,获取开始时间和结束时间
	 * @param appointDate
	 * @param appointIndex
	 * @return
	 */
	public static Date[] getDateArrByTenDays(Date appointDate,int appointIndex ){
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		if(appointDate == null){
			appointDate = new Date();
		}
		//init date
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(appointDate);
		int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
		int maxDayOfMonth = calendar.getMaximum(Calendar.DAY_OF_MONTH);
		
		Date tempDate = DateUtils.truncate(DateUtils.addDays(appointDate, -dayOfMonth + 1), Calendar.DATE);
		
		if(appointIndex == FIRSTTEN){
			stime = tempDate;
			etime = DateUtils.addSeconds(DateUtils.addDays(stime, 10), -1);
		}
		
		if(appointIndex == MIDTEN){
			stime = DateUtils.addDays(tempDate, 10);
			etime = DateUtils.addSeconds(DateUtils.addDays(stime, 10), -1);
		}
		
		if(appointIndex == LASTTEN){
			stime = DateUtils.addDays(tempDate, 20);
			etime = DateUtils.addSeconds(DateUtils.addDays(tempDate, maxDayOfMonth), -1);
		}
		
		date[0] = stime;
		date[1] = etime; 
		return date;
	}
	
	/**
	 * 功能:根据指定时间获取相应月份的开始时间和结束时间
	 * @param appointDate
	 * @return
	 */
	public static Date[] getDateArrByMonth(Date appointDate){
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		if(appointDate == null){
			appointDate = new Date();
		}
		
		//init date
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(appointDate);
		int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
		int maxDayOfMonth = calendar.getMaximum(Calendar.DAY_OF_MONTH);
		
		appointDate = DateUtils.truncate(appointDate, Calendar.DATE);
		
		stime = DateUtils.truncate(DateUtils.addDays(appointDate, -dayOfMonth+1), Calendar.DATE);
		etime = DateUtils.addSeconds(DateUtils.addDays(stime, maxDayOfMonth), -1);
		
		date[0] = stime;
		date[1] = etime;
		
		return date;
	}
	
	/**
	 * 功能:根据指定时间所在的当前年,获取指定季度的开始时间和结束时间
	 * @param appointDate 指定当前年
	 * @param appointIndex
	 * @return
	 * @throws IllegalArgumentException
	 */
	public static Date[] getDateArrByQuarter(Date appointDate,int appointIndex) throws IllegalArgumentException{
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		if(appointDate == null){
			appointDate = new Date();
		}
		int month = appointDate.getMonth();
		Date tempDate = DateUtils.truncate(appointDate, Calendar.YEAR);
		if(appointIndex == FIRSTQUARTER){
			stime = tempDate;
		}else if(appointIndex == SECONDQUARTER){
			stime = DateUtils.addMonths(tempDate, 3);
		}else if(appointIndex == THIRDQUARTER ){
			stime = DateUtils.addMonths(tempDate, 6);
		}else if(appointIndex == FORTHQUARTER){
			stime = DateUtils.addMonths(tempDate, 9);
		}
		etime = DateUtils.addSeconds(DateUtils.addMonths(stime, 3), -1);
		
		date[0] = stime;
		date[1] = etime;
		
		return date;
	}
	
	/**
	 * 功能:根据指定时间,获取年的开始时间和结束时间
	 * @param appointDate
	 * @return
	 */
	public static Date[] getDateArrByYear(Date appointDate){
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];
		if(appointDate == null){
			appointDate = new Date();
		}
		stime = DateUtils.truncate(appointDate, Calendar.YEAR);
		etime = DateUtils.addSeconds(DateUtils.addYears(stime, 1), -1);
		
		date[0] = stime;
		date[1] = etime;
		
		return date;
	}
	
	/**
	 * 逻辑: 1、检查startTime,endTime的有效性(是否为空,数据格式), 异常处理: 1、两个参数都为空,抛出空指针异常
	 * 2、数据格式不对,直接抛出 3、一个参数为空,另一个参数格式正确的情况下,为空的参数采用系统时间,为了保证startTime <=
	 * endTime,工具类会做适当的调整 2、转换 3、返回值是个Date[2]数组,date[0] 保存startTime值,date[1]
	 * 保存startTime值,其中startTime <= endTime
	 * 
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static Date[] convertDateClass(String startTime, String endTime)
			throws NullPointerException, DataFormatException, ParseException {
		Date stime = null;
		Date etime = null;
		Date[] date = new Date[2];

		if (StringUtil.isEmpty(startTime) && StringUtil.isEmpty(endTime)) {
			throw new NullPointerException("两个参数不能同时为空");
		}

		if (StringUtil.isEmpty(startTime) && !StringUtil.isEmpty(endTime)) {
			// 先判断endTime格式是否正确
			Matcher matcher = pattern.matcher(endTime);
			if (matcher.matches()) {
				stime = DateUtils.truncate(new Date(), Calendar.DATE); // 当天的开始时间,比如:当前时间为2010-12-27 11:31:30 这里stime的时间是2010-12-27 0:0:0
				etime = DateUtils.truncate(sDateFormat.parse(endTime),Calendar.DATE);
			} else {
				throw new DataFormatException(
						"参数endTime的格式不正确!正确的格式 yyyy-MM-dd 比如:2010-12-12!");
			}
		}
		if (!StringUtil.isEmpty(startTime) && StringUtil.isEmpty(endTime)) {
			Matcher matcher = pattern.matcher(startTime);
			if (matcher.matches()) {
				// 提供转换
				etime = DateUtils.truncate(new Date(), Calendar.DATE); // 当天的开始时间,比如:当前时间为2010-12-27 11:31:30 这里stime的时间是2010-12-27 0:0:0
				stime = DateUtils.truncate(sDateFormat.parse(startTime),Calendar.DATE);
			} else {
				throw new DataFormatException(
						"参数startTime的格式不正确!正确的格式 yyyy-MM-dd 比如:2010-12-12!");
			}
		}

		if (!StringUtil.isEmpty(startTime) && !StringUtil.isEmpty(endTime)) {
			Matcher sMatcher = pattern.matcher(startTime);
			Matcher eMatcher = pattern.matcher(endTime);
			if (sMatcher.matches() && eMatcher.matches()) {

				stime = DateUtils.truncate(sDateFormat.parse(startTime),
						Calendar.DATE);
				etime = DateUtils.truncate(sDateFormat.parse(endTime),
						Calendar.DATE);

			} else {
				throw new DataFormatException(
						"请检查参数startTime、endTime的格式是否正确!正确的格式 yyyy-MM-dd 比如:2010-12-12!");
			}

		}

		if (!stime.before(etime)) {
			Date temp = stime;
			stime = etime;
			etime = temp;
			temp = null;
		}
		
		date[0] = stime;
		date[1] = etime;
		return date;
	}
}
   发表时间:2010-12-28  
30%~50%的地方可以代码复用
0 请登录后投票
   发表时间:2010-12-28  
SimpleDateFormat这个类不是线程安全的,所以在多线程的时候上面的代码可能会出错!
建议用这个包:joda-time
0 请登录后投票
   发表时间:2010-12-29  
changyuxin 写道
SimpleDateFormat这个类不是线程安全的,所以在多线程的时候上面的代码可能会出错!
建议用这个包:joda-time

用 ThreadLocal
这样写:
	private static ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
		@Override
		protected DateFormat initialValue() {
			return new SimpleDateFormat("yyyy-MM-dd");
		}
	};
	/**
	 * 格式化日期为  yyyy-MM-dd 格式
	 * @param date
	 * @return
	 */
	public static String formatDate(Date date) {
		return dateFormat.get().format(date);
	}

请大牛评论,这样做在WEB程序中的优劣
0 请登录后投票
   发表时间:2010-12-29   最后修改:2010-12-29
没全部看完。代码质量不高。

执行效率和安全性上都有问题。也多分配了一些多余对象容易引起性能问题。
而且使用了一些第三方类,导致使用你的代码还要引入额外的jar包。
0 请登录后投票
   发表时间:2010-12-29  
changyuxin 写道
SimpleDateFormat这个类不是线程安全的,所以在多线程的时候上面的代码可能会出错!
建议用这个包:joda-time


对,webwork jar包里面的那个过滤器里用到了  SimpleDateFormat ,就出现了这个BUG。
struts2 好像修正了这个问题。
0 请登录后投票
   发表时间:2010-12-29  
pengsuyun 写道
   该类主要服务于sql中基于时间的统计查询,在写sql的过程中建议不要使用to_char或者to_date等oracle函数这样不利用索引(除非你对to_char进行了类似索引的操作),比如:在表的logintime字段上建立了索引,但是在sql中使用to_char(logintime,'yyyy-MM-dd')作为检索条件的时候,数据库在logintime上建立的索引就没用了。在数据量很大的时候会影响检索的速度。
   该类提供如下方法:
   1、获取系统按天截取时间 getSystemTranceDay();
   2、根据指定时间提供天、周、旬、月、季度、年的开始时间,结束时间(时间格式采java.util.Date),以Date数组的形式返回开始和结束时间。
   3、给定字符串类型的startTime和endTime,工具类负责类型的转换(String转换成Date)
   注意:
   1、在sql中使用开始时间和最后时间的时候,为了保证统计数据的正确性,
     sql按给出的例子组织:t.logintime >= startTime and t.loginTime <= entTime
   2、时间的字符串格式采用 yyyy-MM-dd
   3、使用该类的时候,注意返回结果的正确性,虽然单元测试通过,还是担心有数据不正确的问题。
   4、工具类以附件形式提供。

为什么不可以to_date?
logintime > to_date(条件,'yyyy-MM-dd')
0 请登录后投票
   发表时间:2010-12-29  
运行结果:
dayOfWeek=2
appointDate=2011-01-03 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=3
appointDate=2011-01-04 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=4
appointDate=2011-01-05 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=5
appointDate=2011-01-06 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=6
appointDate=2011-01-07 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=7
appointDate=2011-01-08 10:35:43
本周开始 date[0]=2011-01-03 00:00:00
本周结束 date[1]=2011-01-09 23:59:59

dayOfWeek=1
appointDate=2011-01-09 10:35:43
本周开始 date[0]=2011-01-10 00:00:00
本周结束 date[1]=2011-01-16 23:59:59

这个是不是有问题?
凡是dayOfWeek=1 的话,都会有问题!!!
0 请登录后投票
   发表时间:2010-12-29  
能不能哪位大虾给个web应用上 完美点的时间处理类
0 请登录后投票
   发表时间:2010-12-29  
mfkvfn 写道
没全部看完。代码质量不高。

执行效率和安全性上都有问题。也多分配了一些多余对象容易引起性能问题。
而且使用了一些第三方类,导致使用你的代码还要引入额外的jar包。

高手,大体浏览下就知道代码的优缺点。希望达到你的层次~
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics