new SimpleDateFormat() 吗?先说结论:
尽量少用SimpleDateFormat,原因有以下两点
如果使用static将SImpleDateFormat设置成共享变量,这会造成线程安全问题。如果一定要使用共享变量,那需要加锁! 或者可以使用JDK8+,使用DateTimeFormatter代替 SimpleDateFormat,这是一个线程安全的格式化工具类
两者最大的区别是,Java 8 新增的 DateTimeFormatter 是线程安全的,而 SimpleDateFormat 是线程不安全的。
DateTimeFormatter是在Java 8中引入的一个格式化器,用于打印和解析日期时间对象。
DateTimeFormatter是不可变的,并且是线程安全的。
DateTimeFormatter使用用户定义的格式(如 "yyyy-MMM-dd hh:mm:ss")或使用预定义的常数(如ISO_LOCAL_DATE_TIME)来格式化日期时间。
一个DateTimeFormatter可以用所需的Locale、Chronology、ZoneId和DecimalStyle创建。
DateTimeFormatter通过使用其ofPattern方法被实例化为一个日期时间格式字符串。
实例化DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // yyyy-MMM-dd HH:mm:ss
代码,用给定的格式打印日期时间(date-time)对象的代码:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateTime = formatter.format(LocalDateTime.now());
System.out.println(dateTime); //
用给定的格式解析一个日期时间(date-time)对象:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse("2018-Dec-20 08:25:30", formatter);
System.out.println(ldt); //2018-12-20T08:25:30
下面,我们将讨论DateTimeFormatter的方法,并举例说明LocalDate、LocalDateTime和LocalTime实例的格式。
DateTimeFormatter有以下静态方法来实例化DateTimeFormatter。
FormatStyle是一个枚举,其值可以是FULL, LONG, MEDIUM, SHORT。date-time)格式的格式化器。date-time)格式的格式化器。我们需要为日期和时间分别传递FormatStyle。例如,日期可以是LONG,时间可以是SHORT。import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("MMM dd, yyyy");
String formattedDate1 = formatter1.format(localDate);
System.out.println(formattedDate1); //Dec 17, 2018
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MMM dd, yyyy", Locale.CANADA);
String formattedDate2 = formatter2.format(localDate);
System.out.println(formattedDate2); //Dec. 17, 2018
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String formattedDate3 = formatter3.format(localDate);
System.out.println(formattedDate3); //Monday, December 17, 2018
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
String formattedDate4 = formatter4.format(localDateTime);
System.out.println(formattedDate4); //Dec 17, 2018, 9:14:39 PM
DateTimeFormatter formatter5 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT);
String formattedDate5 = formatter5.format(localDateTime);
System.out.println(formattedDate5); //December 17, 2018, 9:14 PM
LocalTime localTime = LocalTime.now();
DateTimeFormatter formatter6 = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
String formattedDate6 = formatter6.format(localTime);
System.out.println(formattedDate6); //9:14:39 PM
}
}
输出
Dec 17, 2018
Dec. 17, 2018
Monday, December 17, 2018
Dec 17, 2018, 9:14:39 PM
December 17, 2018, 9:14 PM
9:14:39 PM
它是一个关于本地化日期、时间或日期时间(date-time)格式化风格的枚举。
它有以下常数。
1.FULL:例如 'Tuesday, April 11, 2015 AD' or '5:30:45pm PST'.
'January 10, 2018'.'Jan 10, 2018''11.15.50' or '6:30pm'.为了格式化一个日期、时间或日期时间(date-time),DateTimeFormatter提供了以下方法。
date-time)对象进行格式化,并以字符串形式返回。date-time)对象进行格式化,并将结果附加到给定的Appendable对象中。Appendable对象可以是StringBuffer、StringBuilder等的实例。import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd hh:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
System.out.println(dtf.format(ldt)); //2018-Dec-20 03:50:45
StringBuffer sb = new StringBuffer("Date ");
dtf.formatTo(ldt, sb);
System.out.println(sb); //Date 2018-Dec-20 03:50:45
}
}
输出
2018-Dec-20 03:50:45
Date 2018-Dec-20 03:50:45
LocalDate是一个在ISO-8601日历系统中没有时区的日期。
找到使用DateTimeFormatter格式化LocalDate的例子。
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd");
LocalDate ld = LocalDate.now();
System.out.println(dtf.format(ld)); //2018-Dec-20
dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd(E)");
ld = LocalDate.now();
System.out.println(dtf.format(ld)); //2018-Dec-20(Thu)
dtf = DateTimeFormatter.ofPattern("MMM dd, YYYY");
ld = LocalDate.now();
System.out.println(dtf.format(ld)); //Dec 20, 2018
}
}
输出
2018-Dec-20
2018-Dec-20(Thu)
Dec 20, 2018 java
DateTimeFormatter也被用来解析一个本地日期。
示例代码:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd, yyyy");
LocalDate ld = LocalDate.parse("Dec 20, 2018", dtf);
System.out.println(ld);
输出
2018-12-20
LocalDateTime是ISO-8601日历系统中没有时区的日期时间。
查找使用DateTimeFormatter格式化LocalDateTime的示例。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd hh:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
System.out.println(dtf.format(ldt)); //2018-Dec-20 07:40:03
dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd(E) hh:mm:ss a");
ldt = LocalDateTime.now();
System.out.println(dtf.format(ldt)); //2018-Dec-20(Thu) 07:40:03 PM
dtf = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss");
ldt = LocalDateTime.now();
System.out.println(dtf.format(ldt)); //18-12-20 19:40:03
}
}
输出
2018-Dec-20 07:40:03
2018-Dec-20(Thu) 07:40:03 PM
18-12-20 19:40:03
DateTimeFormatter也被用来解析本地日期时间。
示例代码。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse("2018-Dec-20 08:25:30", dtf);
System.out.println(ldt);
输出
2018-12-20T08:25:30
LocalTime是ISO-8601日历系统中没有时区的时间。
查找使用DateTimeFormatter格式化LocalTime的例子。
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("hh:mm:ss");
LocalTime lt = LocalTime.now();
System.out.println(dtf.format(lt)); //08:03:32
dtf = DateTimeFormatter.ofPattern("hh:mm:ss a");
lt = LocalTime.now();
System.out.println(dtf.format(lt)); //08:03:32 PM
dtf = DateTimeFormatter.ofPattern("HH:mm");
lt = LocalTime.now();
System.out.println(dtf.format(lt)); //20:03
}
}
输出
08:03:32
08:03:32 PM
20:03
DateTimeFormatter也被用来解析本地时间。
示例代码。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
LocalTime lt = LocalTime.parse("08:25:30", dtf);
System.out.println(lt);
输出
08:25:30
DateTimeFormatter提供以下方法来解析文本。
1.
TemporalAccessor parse(CharSequence text)
解析一个日期、时间或日期时间(date-time)的文本,并返回时间性(temporal)对象。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss");
TemporalAccessor ta = formatter.parse("18-Dec-2017 02:46:41");
System.out.println(ta.get(ChronoField.YEAR));
System.out.println(ta.get(ChronoField.HOUR_OF_AMPM));
输出
2017
2
2.
TemporalAccessor parse(CharSequence text, ParsePosition position)
我们可以通过ParsePosition来转义给定文本中的一些字符。
我们用给定的初始索引启动一个ParsePosition,parse方法将从那里开始解析给定的文本。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss");
TemporalAccessor ta = formatter.parse("Date 18-Dec-2017 02:46:41", new ParsePosition(5));
System.out.println(ta.get(ChronoField.YEAR));
System.out.println(ta.get(ChronoField.HOUR_OF_AMPM));
输出
2017
2
3.
<T> T parse(CharSequence text, TemporalQuery<T> query)
解析给定的文本并返回TemporalQuery指定的对象。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss");
LocalDate localDate = formatter.parse("18-Dec-2017 02:46:41", TemporalQueries.localDate());
System.out.println(localDate);
输出
2017-12-18
4.
TemporalAccessor parseBest(CharSequence text, TemporalQuery<?>... queries)
解析给定文本并返回其中一个指定类型。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss");
TemporalAccessor ta = formatter.parseBest("18-Dec-2017 02:46:41",
TemporalQueries.localDate(), TemporalQueries.localTime());
System.out.println(ta);
输出
2017-12-18
5.
TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position)
用给定的ParsePosition解析给定的文本,但不解决它。
这意味着即使月日是38,它也不会产生错误。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss");
TemporalAccessor ta = formatter.parseUnresolved("Date 38-Dec-2017 02:46:41", new ParsePosition(5));
System.out.println(ta);
输出
{DayOfMonth=38, ClockHourOfAmPm=2, MinuteOfHour=46, YearOfEra=2017, SecondOfMinute=41, MonthOfYear=12},null
6.
static TemporalQuery<Period> parsedExcessDays()
提供一个查询,以访问作为已解析的Period的多余天数。
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("HH:mm");
TemporalAccessor parsed1 = formatter1.parse("24:00");
LocalTime lt1 = parsed1.query(LocalTime::from);
Period excessDays1 = parsed1.query(DateTimeFormatter.parsedExcessDays());
System.out.println(lt1 + " , " + excessDays1); //00:00 , P1D
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
TemporalAccessor parsed2 = formatter2.parse("2018-12-03 24:00");
LocalDateTime lt2 = parsed2.query(LocalDateTime::from);
Period excessDays2 = parsed2.query(DateTimeFormatter.parsedExcessDays());
System.out.println(lt2 + " , " + excessDays2); //2018-12-04T00:00 , P0D
}
}
输出
00:00 , P1D
2018-12-04T00:00 , P0D
我们可以看到,当我们只有时间时,24:00(一天的结束),我们得到的时间是00和超过1天(P1D意味着有1天的时间)。
但是当我们同时提供日期和时间时,在这种情况下,多余的天数就会加到日期部分。在我们的例子中,我们可以看到第3天已经变成了第4天,多余的天数为0。
7.
static TemporalQuery<Boolean> parsedLeapSecond()
提供一个查询,用于访问是否解析了闰秒。
如果解析到闰秒,该查询返回真,否则返回假。
在UTC时区,闰秒发生在'23:59:60'。
在其他时区,时间可能不同。
查找示例。
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
TemporalAccessor parsed = formatter.parse("2017-12-31T23:59:60Z");
Instant instant = parsed.query(Instant::from);
System.out.println(instant);
System.out.println("leap second parsed="
+ parsed.query(DateTimeFormatter.parsedLeapSecond()));
}
}
输出
2017-12-31T23:59:59Z
leap second parsed=true
DateTimeFormatter.ISO_INSTANT用UTC格式化一个瞬间(instant)。
下列方法返回DateTimeFormatter实例。
我们可以在使用DateTimeFormatterBuilder实例化DateTimeFormatter时使用上述方法。
查找示例代码。
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DecimalStyle;
import java.time.format.ResolverStyle;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = builder.appendLiteral("Day is:")
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(", month is:")
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral(", and year:")
.appendPattern("u")
.appendLiteral(" with the time:")
.appendValue(ChronoField.HOUR_OF_DAY)
.appendLiteral(":")
.appendText(ChronoField.MINUTE_OF_HOUR, TextStyle.NARROW_STANDALONE)
.toFormatter()
.withDecimalStyle(DecimalStyle.STANDARD)
.withChronology(IsoChronology.INSTANCE)
.withLocale(Locale.CANADA)
.withResolverStyle(ResolverStyle.LENIENT)
.withZone(ZoneId.systemDefault());
LocalDateTime dateTime = LocalDateTime.now();
String str = dateTime.format(formatter);
System.out.println(str);
}
}
输出
Day is:20, month is:12, and year:2018 with the time:11:36
我们可以使用以下方法获取DateTimeFormatter对象信息。
getChronology():获取年表。
getDecimalStyle():获取十进制风格。
getLocale():获取区域设置。
getResolverFields():获取解析器字段。
getResolverStyle():获取解析器样式。
getZone():获取区域。
示例
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
System.out.println("Chronology: " + dtf.getChronology());
System.out.println("DecimalStyle: " + dtf.getDecimalStyle());
System.out.println("Locale: "+ dtf.getLocale());
System.out.println("ResolverFields: "+ dtf.getResolverFields());
System.out.println("ResolverStyle: "+ dtf.getResolverStyle());
System.out.println("Zone: "+ dtf.getZone());
}
}
输出
Chronology: ISO
DecimalStyle: DecimalStyle[0+-.]
Locale: en_US
ResolverFields: null
ResolverStyle: STRICT
Zone: null
DateTimeFormatter提供以下方法将DateTimeFormatter转换为java.text.Format。
示例
import java.text.Format;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("MMM dd, yyyy");
Format format1 = dtf1.toFormat();
String ld = format1.format(LocalDate.parse("2017-12-20"));
System.out.println(ld); //Dec 20, 2017
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("HH:mm:ss");
Format format2 = dtf2.toFormat();
String time = format2.format(LocalDateTime.now());
System.out.println(time); //12:34:23
}
}
输出
Dec 20, 2017
12:34:23
DateTimeFormatter有以下预定义的格式。
| Formatter | Example |
|---|---|
| BASIC_ISO_DATE | ‘20181203’ |
| ISO_LOCAL_DATE | ‘2018-12-03’ |
| ISO_OFFSET_DATE | ‘2018-12-03+01:00’ |
| ISO_DATE | ‘2018-12-03+01:00’; ‘2018-12-03’ |
| ISO_LOCAL_TIME | ‘11:15:30’ |
| ISO_OFFSET_TIME | ‘11:15:30+01:00’ |
| ISO_TIME | ‘11:15:30+01:00’; ‘11:15:30’ |
| ISO_LOCAL_DATE_TIME | ‘2018-12-03T11:15:30’ |
| ISO_OFFSET_DATE_TIME | ‘2018-12-03T11:15:30+01:00’ |
| ISO_ZONED_DATE_TIME | ‘2018-12-03T11:15:30+01:00[Europe/Paris]’ |
| ISO_DATE_TIME | ‘2018-12-03T11:15:30+01:00[Europe/Paris]’ |
| ISO_ORDINAL_DATE | ‘2018-337’ |
| ISO_WEEK_DATE | ‘2018-W48-6’ |
| ISO_INSTANT | ‘2018-12-03T11:15:30Z’ |
| RFC_1123_DATE_TIME | ‘Tue, 3 Jun 2018 11:05:30 GMT’ |
例如,我们正在提供一个示例,以便使用预定义格式化器ISO_WEEK_DATE来打印和解析本地日期。
找到代码。
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ISO_WEEK_DATE;
String dateTime = formatter.format(LocalDate.now());
System.out.println(dateTime); //2018-W51-5
LocalDate ld = LocalDate.parse("2018-W40-4", formatter);
System.out.println(ld); //2018-10-04
}
}
输出
2018-W51-5
2018-10-04
找到格式化日期时间的模式字母(letters)和符号(symbols)。
| Symbol | Description | Example |
|---|---|---|
| G | era | AD; Anno Domini; A |
| u | year | 2018; 18 |
| y | year-of-era | 2018; 18 |
| D | day-of-year | 180 |
| M/L | month-of-year | 7; 07; Jul; July; J |
| d | day-of-month | 11 |
| g | modified-julian-day | 2451334 |
| Q/q | quarter-of-year | 3; 03; Q3; 3rd quarter |
| Y | week-based-year | 1999; 99 |
| w | week-of-week-based-year | 25 |
| W | week-of-month | 3 |
| E | day-of-week | Tue; Tuesday; T |
| e/c | localized day-of-week | 2; 02; Tue; Tuesday; T |
| F | day-of-week-in-month | 2 |
| a | am-pm-of-day | AM |
| h | clock-hour-of-am-pm (1-12) | 12 |
| K | hour-of-am-pm (0-11) | 0 |
| k | clock-hour-of-day (1-24) | 24 |
| H | hour-of-day (0-23) | 0 |
| m | minute-of-hour | 35 |
| s | second-of-minute | 50 |
| S | fraction-of-second | 970 |
| A | milli-of-day | 1234 |
| n | nano-of-second | 987654321 |
| N | nano-of-day | 1234000000 |
| V | time-zone ID | America/Los_Angeles; Z; -08:30 |
| v | generic time-zone name | Pacific Time; PT |
| z | time-zone name | Pacific Standard Time; PST |
| O | localized zone-offset | GMT+8; GMT+08:00; UTC-08:00 |
| X | zone-offset ‘Z’ for zero | Z; -08; -0830; -08:30; -083015; -08:30:15 |
| x | zone-offset | +0000; -08; -0830; -08:30; -083015; -08:30:15 |
| Z | zone-offset | +0000; -0800; -08:00 |
| p | pad next | 1 |
' | escape for text | |
'' | single quote | ' |
| [ | optional section start | |
| ] | optional section end |