专栏首页只为你下Java日期处理易踩的十个坑
原创

Java日期处理易踩的十个坑

  整理了Java日期处理的十个坑,希望对大家有帮助。

  

  一、用Calendar设置时间的坑

  

  反例:

  

  Calendar c = Calendar.getInstance();

  

  c.set(Calendar.HOUR, 10);

  

  System.out.println(c.getTime());

  

  运行结果:

  

  Thu Mar 26 22:28:05 GMT+08:00 2020

  

  解析:

  

  我们设置了10小时,但运行结果是22点,而不是10点。因为Calendar.HOUR默认是按12小时制处理的,需要使用Calendar.HOUR_OF_DAY,因为它才是按24小时处理的。

  

  正例:

  

  Calendar c = Calendar.getInstance();

  

  c.set(Calendar.HOUR_OF_DAY, 10);

  

  二、Java日期格式化YYYY的坑

  

  反例:

  

  Calendar calendar = Calendar.getInstance();

  

  calendar.set(2019, Calendar.DECEMBER, 31);

  

  Date testDate = calendar.getTime();

  

  SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");

  

  System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate));

  

  运行结果:

  

  2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31

  

  解析:

  

  为什么明明是2019年12月31号,就转了一下格式,就变成了2020年12月31号了?因为YYYY是基于周来计算年的,它指向当天所在周属于的年份,一周从周日开始算起,周六结束,只要本周跨年,那么这一周就算下一年的了。正确姿势是使用yyyy格式。

  

  正例:

  

  Calendar calendar = Calendar.getInstance();

  

  calendar.set(2019, Calendar.DECEMBER, 31);

  

  Date testDate = calendar.getTime();

  

  SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd");

  

  System.out.println("2019-12-31 转 yyyy-MM-dd 格式后 " + dtf.format(testDate));

  

  三、Java日期格式化hh的坑。

  

  反例:

  

  String str = "2020-03-18 12:00";

  

  SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd hh:mm");

  

  Date newDate = dtf.parse(str);

  

  System.out.println(newDate);

  

  运行结果:

  

  Wed Mar 18 00:00:00 GMT+08:00 2020

  

  解析:

  

  设置的时间是12点,为什么运行结果是0点呢?因为hh是12制的日期格式,当时间为12点,会处理为0点。正确姿势是使用HH,它才是24小时制。

  

  正例:

  

  String str = "2020-03-18 12:00";

  

  SimpleDateFormat dtf www.shentuylgw.cn= new SimpleDateFormat("yyyy-MM-dd HH:mm");

  

  Date newDate = dtf.parse(str);

  

  System.out.println(newDate);

  

  四、Calendar获取的月份比实际数字少1即(0-11)

  

  反例:

  

  //获取当前月,当前是3月

  

  Calendar calendar = Calendar.getInstance();

  

  System.out.println("当前"+calendar.get(Calendar.MONTH)+"月份");

  

  运行结果:

  

  当前2月份

  

  解析:

  

  The first month of the year in the Gregorian and Julian calendars

  

  is <code>JANUARY</code> which is 0;

  

  也就是1月对应的是下标 0,依次类推。因此获取正确月份需要加 1.

  

  正例:

  

  //获取当前月,当前是3月

  

  Calendar calendar = Calendar.getInstance();

  

  System.out.println("当前"+( shentuylzc.cn calendar.get(Calendar.MONTH)+1)+"月份");

  

  五、Java日期格式化DD的坑

  

  反例:

  

  Calendar calendar = Calendar.getInstance();

  

  calendar.set(2019, Calendar.DECEMBER, 31);

  

  Date testDate = calendar.getTime(www.luqintang.com);

  

  SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-DD");

  

  System.out.println("2019-12-31 转 yyyy-MM-DD 格式后 " +www.lecaixuanzc.cn dtf.format(testDate));

  

  运行结果:

  

  2019-12-31 转 yyyy-MM-DD 格式后 2019-12-365

  

  解析:

  

  DD和dd表示的不一样,DD表示的是一年中的第几天,而dd表示的是一月中的第几天,所以应该用的是dd。

  

  正例:

  

  Calendar calendar = Calendar.getInstance();

  

  calendar.set(2019, Calendar.DECEMBER, 31);

  

  Date testDate = calendar.getTime(www.jucaiylzc.cn);

  

  SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd");

  

  System.out.println("2019-12-31 转 yyyy-MM-dd 格式后 " + dtf.format(testDate));

  

  六、SimleDateFormat的format初始化问题

  

  反例:

  

  SimpleDateFormat sdf = new SimpleDateFormat(www.jucaiyle.cn"yyyy-MM-dd");

  

  System.out.println(sdf.format(20200323));

  

  运行结果:

  

  1970-01-01

  

  解析:

  

  用format格式化日期是,要输入的是一个Date类型的日期,而不是一个整型或者字符串。

  

  正例:

  

  Calendar calendar = Calendar.getInstance();

  

  calendar.set(2020, Calendar.MARCH, 23);

  

  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

  

  System.out.println(sdf.format(calendar.getTime()));

  

  七、日期本地化问题

  

  反例:

  

  String dateStr = "Wed Mar 18 10:00:00 2020";

  

  DateTimeFormatter formatter www.javachenglei.com= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy");

  

  LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);

  

  System.out.println(dateTime);

  

  运行结果:

  

  Exception in thread "main" java.time.format.DateTimeParseException: Text 'Wed Mar 18 10:00:00 2020' could not be parsed at index 0

  

  at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)

  

  at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)

  

  at java.time.LocalDateTime.parse(LocalDateTime.java:492)

  

  at com.example.demo.SynchronizedTest.main(SynchronizedTest.java:19)

  

  解析:

  

  DateTimeFormatter 这个类默认进行本地化设置,如果默认是中文,解析英文字符串就会报异常。可以传入一个本地化参数(Locale.US)解决这个问题

  

  正例:

  

  String dateStr = "Wed Mar 18 10:00:00 2020";

  

  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy",Locale.US);

  

  LocalDateTime dateTime = LocalDateTime.parse(www.yongshiyule178.com dateStr, formatter);

  

  System.out.println(dateTime);

  

  八、SimpleDateFormat 解析的时间精度问题

  

  反例:

  

  SimpleDateFormat sdf =www.zhuyngyule.cn new SimpleDateFormat("yyyy-MM-dd");

  

  String time = "2020-03";

  

  System.out.println(sdf.parse(time));

  

  运行结果:

  

  Exception in thread "main" java.text.ParseException: Unparseable date: "2020-03"

  

  at java.text.DateFormat.parse(www.51kunlunyule.com DateFormat.java:366)

  

  at com.example.demo.SynchronizedTest.main(www.chuancenpt.com SynchronizedTest.java:19)

  

  解析:

  

  SimpleDateFormat 可以解析长于/等于它定义的时间精度,但是不能解析小于它定义的时间精度。

  

  正例:

  

  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");

  

  String time = "2020-03";

  

  System.out.println(sdf.parse(time));

  

  九、SimpleDateFormat 的线性安全问题

  

  反例:

  

  public class SimpleDateFormatTest {

  

  private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  

  public static void main(String[www.yixingylzc.cn] args) {

  

  ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000));

  

  while (true) {

  

  threadPoolExecutor.execute((www.baihua178.cn) -> {

  

  String dateString = sdf.format(new Date());

  

  try {

  

  Date parseDate = sdf.parse(dateString);

  

  String dateString2 = sdf.format(parseDate);

  

  System.out.println(dateString.equals(dateString2));

  

  } catch (ParseException e) {

  

  e.printStackTrace(www.moyouptzc.cn);

 

  运行结果:

  

  Exception in thread "pool-1-thread-49" java.lang.NumberFormatException: For input string: "5151."

  

  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

  

  at java.lang.Long.parseLong(Long.java:589)

  

  at java.lang.Long.parseLong(Long.java:631)

  

  at java.text.DigitList.getLong(DigitList.java:195)

  

  at java.text.DecimalFormat.parse(DecimalFormat.java:2051)

  

  at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)

  

  at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)

  

  at java.text.DateFormat.parse(DateFormat.java:364)

  

  at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)

  

  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

  

  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

  

  at java.lang.Thread.run(Thread.java:748)

  

  Exception in thread "pool-1-thread-47" java.lang.NumberFormatException: For input string: "5151."

  

  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

  

  at java.lang.Long.parseLong(Long.java:589)

  

  at java.lang.Long.parseLong(Long.java:631)

  

  at java.text.DigitList.getLong(DigitList.java:195)

  

  at java.text.DecimalFormat.parse(DecimalFormat.java:2051)

  

  at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)

  

  at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)

  

  at java.text.DateFormat.parse(DateFormat.java:364)

  

  at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)

  

  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

  

  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

  

  at java.lang.Thread.run(Thread.java:748)

  

  解析:

  

  全局变量的SimpleDateFormat,在并发情况下,存在安全性问题。

  

  SimpleDateFormat继承了 DateFormat

  

  DateFormat类中维护了一个全局的Calendar变量

  

  sdf.parse(dateStr)和sdf.format(date),都是由Calendar引用来储存的。

  

  如果SimpleDateFormat是static全局共享的,Calendar引用也会被共享。

  

  又因为Calendar内部并没有线程安全机制,所以全局共享的SimpleDateFormat不是线性安全的。

  

  解决SimpleDateFormat线性不安全问题,有三种方式:

  

  将SimpleDateFormat定义为局部变量

  

  使用ThreadLocal。

  

  方法加同步锁synchronized。

  

  正例:

  

  public class SimpleDateFormatTest {

  

  private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

  

  private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>();

  

  public static DateFormat getDateFormat() {

  

  DateFormat df = threadLocal.get();

  

  if(df == null){

  

  df = new SimpleDateFormat(DATE_FORMAT);

  

  threadLocal.set(df);

  

  }

  

  return df;

  

  }

  

  public static String formatDate(Date date) throws ParseException {

  

  return getDateFormat().format(date);

  

  }

  

  public static Date parse(String strDate) throws ParseException {

  

  return getDateFormat().parse(strDate);

  

  }

  

  public static void main(String[] args) {

  

  ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000));

  

  while (true) {

  

  threadPoolExecutor.execute(() -> {

  

  try {

  

  String dateString = formatDate(new Date());

  

  Date parseDate = parse(dateString);

  

  String dateString2 = formatDate(parseDate);

  

  System.out.println(dateString.equals(dateString2));

  

  } catch (ParseException e) {

  

  e.printStackTrace();

  

  }

  

  });

  

  }

  

  }

  

  }

  

  十、Java日期的夏令时问题

  

  反例:

  

  TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));

  

  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  

  System.out.println(sdf.parse("1986-05-04 00:30:00"));

  

  运行结果:

  

  Sun May 04 01:30:00 CDT 1986

  

  解析:

  

  先了解一下夏令时

  

  夏令时,表示为了节约能源,人为规定时间的意思。

  

  一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。

  

  各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。

  

  1986年4月,中国中央有关部门发出“在全国范围内实行夏时制的通知”,具体作法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时。(1992年起,夏令时暂停实行。)

  

  夏时令这几个时间可以注意一下哈,1986-05-04, 1987-04-12, 1988-04-10, 1989-04-16, 1990-04-15, 1991-04-14.

  

  结合demo代码,中国在1986-05-04当天还在使用夏令时,时间被拨快了1个小时。所以0点30分打印成了1点30分。如果要打印正确的时间,可以考虑修改时区为东8区。

  

  正例:

  

  TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));

  

  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  

  System.out.println(sdf.parse("1986-05-04 00:30:00"));

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 沙堆模型中的智慧,时代的一粒灰,落在个人头上就是一座山

    这篇文章,我们通过一个更加普遍而又简单的现象来更深入地讨论【自组织临界动力学】。沙堆是我们日常生活经验的一部分,在沙滩上玩过沙的孩子都懂得。

    不会飞的小鸟
  • Serverless Component

    相信读完前面几篇有关 Serverless Component 文章的小伙伴已经体验到,它给我们开发带来的遍历。但是实际我们的日常开发项目中,并不仅仅只是单纯地...

    不会飞的小鸟
  • 基于Jquery WeUI的微信开发H5页面控件的经验总结(2)

      在微信开发H5页面的时候,往往借助于WeUI或者Jquery WeUI等基础上进行界面效果的开发,由于本人喜欢在Asp.net的Web界面上使用JQuery...

    不会飞的小鸟
  • 程序员必备:Java日期处理的十个坑

    我们设置了10小时,但运行结果是22点,而不是10点。因为Calendar.HOUR默认是按12小时制处理的,需要使用Calendar.HOUROFDAY,因为...

    捡田螺的小男孩
  • 1.3java的运行原理

    java的运行原理 这里我们简单分析一下我们的第一个应用程序,其中涉及到很多没有接触过的概念,大家可先阅读以下,以后会详细讲解。重点是理解java的运行原理。 ...

    Java学习
  • Exception in thread "main" java.lang.NoClassDefFoundError: UDP_Receive (wrong na me: com/ray/net/UDP

        今晚学习java网络编程,在eclipse中写了两个个java文件,一个发送端UDP_Send2.java,一个接收端UDP_Receive.java。...

    shirayner
  • JVM | OpenJDK源码执行HelloWorld

    平时我们在运行java程序时, 一般有两种选择, 1是在服务器上直接用java -jar 命令来运行程序, 2是在idea中直接点击运行/debug,如下图所示...

    微笑的小小刀
  • 【入门篇】Linux服务器安装Java运行环境,即安装JDK

    前言:首先我们需要一个工具能够连接到服务器,这里先选用最轻便的PuTTY(其他工具都可)(点击下载PuTTY)

    Java编程指南
  • 修改github上仓库的项目的语言类型

    在把项目上传到github仓库上时语言会显示错误语言,github上的项目语言是自动识别的,也就是你某种语言的占比最多,就会自动识别为那种语言,这个方式显然不合...

    浩Coding
  • 前端基础-CSS网页调试

    在网页中点击右键,选择(审查元素/查看元素/检查)或者按F12,在右侧或下面会打开一个窗口,窗口最左边是查看html的结构,network是查看网页的http请...

    cwl_java

扫码关注云+社区

领取腾讯云代金券