在Java中,你真的會日期轉(zhuǎn)換嗎

1.什么是SimpleDateFormat

在java doc對SimpleDateFormat的解釋如下:

SimpleDateFormatis 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解析成日期和規(guī)范化。

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")); }復(fù)制代碼

1.首先需要定義一個日期的pattern,這里我們定義的是"yyyy-mm-dd HH:mm:ss" 黎茎,也就是我們這個simpleDateFormat不管是格式化還是解析都需要按照這個pattern。

2.對于format需要傳遞Date的對象当悔,會返回一個String類型傅瞻,這個String會按照我們上面的格式生成。

3.對于parse需要傳遞一個按照上面pattern的字符串盲憎,如果傳遞錯誤的pattern會拋出java.text.ParseException異常嗅骄,如果傳遞正確的會生成一個Date對象。

附:格式占位符 G 年代標(biāo)志符 y 年 M 月 d 日 h 時 在上午或下午 (1~12) H 時 在一天中 (0~23) m 分 s 秒 S 毫秒 E 星期 D 一年中的第幾天 F 一月中第幾個星期幾 w 一年中第幾個星期 W 一月中第幾個星期 a 上午 / 下午 標(biāo)記符 k 時 在一天中 (1~24) K 時 在上午或下午 (0~11) z 時區(qū)復(fù)制代碼

2.SimpleDateFormat的隱患

很多初學(xué)者焙畔,或者一些經(jīng)驗比較淺的java開發(fā)工程師掸读,用SimpleDateFormat會出現(xiàn)一些奇奇怪怪的BUG。

1.結(jié)果值不對:轉(zhuǎn)換的結(jié)果值經(jīng)常會出人意料,和預(yù)期不同儿惫,往往讓很多人摸不著頭腦澡罚。

2.內(nèi)存泄漏: 由于轉(zhuǎn)換的結(jié)果值不對,后續(xù)的一些操作肾请,如一個循環(huán)留搔,累加一天處理一個東西,但是生成的日期如果異常導(dǎo)致很大的話铛铁,會讓這個循環(huán)變成一個類似死循環(huán)一樣導(dǎo)致系統(tǒng)內(nèi)存泄漏隔显,頻繁觸發(fā)GC,造成系統(tǒng)不可用饵逐。

為什么會出現(xiàn)這么多問題呢括眠?因為SimpleDateFormat線程不安全,很多人都會寫個Util類倍权,然后把SimpleDateFormat定義成全局的一個常量掷豺,所有線程都共享這個常量:

protected static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");public static Date formatDate(String date) throws ParseException {returndayFormat.parse(date);}復(fù)制代碼

為什么SimpleDateFormat會線程不安全呢,在SimpleDateFormat源碼中,所有的格式化和解析都需要通過一個中間對象進(jìn)行轉(zhuǎn)換薄声,那就是Calendar当船,而這個也是我們出現(xiàn)線程不安全的罪魁禍?zhǔn)祝囅胍幌庐?dāng)我們有多個線程操作同一個Calendar的時候后來的線程會覆蓋先來線程的數(shù)據(jù)默辨,那最后其實返回的是后來線程的數(shù)據(jù)德频,這樣就導(dǎo)致我們上面所述的BUG的產(chǎn)生:

/在這里順便給大家推薦一個架構(gòu)交流群:617434785,里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring缩幸,MyBatis壹置,Netty源碼分析,高并發(fā)桌粉、高性能蒸绩、分布式、微服務(wù)架構(gòu)的原理铃肯,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系患亿。還能領(lǐng)取免費的學(xué)習(xí)資源。相信對于已經(jīng)工作和遇到技術(shù)瓶頸的碼友押逼,在這個群里會有你需要的內(nèi)容步藕。

/ 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) {caseTAG\_QUOTE\_ASCII_CHAR: toAppendTo.append((char)count);break;?caseTAG\_QUOTE\_CHARS: toAppendTo.append(compiledPattern, i, count); i += count;break;? default: subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);break; } }returntoAppendTo; }復(fù)制代碼

3.如何避坑

對于SimpleDateFormat的解決方法有下面幾種:

3.1新建SimpleDateFormat

上面出現(xiàn)Bug的原因是因為所有線程都共用一個SimpleDateFormat,這里有個比較好解決的辦法挑格,每次使用的時候都創(chuàng)建一個新的SimpleDateFormat,我們可以在DateUtils中將創(chuàng)建SimpleDateFormat放在方法內(nèi)部:

public static Date formatDate(String date) throws ParseException { SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd");returndayFormat.parse(date);}復(fù)制代碼

上面這個方法雖然能解決我們的問題但是引入了另外一個問題就是咙冗,如果這個方法使用量比較大,有可能會頻繁造成Young gc漂彤,整個系統(tǒng)還是會受一定的影響雾消。

3.2使用ThreadLocal

使用ThreadLocal能避免上面頻繁的造成Young gc灾搏,我們對每個線程都使用ThreadLocal進(jìn)行保存,由于ThreadLocal是線程之間隔離開的立润,所以不會出現(xiàn)線程安全問題:

private static ThreadLocal simpleDateFormatThreadLocal = new ThreadLocal<>(); public static Date formatDate(String date) throws ParseException { SimpleDateFormat dayFormat = getSimpleDateFormat();returndayFormat.parse(date); }? private static SimpleDateFormatgetSimpleDateFormat() { SimpleDateFormat simpleDateFormat = simpleDateFormatThreadLocal.get();if(simpleDateFormat == null){ simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd? HH:mm:ss") simpleDateFormatThreadLocal.set(simpleDateFormat); }returnsimpleDateFormat; }復(fù)制代碼

3.3使用第三方工具包

雖然上面的ThreadLocal能解決我們出現(xiàn)的問題狂窑,但是第三方工具包提供的功能更加強大,在java中有兩個類庫比較出名一個是Joda-Time,一個是Apache common包

3.3.1 Joda-Time(推薦)

Joda-Time 令時間和日期值變得易于管理桑腮、操作和理解泉哈。對于我們復(fù)雜的操作都可以使用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()));復(fù)制代碼

但是在我們的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");復(fù)制代碼

3.3.2 common-lang包

在common-lang包中有個類叫FastDateFormat烫沙,由于common-lang這個包基本被很多Java項目都會引用,所以你可以不用專門去引用處理時間包隙笆,即可處理時間斧吐,在FastDateFormat中每次處理時間的時候會創(chuàng)建一個calendar,使用方法比較簡單代碼如下所示:

FastDateFormat.getInstance().format(new Date());

3.4升級jdk8(推薦)

在java8中Date這個類中的很多方法包括構(gòu)造方法都被打上了@Deprecated廢棄的注解,取而代之的是LocalDateTime,LocalDate LocalTime這三個類:

LocalDate無法包含時間仲器;

LocalTime無法包含日期;

LocalDateTime才能同時包含日期和時間仰冠。

如果你是Java8乏冀,那你一定要使用他,在日期的格式化和解析方面不用考慮線程安全性洋只,代碼如下:

public static String formatTime(LocalDateTime time,String pattern) {returntime.format(DateTimeFormatter.ofPattern(pattern)); }復(fù)制代碼

?

當(dāng)然localDateTime是java8的一大亮點辆沦,當(dāng)然不僅僅只是解決了線程安全的問題,同樣也提供了一些其他的運算比如加減天數(shù):

//日期加上一個數(shù),根據(jù)field不同加不同值,field為ChronoUnit.* public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {returntime.plus(number, field); }? //日期減去一個數(shù),根據(jù)field不同減不同值,field參數(shù)為ChronoUnit.* public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field){returntime.minus(number,field); }復(fù)制代碼

最后识虚,如果你擔(dān)心使用LocalDateTime 會對你現(xiàn)有的代碼產(chǎn)生很大的改變的話肢扯,那你可以將他們兩進(jìn)行互轉(zhuǎn):

//Date轉(zhuǎn)換為LocalDateTime public static LocalDateTime convertDateToLDT(Date date) {returnLocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); }? //LocalDateTime轉(zhuǎn)換為Date public static Date convertLDTToDate(LocalDateTime time) {returnDate.from(time.atZone(ZoneId.systemDefault()).toInstant()); }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市担锤,隨后出現(xiàn)的幾起案子蔚晨,更是在濱河造成了極大的恐慌,老刑警劉巖肛循,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铭腕,死亡現(xiàn)場離奇詭異,居然都是意外死亡多糠,警方通過查閱死者的電腦和手機累舷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夹孔,“玉大人被盈,你說我怎么就攤上這事析孽。” “怎么了只怎?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵袜瞬,是天一觀的道長。 經(jīng)常有香客問我尝盼,道長吞滞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任盾沫,我火速辦了婚禮裁赠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赴精。我一直安慰自己佩捞,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布蕾哟。 她就那樣靜靜地躺著一忱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谭确。 梳的紋絲不亂的頭發(fā)上帘营,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機與錄音逐哈,去河邊找鬼芬迄。 笑死,一個胖子當(dāng)著我的面吹牛昂秃,可吹牛的內(nèi)容都是我干的禀梳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肠骆,長吁一口氣:“原來是場噩夢啊……” “哼算途!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蚀腿,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤嘴瓤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后莉钙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纱注,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年胆胰,在試婚紗的時候發(fā)現(xiàn)自己被綠了狞贱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜀涨,死狀恐怖瞎嬉,靈堂內(nèi)的尸體忽然破棺而出蝎毡,到底是詐尸還是另有隱情,我是刑警寧澤氧枣,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布沐兵,位于F島的核電站,受9級特大地震影響便监,放射性物質(zhì)發(fā)生泄漏扎谎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一烧董、第九天 我趴在偏房一處隱蔽的房頂上張望毁靶。 院中可真熱鬧,春花似錦逊移、人聲如沸预吆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拐叉。三九已至,卻和暖如春扇商,著一層夾襖步出監(jiān)牢的瞬間凤瘦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工案铺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留廷粒,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓红且,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涤姊。 傳聞我的和親對象是個殘疾皇子暇番,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容