• Java中的时间处理


    1. 日期时间组件使用

      java.util.Date:实现类,其对象具有时间、日期组件。
      java.util.Calendar:抽象类,其对象具有时间、日期组件。
      java.sql.Date:实现类,其对象具有日期组件。
      java.sql.Time:实现类,其对象具有时间组件。
      java.sql.Timestamp:实现类,其对象具有时间日期组件。
      java.text.DateFormat:抽象类,其对象格式化时间日期。
      java.text.DateFormatSymbols:实现类,其对象为格式化时间日期提供参数。

    2. long currentTime = System.currentTimeMillis(); //获取当前时间戳,从1970-01-01以来的毫秒数
              LOGGER.info("{}", currentTime);
      
              java.util.Date utilDate = new java.util.Date(currentTime);
              LOGGER.info("{}|{}", utilDate, utilDate.getTime());
      
              Calendar calendar = Calendar.getInstance(); //除某些特殊地区外,默认等效于new GregorianCalendar()
              calendar.setTimeInMillis(currentTime);
              LOGGER.info("{}", calendar);
      
              java.sql.Date sqlDate = new java.sql.Date(currentTime);
              LOGGER.info("{}|{}", sqlDate, sqlDate.getTime());
      
              java.sql.Time sqlTime = new java.sql.Time(currentTime);
              LOGGER.info("{}|{}", sqlTime, sqlTime.getTime());
      
              java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(currentTime);
              LOGGER.info("{}|{}", sqlTimestamp, sqlTimestamp.getTime());
      
      
              DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //默认是SimpleDateFormat
      LOGGER.info("{}", dateFormat.format(utilDate));
      LOGGER.info("{}", dateFormat.parse("2017-05-25 23:00:00"));

      输出:

      1495724884755 
      Thu May 25 23:08:04 CST 2017|1495724884755 
      java.util.GregorianCalendar[time=1495724884755,...,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai"...] 
      2017-05-25|1495724884755 
      23:08:04|1495724884755 
      2017-05-25 23:08:04.755|1495724884755 
      2017-05-25 23:08:04 
      Thu May 25 23:00:00 CST 2017 
    3. java.text.SimpleDateFormat的线程不安全问题
      问题重现:

              //final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
      
              Callable<Date> task = new Callable<Date>() {
                  @Override
                  public Date call() throws Exception {
                      LOGGER.info("executing task...");
                      try{
                          return new SimpleDateFormat("yyyy-MM-dd").parse("2017-05-25");
                          //return format.parse("2017-05-25"); //if use shared SimpleDateFormat, executing result is not expected.
                      }catch (Exception ex){
                          LOGGER.error("Exception:", ex);
                          return new Date(0);
                      }
                  }
              };
              // pool with 5 threads
              ExecutorService exec = Executors.newFixedThreadPool(5);
              List<Future<Date>> results = new ArrayList<Future<Date>>();
              // perform 10 date conversions
              for (int i = 0; i < 10; i++) {
                  LOGGER.info("submit task[{}]", i);
                  results.add(exec.submit(task));
              }
              exec.shutdown();
              LOGGER.info("shutdown");
              // look at the results
              DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              for (Future<Date> result : results) {
                  LOGGER.info("{}", dateFormat.format(result.get()));
              }
              LOGGER.info("completed");

      输出(使用共享的SimpleDateFormat时,执行结果并不是预期结果):

      submit task[0] 
      submit task[1] 
      submit task[2] 
      executing task... 
      submit task[3] 
      executing task... 
      submit task[4] 
      executing task... 
      executing task... 
      submit task[5] 
      executing task... 
      submit task[6] 
      submit task[7] 
      submit task[8] 
      submit task[9] 
      shutdown 
      executing task... 
      executing task... 
      executing task... 
      executing task... 
      executing task... 
      Exception: 
      java.lang.NumberFormatException: multiple points
          at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
          at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
          at java.lang.Double.parseDouble(Double.java:538)
          at java.text.DigitList.getDouble(DigitList.java:169)
          at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
          at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
          at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
          at java.text.DateFormat.parse(DateFormat.java:364)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:65)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:59)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      Exception: 
      java.lang.NumberFormatException: empty String
          at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
          at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
          at java.lang.Double.parseDouble(Double.java:538)
          at java.text.DigitList.getDouble(DigitList.java:169)
          at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
          at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
          at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
          at java.text.DateFormat.parse(DateFormat.java:364)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:65)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:59)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      Exception: 
      java.lang.NumberFormatException: For input string: "E.2505E2"
          at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
          at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
          at java.lang.Double.parseDouble(Double.java:538)
          at java.text.DigitList.getDouble(DigitList.java:169)
          at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
          at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
          at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
          at java.text.DateFormat.parse(DateFormat.java:364)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:65)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:59)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      Exception: 
      java.lang.NumberFormatException: For input string: "E.2505"
          at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
          at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
          at java.lang.Double.parseDouble(Double.java:538)
          at java.text.DigitList.getDouble(DigitList.java:169)
          at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
          at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
          at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
          at java.text.DateFormat.parse(DateFormat.java:364)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:65)
          at com.liq.DateTimeTest$1.call(DateTimeTest.java:59)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)
      1970-01-01 08:00:00 
      1970-01-01 08:00:00 
      1970-01-01 08:00:00 
      1970-01-01 08:00:00 
      2017-05-25 00:00:00 
      2017-05-25 00:00:00 
      2017-05-25 00:00:00 
      2017-05-25 00:00:00 
      2017-05-25 00:00:00 
      2017-05-25 00:00:00 
      completed
      View Code

      产生原因:
      SimpleDateFormat维护一个共享的Calendar对象,如果共享SimpleDateFomat时这个Calendar也是共享的。由多个线程并发进行操作就会有问题了。

      protected Calendar calendar;

      解决:
      (1)使用局部变量
      (2)使用 ThreadLocal

              final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
                  @Override
                  protected DateFormat initialValue() {
                      return new SimpleDateFormat("yyyy-MM-dd");
                  }
              };
              //final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
      
              Callable<Date> task = new Callable<Date>() {
                  @Override
                  public Date call() throws Exception {
                      LOGGER.info("executing task...");
                      try{
                          //return new SimpleDateFormat("yyyy-MM-dd").parse("2017-05-25");
                          //return format.parse("2017-05-25"); //if use shared SimpleDateFormat, executing result is not expected.
                          return df.get().parse("2017-05-25");
                      }catch (Exception ex){
                          LOGGER.error("Exception:", ex);
                          return new Date(0);
                      }
                  }
              };

      (3)同步代码块 synchronized(code)
      (4)使用第三方的日期处理函数:比如使用 commons-lang 包中的 FastDateFormat 工具类

    4.  

    参考:

    1. 如何在Java 8中愉快地处理日期和时间
    2. Java中的时间日期处理
    3. 详解SimpleDateFormat的线程安全问题与解决方案
    4. java中关于时间的处理 *
    5. 日历字段之间的转换
  • 相关阅读:
    Java之基础(1)
    Java之架构(0)
    Android Exception 11(baidumapsdk(15405): Authentication Error errorcode: 102 uid)
    Android Exception 10(server)' ~ Channel is unrecoverably broken and will be disposed!)
    IOS Exception 1(libc++abi.dylib: terminating with uncaught exception of type NSException)
    Android Exception 9(requestFeature() must be called before adding content)
    Android Exception 8(Couldn't read row 0, col -1 from CursorWindow)
    简洁的BP及RBF神经网络代码
    Android实现一键获取课程成绩dome
    hdu 5371 Hotaru&#39;s problem【manacher】
  • 原文地址:https://www.cnblogs.com/liqipeng/p/6901791.html
Copyright © 2020-2023  润新知