在Java中,你真的会日期转换吗
1.什么是SimpleDateFormat
在java doc对SimpleDateFormat的解释如下:
SimpleDateFormat
is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date → text), parsing (text → date), and normalization.
SimpleDateFormat是一个用来对位置敏感的格式化和解析日期的实体类。他允许把日期格式化成text,把text解析成日期和规范化。
1.1使用SimpleDateFormat
simpleDateFormat的使用方法比较简单:
public static void main(String[] args) throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
System.out.println(simpleDateFormat.format(new Date()));
System.out.println(simpleDateFormat.parse("2018-07-09 11:10:21"));
}
复制代码
1.首先需要定义一个日期的pattern,这里我们定义的是"yyyy-mm-dd HH:mm:ss" ,也就是我们这个simpleDateFormat不管是格式化还是解析都需要按照这个pattern。
2.对于format需要传递Date的对象,会返回一个String类型,这个String会按照我们上面的格式生成。
3.对于parse需要传递一个按照上面pattern的字符串,如果传递错误的pattern会抛出java.text.ParseException异常,如果传递正确的会生成一个Date对象。
附:格式占位符
G 年代标志符
y 年
M 月
d 日
h 时 在上午或下午 (1~12)
H 时 在一天中 (0~23)
m 分
s 秒
S 毫秒
E 星期
D 一年中的第几天
F 一月中第几个星期几
w 一年中第几个星期
W 一月中第几个星期
a 上午 / 下午 标记符
k 时 在一天中 (1~24)
K 时 在上午或下午 (0~11)
z 时区
复制代码
2.SimpleDateFormat的隐患
很多初学者,或者一些经验比较浅的java开发工程师,用SimpleDateFormat会出现一些奇奇怪怪的BUG。
1.结果值不对:转换的结果值经常会出人意料,和预期不同,往往让很多人摸不着头脑。
2.内存泄漏: 由于转换的结果值不对,后续的一些操作,如一个循环,累加一天处理一个东西,但是生成的日期如果异常导致很大的话,会让这个循环变成一个类似死循环一样导致系统内存泄漏,频繁触发GC,造成系统不可用。
为什么会出现这么多问题呢?因为SimpleDateFormat线程不安全,很多人都会写个Util类,然后把SimpleDateFormat定义成全局的一个常量,所有线程都共享这个常量:
protected static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
public static Date formatDate(String date) throws ParseException {
return dayFormat.parse(date);
}
复制代码
为什么SimpleDateFormat会线程不安全呢,在SimpleDateFormat源码中,所有的格式化和解析都需要通过一个中间对象进行转换,那就是Calendar,而这个也是我们出现线程不安全的罪魁祸首,试想一下当我们有多个线程操作同一个Calendar的时候后来的线程会覆盖先来线程的数据,那最后其实返回的是后来线程的数据,这样就导致我们上面所述的BUG的产生:
/
/ Called from Format after creating a FieldDelegate
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern\[i\] >>> 8;
int count = compiledPattern\[i++\] & 0xff;
if (count == 255) {
count = compiledPattern\[i++\] << 16;
count |= compiledPattern\[i++\];
}
switch (tag) {
case TAG\_QUOTE\_ASCII_CHAR:
toAppendTo.append((char)count);
break;
case TAG\_QUOTE\_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;
default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}
复制代码
3.如何避坑
对于SimpleDateFormat的解决方法有下面几种:
3.1新建SimpleDateFormat
上面出现Bug的原因是因为所有线程都共用一个SimpleDateFormat,这里有个比较好解决的办法,每次使用的时候都创建一个新的SimpleDateFormat,我们可以在DateUtils中将创建SimpleDateFormat放在方法内部:
public static Date formatDate(String date) throws ParseException {
SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");
return dayFormat.parse(date);
}
复制代码
上面这个方法虽然能解决我们的问题但是引入了另外一个问题就是,如果这个方法使用量比较大,有可能会频繁造成Young gc,整个系统还是会受一定的影响。
3.2使用ThreadLocal
使用ThreadLocal能避免上面频繁的造成Young gc,我们对每个线程都使用ThreadLocal进行保存,由于ThreadLocal是线程之间隔离开的,所以不会出现线程安全问题:
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<>();
public static Date formatDate(String date) throws ParseException {
SimpleDateFormat dayFormat = getSimpleDateFormat();
return dayFormat.parse(date);
}
private static SimpleDateFormat getSimpleDateFormat() {
SimpleDateFormat simpleDateFormat = simpleDateFormatThreadLocal.get();
if (simpleDateFormat == null){
simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss")
simpleDateFormatThreadLocal.set(simpleDateFormat);
}
return simpleDateFormat;
}
复制代码
3.3使用第三方工具包
虽然上面的ThreadLocal能解决我们出现的问题,但是第三方工具包提供的功能更加强大,在java中有两个类库比较出名一个是Joda-Time,一个是Apache common包
3.3.1 Joda-Time(推荐)
Joda-Time 令时间和日期值变得易于管理、操作和理解。对于我们复杂的操作都可以使用Joda-Time操作,下面我列举两个例子,对于把日期加上90天,如果使用原生的Jdk我们需要这样写:
Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
SimpleDateFormat sdf =
new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.add(Calendar.DAY\_OF\_MONTH, 90);
System.out.println(sdf.format(calendar.getTime()));
复制代码
但是在我们的joda-time中只需要两句话,并且api也比较通俗易懂,所以你为什么不用Joda-Time呢?
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");
复制代码
3.3.2 common-lang包
在common-lang包中有个类叫FastDateFormat,由于common-lang这个包基本被很多Java项目都会引用,所以你可以不用专门去引用处理时间包,即可处理时间,在FastDateFormat中每次处理时间的时候会创建一个calendar,使用方法比较简单代码如下所示:
FastDateFormat.getInstance().format(new Date());
3.4升级jdk8(推荐)
在java8中Date这个类中的很多方法包括构造方法都被打上了@Deprecated废弃的注解,取而代之的是LocalDateTime,LocalDate LocalTime这三个类:
LocalDate无法包含时间;
LocalTime无法包含日期;
LocalDateTime才能同时包含日期和时间。
如果你是Java8,那你一定要使用他,在日期的格式化和解析方面不用考虑线程安全性,代码如下:
public static String formatTime(LocalDateTime time,String pattern) {
return time.format(DateTimeFormatter.ofPattern(pattern));
}
复制代码
当然localDateTime是java8的一大亮点,当然不仅仅只是解决了线程安全的问题,同样也提供了一些其他的运算比如加减天数:
//日期加上一个数,根据field不同加不同值,field为ChronoUnit.*
public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
return time.plus(number, field);
}
//日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*
public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field){
return time.minus(number,field);
}
复制代码
最后,如果你担心使用LocalDateTime 会对你现有的代码产生很大的改变的话,那你可以将他们两进行互转:
//Date转换为LocalDateTime
public static LocalDateTime convertDateToLDT(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
//LocalDateTime转换为Date
public static Date convertLDTToDate(LocalDateTime time) {
return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
}
在Java中,你真的会日期转换吗的更多相关文章
- Java中数据类型及其之间的转换
Java中数据类型及其之间的转换 基本的数据类型 基本类型有以下四种:1)int长度数据类型有:byte(8bits).short(16bits).int(32bits).long(64bits).2 ...
- (转)SQL Server中使用convert进行日期转换
原文链接:http://www.cnblogs.com/weiqt/articles/1826847.html SQL Server中使用convert进行日期转换 一般存入数据库中的时间格式为yyy ...
- Java中数据类型及其之间的转换(转)
Java中数据类型及其之间的转换 基本的数据类型 基本类型有以下四种:1)int长度数据类型有:byte(8bits).short(16bits).int(32bits).long(64bits).2 ...
- 关于==和equals()方法&Java中string与char如何转换&String,StringBuffer
1.对于基本数据类型,可以直接使用==和!=进行内容比较 如:int x=30; int y=30; x==y; //true 基本数据类型 简单类型(基本类型) bo ...
- java中经常使用的日期格式化(全)
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...
- Java中关于Date等日期类的简单使用
Date Date类不常用,很多方法被废弃了,常用它的两个构造方法来new一个Date对象. Date d1 = new Date(); //不传任何参数,代表当前时间点 System.out.pri ...
- JAVA中计算两个日期时间的差值竟然也有这么多门道
上半年春招的时候,作为面试官,对于面试表现的不错的同学会要求其写一小段代码看看.题目很简单: 给定一个日期,然后计算下距离今天相差的天数. 本以为这么个问题就是用来活跃面试氛围的,但是结果却让人大跌眼 ...
- 一段代码了解Java中char和int的转换
题目要求: 将输入的大写字母转成对应小写的后5个,如A转换后为f:如果转换后大于z则从a重新计,即多出1就转成a,多出2就转成b以此类推. Java代码: ```java private static ...
- Java中int和String互相转换的多种方法
1 如何将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 i = Integer.parseInt([ ...
- java中的基本数据类型的转换
本文参考了如下两篇文章: https://my.oschina.net/joymufeng/blog/139952 http://www.cnblogs.com/lwbqqyumidi/p/37001 ...
随机推荐
- 利用canvas对上传图片进行上传前压缩
利用谷歌调式工具发现,图片大小直接影响着首屏加载时间. 且考虑到后期服务端压力,图片压缩特别必要. 本文是前端利用canvas实现图片.参考文章:https://www.cnblogs.com/007 ...
- (八)Jmeter怎么通过后置处理器去做关联
一.Jmeter关联的方式: Jmeter中关联可以在需要获取数据的请求上 右键-->后置处理器 选择需要的关联方式,如下图有很多种方法可以提取动态变化数据: 二.正则表达式提取器: 1.比如 ...
- 新浪 ip 地址库
API地址:http://int.dpool.sina.com.cn/iplookup/iplookup.php 帮助 1 2 3 4 5 6 7 8 function get_location($i ...
- iOS OC语言原生开发的IM模块--RChat
iOS OC语言原生开发的IM模块,用于项目中需要原生开发IM的情况,具备发送文字.表情.语音.图片.视频等完整功能,包含图片预览视频播放等功能,此项目将会长期更新如有问题可以提出,我的邮箱:fshm ...
- 转---秒杀多线程第五篇 经典线程同步 关键段CS
上一篇<秒杀多线程第四篇 一个经典的多线程同步问题>提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文首先介绍下如何使用关键段,然 ...
- [十二]SpringBoot 之 servlet
Web开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet.Filter.Listener.Interceptor 等等. 当使用spring-Boot时,嵌 ...
- [BZOJ4103][Thu Summer Camp 2015]异或运算 可持久化Trie树
4103: [Thu Summer Camp 2015]异或运算 Time Limit: 20 Sec Memory Limit: 512 MB Description 给定长度为n的数列X={x1 ...
- Elasticsearch在windows上安装好了之后怎么使用?
windows 10上安装Elasticsearch过程记录 一.安装和配置Java JDK1.下载:http://download.oracle.com/otn ... 4.exe2.设置环境变量: ...
- 【NOIP考试范围】
※号为可能考察的算法[历年有出现过,但概率小,但最好掌握] [本图片仅作参考] 梦想总是要有的,万一实现了呢?
- 20135239益西拉姆 Linux内核分析 操作系统是怎样工作的?
益西拉姆+ 原创作品+ <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 堆栈 堆栈是C语言程序运行时 ...