java:SimpleDateFormat使用注意项

前言:Java中,说起日期转换,SimpleDateFormat不得不提,但是在实战操作中,使用时千万要小心。否则将会出现“ java.lang.NumberFormatException: multiple points”错误,那么究竟是为什么呢?

首先,请随小编来看看一个用到SimpleDateFormat的日期转换类。

package com.mwq.format;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */
    private static final SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");

    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
//          System.out.println(tomorrow);
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}

内容很简单,静态初始化一个SimpleDateFormat,然后用它来转换一个凌晨的时间戳,用到了SimpleDateFormat的format和parse方法。

类看起来似乎没什么问题,反正我是没找出什么理由来证明它写的有问题!(小编的编程水平有限啊!)

其次,我们写个测试类调用一下。

package com.mwq.format;

public class Test {

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {

            Thread thread1 = new Thread() {
                public void run() {
                    System.out.println(DateUtils.getTimeMillisSpecifyDaysBaseOnToday(0));
                }
            };
            thread1.start();
        }
    }

}

主类循环10此而已,创造线程来调用getTimeMillisSpecifyDaysBaseOnToday方法,也仅此而已。

然后,我们来看看结果。

1436544000000
1436544000000
835200000
1436544000000
1436544000000
835200000
Exception in thread "Thread-2" java.lang.NumberFormatException: multiple points
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1538)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1263)
    at java.text.DateFormat.parse(DateFormat.java:335)
    at com.mwq.format.DateUtils.getTimeMillisSpecifyDaysBaseOnToday(DateUtils.java:20)
    at com.mwq.format.Test$1.run(Test.java:10)
Exception in thread "Thread-9" java.lang.NumberFormatException: multiple points
1436544000000
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1538)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1263)
    at java.text.DateFormat.parse(DateFormat.java:335)
1436544000000
    at com.mwq.format.DateUtils.getTimeMillisSpecifyDaysBaseOnToday(DateUtils.java:20)
    at com.mwq.format.Test$1.run(Test.java:10)

什么?输出了一大推错误!

查看一下源码吧!

    /**
     * Returns a new <code>double</code> initialized to the value
     * represented by the specified <code>String</code>, as performed
     * by the <code>valueOf</code> method of class
     * <code>Double</code>.
     *
     * @param      s   the string to be parsed.
     * @return the <code>double</code> value represented by the string
     *         argument.
     * @exception NumberFormatException if the string does not contain
     *            a parsable <code>double</code>.
     * @see        java.lang.Double#valueOf(String)
     * @since 1.2
     */
    public static double parseDouble(String s) throws NumberFormatException {
    return FloatingDecimal.readJavaFormatString(s).doubleValue();
    }

如果这个字符串没有包含一个可转换的double,那么就会抛出NumberFormatException 异常。

当然这个解释对于上面出现错误,似乎没有什么好解释的。

那么,我们再来看看SimpleDateFormat的API doc解释。

parse
public Date parse(String text,
                  ParsePosition pos)解析字符串的文本,生成 Date。
此方法试图解析从 pos 给定的索引处开始的文本。如果解析成功,则将 pos 的索引更新为所用最后一个字符后面的索引(不必对直到字符串结尾的所有字符进行解析),并返回解析得到的日期。更新后的 pos 可以用来指示下次调用此方法的起始点。如果发生错误,则不更改 pos 的索引,并将 pos 的错误索引设置为发生错误处的字符索引,并且返回 null。 

指定者:
类 DateFormat 中的 parse
参数:
text - 应该解析其中一部分的 String。
pos - 具有以上所述的索引和错误索引信息的 ParsePosition 对象。
返回:
从字符串进行解析的 Date。如果发生错误,则返回 null。
抛出:
NullPointerException - 如果 text 或 pos 为 null。
另请参见:
DateFormat.setLenient(boolean)

也就是说,String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);

// System.out.println(tomorrow);

Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);

产生了空指针引用。

其实,再回看我们的日志信息,我们其实可以发现一些端倪。

835200000

1436544000000

1436544000000

835200000

如果一切正常的话,都应该输出“1436544000000”才对的,为什么出现了“835200000”?

再看看

此方法试图解析从 pos 给定的索引处开始的文本。如果解析成功,则将 pos 的索引更新为所用最后一个字符后面的索引(不必对直到字符串结尾的所有字符进行解析),并返回解析得到的日期。更新后的 pos 可以用来指示下次调用此方法的起始点。如果发生错误,则不更改 pos 的索引,并将 pos 的错误索引设置为发生错误处的字符索引,并且返回 null。

这段话,你也许就恍然大悟了,在多线程并发情况下,SimpleDateFormat显然不够安全

当然,这样的解释是我杜撰的!

那么,怎么来避免这样的错误呢?

1.DateUtils类中getTimeMillisSpecifyDaysBaseOnToday方法中打印一下tomorrow,或者随便输出一些东西就好了。

package com.mwq.format;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */
    private static final SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");

    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
            System.out.println(tomorrow);
//          System.out.println("111111111111");
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}

2.DateUtils类中的YMD_DASH_FORMATTER放错了位置,换成以下这样话,就不会有问题了。

package com.mwq.format;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */

    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
//          System.out.println(tomorrow);
//          System.out.println("");
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}

总结:其实这个时候,我不知道该说些什么?一则因为自己从来都没有对Java深入浅出过,二则因为如果不是读《effective Java 》,想用上面的思路应用到项目中造成的错误也不会有上面这些说辞,不过遇到问题探究一下总归是不错的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-24 12:14:37

java:SimpleDateFormat使用注意项的相关文章

Java SimpleDateFormat工具类

package AnimalDemo; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //日期工具类 public class DateUtil { public static final String DEFALT_ADTE_PATTERN="yyyy-MM-dd HH:mm:ss"; public static void main(String[]

java SimpleDateFormat日期与时间戳的相互转换

自我总结,有什么不满意的地方,各位可以帮忙纠正补充一下,感激不尽! 目的:SimpleDateFormat类可以很随意的组合日期时间的格式,不止单纯的yyyy-MM-dd这种格式 废话不多说,上代码 测试类 DateTest package com.core.test; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateTest {

maven: 打包可运行的jar包(java application)及依赖项处理

IDE环境中,可以直接用exec-maven-plugin插件来运行java application,类似下面这样: 1 <plugin> 2 <groupId>org.codehaus.mojo</groupId> 3 <artifactId>exec-maven-plugin</artifactId> 4 <version>1.2.1</version> 5 <executions> 6 <execu

Java SimpleDateFormat时间解析时区问题

spark JOB在hive入库的时候发生了很诡异的现象,根据report_time时间转换为小时分区的时候,时间对不上,而且只是部分时间对不上,相差12个小时. 由于其他集群未出现此问题,想通过代码发现是否逻辑存在问题.看了代码之后发现逻辑也十分简单: 获取了report_time之后直接通过一个时间转换函数,获取了时间.继续查看事件转化函数: 这里用到了java 中SimpleDateFormat 对给定的时间进行了转换,这种转换java中比较常见,应该也是没问题的. 怀疑跟集群的时间配置有

Java SimpleDateFormat 函数

一.SimpleDateFormat函数例子: SimpleDateFormat format=new SimpleDateFormat("MM-dd HH:mm:ss E"); String time=format.format(new Date()); System.out.println("当前时间: "+time); 二.SimpleDateFormat函数语法: G 年代标志符  y 年  M 月  d 日  h 时 在上午或下午 (1~12)  H 时

[java]SimpleDateFormat

1 public static void main(String[] args) throws ParseException { 2 SimpleDateFormat CeshiFmt0=new SimpleDateFormat("Gyyyy年MM月dd日 HH时mm分ss秒"); 3 SimpleDateFormat CeshiFmt1=new SimpleDateFormat("yyyy/MM/dd HH:mm"); 4 SimpleDateFormat Ces

Java SimpleDateFormat 中英文时间格式化转换

SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本).解析(文本 -> 日期)和规范化. SimpleDateFormat使得可以选择任何用户定义的日期-时间格式的模式.但是,仍然建议通过DateFormat中的getTimeInstance.getDateInstance 或 getDateTimeInstance 来创建日期-时间格式器.每一个这样的类方法都能够返回一个以默认格式模式初始化的日期/时间格式器.可以根据需

Java类(多项1对多映射)

1 class Province { 2 private int pid; 3 private String name; 4 private Stata stata; 5 private City citys [] ; 6 public void setStata(Stata stata){ 7 this.stata=stata; 8 } 9 public Stata getStata(){ 10 return this.stata; 11 } 12 public void setCitys(C

Java SimpleDateFormat 日期-时间格式参数

字母          日期或时间元素 表示          示例           G     Era 标志符 Text  AD y 年 Year 1996; 96 M 年中的月份 Month July; Jul; 07 w 年中的周数 Number 27 W 月份中的周数 Number 2 D 年中的天数 Number   189 d 月份中的天数 Number 10  F 月份中的星期 Number 2   E 星期中的天数 Text Tuesday; Tue  a Am/pm 标记