关于SimpleDateFormat的陷阱
July 15, 2010 – 12:36 am代码中总是有那么多神奇的事情发生, 神奇的背后总是朴实无华的事实
1. SimpleDateFormat 是有 TimeZone的
1)每一个SimpleDateFormat的实例都会和一个TimeZone的实例相关联
2)在不指定TimeZone的情况下,SimpleDateFormat默认会使用OS的TimeZone
看下面的代码片段:
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); Date date = sdf.parse("18-07-1976"); System.out.println(date.getTime()); 这段代码展示的时间一般情况下是没问题的, 但是在两台不同TimeZone的OS上跑的时候获得的 时间是不一样的,在分布式环境中这个还是需要注意下的 修复后的代码 方法一:在期盼的日期格式中带上TimeZone SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy z"); Date date = sdf.parse("18-07-1976 ICT"); System.out.println(date.getTime()); 方法二: 用指定的TimeZone来解释所有的时间 SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); Date date = sdf.parse("18-07-1976"); 2. 验证时间字符串的合法性 一般传入一个时间字符串, 我们会用异常的形式判断其合法性 如: SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date d = null; try { d = sdf.parse(dateStr); } catch (ParseException e) { showErrorMessage("Incorrect date format. "+e.getMessage()); } 1)传入 “10//10/2008″ 肯定会抛出异常 2)传入 “40/20/2009″ 能顺利parse, 结果是按照SimpleDateFormat自己的推测计算出来的结果,一般不是我们期盼的 能顺利parse的原因是SimpleDateFormat默认是lenient(宽容)的,它会尽可能正确的解释传入的时间字符串, 而我们一 般是不希望它这么去处理, 我们可以它的模式: SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); sdf.setLenient(false); 这样SimpleDateFormt会按照严格的方式去处理时间了 3. 线程安全 SimpleDateFormat 是线程不安全的, 而创建一个SimpleDateFormat是比较耗资源的 。 为了既能减少多次创建的开销,并且防止race condition . 看到老外搞了如下一段代码: import java.lang.ref.SoftReference; import java.text.*; import java.util.Date; public class DateConverter { private static final ThreadLocal<SoftReference<DateFormat>> tl = new ThreadLocal<SoftReference<DateFormat>>(); private static DateFormat getDateFormat() { SoftReference<DateFormat> ref = tl.get(); if (ref != null) { DateFormat result = ref.get(); if (result != null) { return result; } } DateFormat result = new SimpleDateFormat("yyyy/MM/dd"); ref = new SoftReference<DateFormat>(result); tl.set(ref); return result; } public void testConvert(String date) { try { DateFormat formatter = getDateFormat(); Date d = formatter.parse(date); String newDate = formatter.format(d); if (!date.equals(newDate)) { System.out.println(date + " converted to " + newDate); } } catch (Exception e) { System.out.println(e); } } } 参考资料: http://eyalsch.wordpress.com/2009/05/29/sdf/ http://www.javaspecialists.eu/archive/Issue172.html
