目录

Java-8-新特性Java-DateTimeFormatter-日期时间格式化器

【Java 8 新特性】Java DateTimeFormatter 日期时间格式化器

Java DateTimeFormatter 日期时间转化器

DateTimeFormatter 是在 Java 8 中引入的一个格式化器,用于打印和解析日期时间对象。

DateTimeFormatter 是不可变的,并且是线程安全的。

DateTimeFormatter使用用户定义的格式(如 "yyyy-MMM-dd hh:mm:ss" )或使用预定义的常数(如 ISO_LOCAL_DATE_TIME )来格式化日期时间。

一个 DateTimeFormatter 可以用所需的 LocaleChronologyZoneIdDecimalStyle 创建。

DateTimeFormatter 通过使用其 ofPattern 方法被实例化为一个日期时间格式字符串。

实例化 DateTimeFormatter

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm:ss"); 

查找代码,用给定的格式打印日期时间( date-time )对象的代码。

String dateTime = formatter.format(LocalDateTime.now());
System.out.println(dateTime); //2018-Dec-21 11:14:12 

查找代码,用给定的格式解析一个日期时间( date-time )对象。

LocalDateTime ldt = LocalDateTime.parse("2018-Dec-20 08:25:30", formatter);
System.out.println(ldt); //2018-12-20T08:25:30

下面,我们将讨论 DateTimeFormatter 的方法,并举例说明 LocalDateLocalDateTimeLocalTime 实例的格式。

实例化 DateTimeFormatter

DateTimeFormatter 有以下静态方法来实例化 DateTimeFormatter

  1. ofPattern(String pattern)
    使用给定的模式创建格式化器。
  2. ofPattern(String pattern, Locale locale)
    使用给定的模式和区域设置创建格式化器。
  3. ofLocalizedDate(FormatStyle dateStyle)
    创建具有当地特定日期格式的格式化器。 FormatStyle 是一个枚举,其值可以是 FULL , LONG , MEDIUM , SHORT
  4. ofLocalizedDateTime(FormatStyle dateTimeStyle)
    创建具有特定地区日期时间( date-time )格式的格式化器。
  5. ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle)
    创建具有特定地区日期时间( date-time )格式的格式化器。我们需要为日期和时间分别传递 FormatStyle 。例如,日期可以是 LONG ,时间可以是 SHORT
  6. ofLocalizedTime(FormatStyle timeStyle)
    创建具有当地特定时间格式的格式化器。

示例

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 

FormatStyle:

它是一个关于本地化日期、时间或日期时间( date-time )格式化风格的枚举。

它有以下常数。

FULL :例如 'Tuesday, April 11, 2015 AD' or '5:30:45pm PST' .

LONG :例如 'January 10, 2018' .

MEDIUM :例如 'Jan 10, 2018'

SHORT :例如 '11.15.50' or '6:30pm' .

DateTimeFormatter format() 和 formatTo()。

为了格式化一个日期、时间或日期时间( date-time ), DateTimeFormatter 提供了以下方法。

  1. format(TemporalAccessor temporal)
    使用该格式化器对给定的日期时间( date-time )对象进行格式化,并以字符串形式返回。
  2. formatTo(TemporalAccessor temporal, Appendable appendable)
    使用该格式化器对给定的日期时间( date-time )对象进行格式化,并将结果附加到给定的 Appendable 对象中。 Appendable 对象可以是 StringBufferStringBuilder 等的实例。

示例

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

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 

DateTimeFormatter 也被用来解析一个本地日期。

查找示例代码。

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd, yyyy");
LocalDate ld = LocalDate.parse("Dec 20, 2018", dtf);
System.out.println(ld); 

输出

2018-12-20 

格式化 LocalDateTime

LocalDateTimeISO-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

LocalTimeISO-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 “parse” 方法

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 来转义给定文本中的一些字符。

我们用给定的初始索引启动一个 ParsePositionparse 方法将从那里开始解析给定的文本。

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_INSTANTUTC 格式化一个瞬间( instant )。

DateTimeFormatter “with” 方法

下列方法返回 DateTimeFormatter 实例。

  1. withChronology(Chronology chrono)
    返回具有给定时间顺序的格式化器副本。
  2. withDecimalStyle(DecimalStyle decimalStyle)
    返回具有给定十进制样式的格式化器副本。
  3. withLocale(Locale locale)
    返回具有给定区域设置的格式化器副本。
  4. withResolverFields(TemporalField… resolverFields)
    返回具有给定时间字段的格式化器副本。
  5. withResolverFields(Set resolverFields)
    返回这个格式化器的副本,并将给定的时间字段作为Set。
  6. withResolverStyle(ResolverStyle resolverStyle)
    返回具有给定解析器样式的格式化器副本。
  7. withZone(ZoneId zone)
    返回这个格式化器的副本,并给定区域ID。

我们可以在使用 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 “get” 方法

我们可以使用以下方法获取 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转换为Format

DateTimeFormatter 提供以下方法将 DateTimeFormatter 转换为 java.text.Format

  1. toFormat()
    返回java.text.Format实例。
  2. toFormat(TemporalQuery parseQuery)
    返回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 有以下预定义的格式。

FormatterExample
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 

Pattern Letters 和 Symbols

找到格式化日期时间的模式字母( letters )和符号( symbols )。

SymbolDescriptionExample
GeraAD; Anno Domini; A
uyear2018; 18
yyear-of-era2018; 18
Dday-of-year180
M/Lmonth-of-year7; 07; Jul; July; J
dday-of-month11
gmodified-julian-day2451334
Q/qquarter-of-year3; 03; Q3; 3rd quarter
Yweek-based-year1999; 99
wweek-of-week-based-year25
Wweek-of-month3
Eday-of-weekTue; Tuesday; T
e/clocalized day-of-week2; 02; Tue; Tuesday; T
Fday-of-week-in-month2
aam-pm-of-dayAM
hclock-hour-of-am-pm (1-12)12
Khour-of-am-pm (0-11)0
kclock-hour-of-day (1-24)24
Hhour-of-day (0-23)0
mminute-of-hour35
ssecond-of-minute50
Sfraction-of-second970
Amilli-of-day1234
nnano-of-second987654321
Nnano-of-day1234000000
Vtime-zone IDAmerica/Los_Angeles; Z; -08:30
vgeneric time-zone namePacific Time; PT
ztime-zone namePacific Standard Time; PST
Olocalized zone-offsetGMT+8; GMT+08:00; UTC-08:00
Xzone-offset ‘Z’ for zeroZ; -08; -0830; -08:30; -083015; -08:30:15
xzone-offset+0000; -08; -0830; -08:30; -083015; -08:30:15
Zzone-offset+0000; -0800; -08:00
ppad next1
'escape for text
''single quote'
[optional section start
]optional section end

参考文献