Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java日期处理易踩的十个坑

Java日期处理易踩的十个坑

原创
作者头像
不会飞的小鸟
修改于 2020-03-30 03:19:40
修改于 2020-03-30 03:19:40
1.6K0
举报
文章被收录于专栏:只为你下只为你下

  整理了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"));

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【优雅的避坑】不安全!别再共享SimpleDateFormat变量了-日期时间处理的正确姿势
JDK文档中已经明确表明了「SimpleDateFormat不应该用在多线程场景」中:
行百里er
2020/12/02
1.1K0
【优雅的避坑】不安全!别再共享SimpleDateFormat变量了-日期时间处理的正确姿势
SimpleDateFormat线程安全引发的事故以及解决方法
同事在多线程中使用了同一个日期的转换工具类,在运行过程中发现日志里偶现一些NumberFormatExcetion,刚开始他以为是数据问题,后来找我仔细分析日志,发现日期字符串存在丢失长度、长度不全等问题,判断是多线程导致,测试代码如下:
公众号 IT老哥
2022/09/19
3890
SimpleDateFormat线程安全引发的事故以及解决方法
Java 基础概念·Java 日期与时间
在计算机中,通常使用 Locale 表示一个国家或地区的日期、时间、数字、货币等格式。Locale 由 语言_国家 的字母缩写构成,例如,zh_CN 表示中文+中国,en_US 表示英文+美国。语言使用小写,国家使用大写。
数媒派
2022/12/01
5.9K0
SimpleDateFormat线程安全问题排查
SimpleDateFormat继承了DateFormat,DateFormat内部有一个Calendar对象的引用,主要用来存储和SimpleDateFormat相关的日期信息。
夕阳也是醉了
2023/10/16
3990
【程序猿硬核科普】Java获取指定时间年月日 | 时间戳转换bug你的项目中招了吗 | yyyy和YYYY的区别
最近在知乎看到有篇回答说:跨年导致日期格式YYYY和yyyy导致日期显示Bug的帖子,微信公众号、一些论坛好多中招了,快来看看你的项目里面有没有这个bug吧,哈哈lo(╥﹏╥)o。
浩Coding
2020/02/13
2.4K0
【程序猿硬核科普】Java获取指定时间年月日 | 时间戳转换bug你的项目中招了吗 | yyyy和YYYY的区别
java中的日期类
在程序的开发中我们经常会遇到日期类型的操作,Java对日期类型的操作提供了很好的支持。在最初的版本下,java.lang包中的System.currentTimeMillis();可以获取当前时间与协调时间(UTC)1970年1月1日午夜之间的时间差(以毫秒为单位测量)。我们往往通过调用该方法计算某段代码的耗时。
别团等shy哥发育
2023/02/25
4.8K0
java中的日期类
Java中的时间和日期(一):有关java时间的哪些坑
从一开始学习java到现在,我们都一直在使用java.util.Date这个对象来表示时间和日期。使用也很方便:
冬天里的懒猫
2020/08/11
2.7K0
Java中的时间和日期(一):有关java时间的哪些坑
一文带你入坑JDK8的新日期时间类 LocalDate、LocalTime、LocalDateTime
参考 https://blog.csdn.net/duan196_118/article/details/111597682 https://blog.csdn.net/qq_24754061/article/details/95500209 https://xijia.blog.csdn.net/article/details/106007147
时间静止不是简史
2023/02/23
5.8K0
一文带你入坑JDK8的新日期时间类 LocalDate、LocalTime、LocalDateTime
java最全最常用的日期工具类(随时补充)
@Slf4j public final class DateUtils { private DateUtils() { } private static final String FORMAT_YYYYMMDDHHMMSS = "yyyy-MM-dd HH:mm:ss"; public static final String FORMAT_YYYY_MM_DD = "yyyy-MM-dd"; public static final String FORMAT_
疯狂的KK
2023/04/10
1.5K0
Java日期计算常用方法《详细版》
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础入门篇)》 🐅 学会Golang语言,畅玩云原生,走遍大小厂~
猫头虎
2024/04/07
5790
java对时间的操作,提供给你工具类,直接调用方法就可以操作时间了
-创建 SimpleDateFormat 对象时必须指定转换格式。 -转换格式区分大小写,yyyy 代表年份,MM 代表月份,dd 代表日期,HH 代表 24 进制的小时,hh 代表 12 进制的小时,mm 代表分钟,ss 代表秒。
一写代码就开心
2020/11/20
3.4K0
java对时间的操作,提供给你工具类,直接调用方法就可以操作时间了
自定义 java 日期、时间 处理函数集
废话少说,在shell下很容易: june@deepin :~> date -d@1353027149 2012年 11月 16日 星期五 08:52:29 CST june@deepin :~> 但是 java 下比较折腾,网上转来抄去的代码也都是错误一大堆。。。 java代码如下: import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; i
用户1177713
2018/02/24
1K0
Java日期问题汇总
通常格式化日期时,都是使用的YYYY/MM/dd来格式化日期,但是在遇到跨年日期时,就会遇到很神奇的现象,如下:
雨临Lewis
2022/01/12
1.8K0
java 获取当前时间的三种方法
1.通过Util包中的Date获取 Date date = new Date(); SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd :hh:mm:ss"); System.out.println(dateFormat.format(date)); 2.通过Util包的Calendar 获取 Calendar calendar= Calendar.getInstance(); SimpleDateFormat dateForm
botkenni
2019/11/04
46.9K0
还在使用SimpleDateFormat?你的项目崩没?
日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对SimpleDateFormat并不陌生。主要是用它进行时间的格式化输出和解析,挺方便快捷的,但是SimpleDateFormat并不是一个线程安全的类。在多线程情况下,会出现异常,想必有经验的小伙伴也遇到过。下面我们就来分析分析SimpleDateFormat为什么不安全?是怎么引发的?以及多线程下有那些SimpleDateFormat的解决方案?
Java3y
2019/03/07
5320
还在使用SimpleDateFormat?你的项目崩没?
Java 日期处理类
日期处理类 Date类 当前日期时间 java.util.Date import java.util.Date; public class TestDemo { public static void main(String [] args) { Date date = new Date(); System.out.println(date); } } 运行结果: Sat Jun 29 21:56:04 CST 2019 上述的结果表示的就是当前的日期时间,为国际标准的格式; 当然我们可以使
Mirror王宇阳
2020/11/12
1.3K0
java 日期格式化– SimpleDateFormat 的使用。字符串转日期,日期转字符串
日期和时间格式由 日期和时间模式字符串 指定。在 日期和时间模式字符串 中,未加引号的字母 ‘A’ 到 ‘Z’ 和 ‘a’ 到 ‘z’ 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (‘) 引起来,以免进行解释。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串 白话文的讲:这些A——Z,a——z这些字母(不被单引号包围的)会被特殊处理替换为对应的日期时间,其他的字符串还是原样输出。
全栈程序员站长
2022/07/01
7.2K0
java 日期格式化– SimpleDateFormat 的使用。字符串转日期,日期转字符串
js和java日期的常用相关操作
js日期的相关操作 1. 时间戳时间格式化 代码如下: // 时间戳时间格式化 function timestampToTime(timestamp) { var date = new Da
不愿意做鱼的小鲸鱼
2022/09/26
3.2K0
java 星期几、得周一、得周日、上周、下周、相差、日期工具类
import org.apache.commons.lang3.StringUtils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * 日期工具类 * * @author silence * @version 2017/12/24 */ public class DateUtil {
微风-- 轻许--
2022/04/13
1.4K0
Java基础系列之日期时间处理
林老师带你学编程
2018/01/03
1K0
推荐阅读
相关推荐
【优雅的避坑】不安全!别再共享SimpleDateFormat变量了-日期时间处理的正确姿势
更多 >
领券
社区新版编辑器体验调研
诚挚邀请您参与本次调研,分享您的真实使用感受与建议。您的反馈至关重要,感谢您的支持与参与!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场