Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

25 Nov 2020

WinRT中DateTimeFormatter类

关于UWP的DateTimeFormatter Class

DateTimeFormatter Class放置在Windows.Globalization.DateTimeFormatting命名空间之下,可能意味着显示日期和时间这件事是一个挺国际化的问题,需要针对不同地方的使用习惯做出处理。

先来看看DateTimeFormatter的构造函数,最简单的版本只接受一个格式化字符串为参数。这个字符串可以是模板(template)字符串,还可以是模式(pattern)字符串。

除了这个字符串参数以外,一个额外的参数是语言列表,另外还可以额外接受一套参数(geographic region, calendar, clock)。

除此接受格式化字符串之外,DateTimeFormatter还可以显示指定下面两个参数组之一,或者全部:

  • 日期参数组:Year Format, Month Format, Day Format, DayofWeekFormat
  • 时间参数组:Hour Format, MinuteFormat, SecondFormat

前面提到,DateTimeFormatter的格式化字符串可以设置为Template或者Pattern。Template可以看成是一组预设的Patterns。在DateTimeFormatter的Template辖属可以获取Template字符串,而Patterns辖属可以获取底层的Patterns字符串。

DateTimeFormatter的跟语言相关的辖属

  • Languages
  • ResolvedLanguage

DateTimeFormatter的跟地理位置相关的辖属

  • GeographicRegion
  • ResolvedGeographicRegion

DateTimeFormatter的跟模板组件相关的辖属:

  • LongDate,返回用于longdate格式化的DateTimeFormatter
  • LongTime,返回用于longtime格式化的DateTimeFormatter
  • ShortDate,返回用于shortdate格式化的DateTimeFormatter
  • ShortTime,返回用于shorttime格式化的DateTimeFormatter

DateTimeFormatter的其他辖属:

  • IncludeDay,返回DayFormat
  • IncludeDayOfWeek,返回DayOfWeekFormat
  • IncludeHour,返回HourFormat
  • IncludeMinute,返回MinuteFormat
  • IncludeMonth,返回MonthFormat
  • IncludeSecond,返回SecondFormat
  • IncludeYear,返回YearFormat
  • NumeralSystem , Latn意味着使用(0123456789),Arab意味着使用(٠١٢٣٤٥ ٦٧٨٩)

DateTimeFormatter唯一的成员方法是Format,但是Format有两个版本:

  • Format(DateTimeOffset)
  • Format(DataTimeOffset, timeZoneId)

Template

可以来看看Template的语法:

<template> ::= <opt-whitespace> <date> <opt-whitespace> |
               <opt-whitespace> <time> <opt-whitespace> |
               <opt-whitespace> <specific-date> <whitespace> <time> <opt-whitespace> |
               <opt-whitespace> <time> <whitespace> <specific-date> <opt-whitespace> |
               <opt-whitespace> <relative-date> <whitespace> <time> <opt-whitespace> |
               <opt-whitespace> <time> <whitespace> <relative-date> <opt-whitespace>

<opt-whitespace> ::= [<whitespace>] 

<whitespace> ::= " "+ 

<date> ::= <year> | <month> | <day> | <month-year> | <relative-date> | <specific-date>

<relativedate> ::= <dayofweek> | <month-day> | <relative-longdate>

<specificdate> ::= <shortdate> | <longdate>

<month-day> ::= <month> <whitespace> <day> |
                <day> <whitespace> <month>

<relative-longdate> ::= <month> <whitespace> <day> <whitespace> <dayofweek> |
                        <month> <whitespace> <dayofweek> <whitespace> <day> |
                        <day> <whitespace> <month> <whitespace> <dayofweek> |
                        <day> <whitespace> <dayofweek> <whitespace> <month> |
                        <dayofweek> <whitespace> <day> <whitespace> <month> |
                        <dayofweek> <whitespace> <month> <whitespace> <day>

<month-year> ::= <month> <whitespace> <year> |
                 <year> <whitespace> <month>


<shortdate> ::= "shortdate" |
                <month> <whitespace> <day> <whitespace> <year> |
                <month> <whitespace> <year> <whitespace> <day> |
                <day> <whitespace> <month> <whitespace> <year> |
                <day> <whitespace> <year> <whitespace> <month> |
                <year> <whitespace> <day> <whitespace> <month> |
                <year> <whitespace> <month> <whitespace> <day>


<longdate> ::= "longdate" |
               <year> <whitespace> <month> <whitespace> <day> <whitespace> <dayofweek> |
               <year> <whitespace> <month> <whitespace> <dayofweek> <whitespace> <day> |
               <year> <whitespace> <day> <whitespace> <month> <whitespace> <dayofweek> |
               <year> <whitespace> <day> <whitespace> <dayofweek> <whitespace> <month> |
               <year> <whitespace> <dayofweek> <whitespace> <day> <whitespace> <month> |
               <year> <whitespace> <dayofweek> <whitespace> <month> <whitespace> <day> |
               <month> <whitespace> <year> <whitespace> <day> <whitespace> <dayofweek> |
               <month> <whitespace> <year> <whitespace> <dayofweek> <whitespace> <day> |
               <day> <whitespace> <year> <whitespace> <month> <whitespace> <dayofweek> |
               <day> <whitespace> <year> <whitespace> <dayofweek> <whitespace> <month> |
               <dayofweek> <whitespace> <year> <whitespace> <day> <whitespace> <month> |
               <dayofweek> <whitespace> <year> <whitespace> <month> <whitespace> <day> |
               <month> <whitespace> <day> <whitespace> <year> <whitespace> <dayofweek> |
               <month> <whitespace> <dayofweek> <whitespace> <year> <whitespace> <day> |
               <day> <whitespace> <month> <whitespace> <year> <whitespace> <dayofweek> |
               <day> <whitespace> <dayofweek> <whitespace> <year> <whitespace> <month> |
               <dayofweek> <whitespace> <day> <whitespace> <year> <whitespace> <month> |
               <dayofweek> <whitespace> <month> <whitespace> <year> <whitespace> <day> |
               <month> <whitespace> <day> <whitespace> <dayofweek> <whitespace> <year> |
               <month> <whitespace> <dayofweek> <whitespace> <day> <whitespace> <year> |
               <day> <whitespace> <month> <whitespace> <dayofweek> <whitespace> <year> |
               <day> <whitespace> <dayofweek> <whitespace> <month> <whitespace> <year> |
               <dayofweek> <whitespace> <day> <whitespace> <month> <whitespace> <year> |
               <dayofweek> <whitespace> <month> <whitespace> <day> <whitespace> <year>

<time> ::= <hour> | 
           <hour> <whitespace> <timezone> |
           <timezone> <whitespace> <hour> |
           <shorttime> |
           <longtime>

<shorttime> ::= "shorttime" |
                <hour> <whitespace> <minute> |
                <minute> <whitespace> <hour> |
                <timezone> <whitespace> <hour> <whitespace> <minute> |
                <timezone> <whitespace> <minute> <whitespace> <hour> |
                <hour> <whitespace> <timezone> <whitespace> <minute> |
                <minute> <whitespace> <timezone> <whitespace> <hour> |
                <hour> <whitespace> <minute> <whitespace> <timezone> |
                <minute> <whitespace> <hour> <whitespace> <timezone>

<longtime> ::= "longtime" |
               <hour> <whitespace> <minute> <whitespace> <second> |
               <hour> <whitespace> <second> <whitespace> <minute> |
               <minute> <whitespace> <hour> <whitespace> <second> |
               <minute> <whitespace> <second> <whitespace> <hour> |
               <second> <whitespace> <minute> <whitespace> <hour> |
               <second> <whitespace> <hour> <whitespace> <minute> |
               <timezone> <whitespace> <hour> <whitespace> <minute> <whitespace> <second> |
               <timezone> <whitespace> <hour> <whitespace> <second> <whitespace> <minute> |
               <timezone> <whitespace> <minute> <whitespace> <hour> <whitespace> <second> |
               <timezone> <whitespace> <minute> <whitespace> <second> <whitespace> <hour> |
               <timezone> <whitespace> <second> <whitespace> <minute> <whitespace> <hour> |
               <timezone> <whitespace> <second> <whitespace> <hour> <whitespace> <minute> |
               <hour> <whitespace> <timezone> <whitespace> <minute> <whitespace> <second> |
               <hour> <whitespace> <timezone> <whitespace> <second> <whitespace> <minute> |
               <minute> <whitespace> <timezone> <whitespace> <hour> <whitespace> <second> |
               <minute> <whitespace> <timezone> <whitespace> <second> <whitespace> <hour> |
               <second> <whitespace> <timezone> <whitespace> <minute> <whitespace> <hour> |
               <second> <whitespace> <timezone> <whitespace> <hour> <whitespace> <minute> |
               <hour> <whitespace> <minute> <whitespace> <timezone> <whitespace> <second> |
               <hour> <whitespace> <second> <whitespace> <timezone> <whitespace> <minute> |
               <minute> <whitespace> <hour> <whitespace> <timezone> <whitespace> <second> |
               <minute> <whitespace> <second> <whitespace> <timezone> <whitespace> <hour> |
               <second> <whitespace> <minute> <whitespace> <timezone> <whitespace> <hour> |
               <second> <whitespace> <hour> <whitespace> <timezone> <whitespace> <minute> |
               <hour> <whitespace> <minute> <whitespace> <second> <whitespace> <timezone> |
               <hour> <whitespace> <second> <whitespace> <minute> <whitespace> <timezone> |
               <minute> <whitespace> <hour> <whitespace> <second> <whitespace> <timezone> |
               <minute> <whitespace> <second> <whitespace> <hour> <whitespace> <timezone> |
               <second> <whitespace> <minute> <whitespace> <hour> <whitespace> <timezone> |
               <second> <whitespace> <hour> <whitespace> <minute> <whitespace> <timezone>

<year> ::= "year" | "year.full" | "year.abbreviated"

<month> ::= "month" | "month.full" | "month.abbreviated" | "month.numeric"

<day> ::= "day"

<dayofweek> ::= "dayofweek" | "dayofweek.full" | "dayofweek.abbreviated"

<hour> ::= "hour"

<minute> ::= "minute"

<second> ::= "second"

<timezone> ::= "timezone" | "timezone.full" | "timezone.abbreviated"

上述的BFN表达式可以看出几点:

  • 模板中的组件其实没有很明显的顺序上的规定
  • 但并不是所有的组合都是有效的,比如不能同时指定<date><specificdata>
  • <longtime>这种,其实有很多候选项,需要根据语言,时钟类型来选中具体的选项

常用模板组件

  • longdate, shortdate
  • longtime, shorttime
  • dayofweek, dayofweek.full, dayofweek.abbreviated
  • day, day month year, day month, month year, year month day hour
  • month, month.full, month.abbreviated, month.numeric
  • year, year.full, year.abbreviated
  • hour, minute, second
  • hour minute second, hour minute
  • timezone, timezone.full, timezone.abbreviated

下面列举一些template组件的常见显示示例:

Patterns

Pattern是Template更底层的机制。Pattern使用花括号来框定特殊含义字符,比如{day.numeric}/{month.numeric}/{year.full}。所以花括号本身需要转义,左花括号用{openbrace}表示,右花括号用{closebrace}表示。

下面是pattern的语法:

<pattern> ::= [<literal-text>] <datetime-pattern> [<literal-text>] |
              [<literal-text>] <datetime-pattern> <pattern>

<literal-text> ::= <literal-character>+

<literal-character> ::= [^{}] | "{openbrace}" | "{closebrace}"

<datetime-pattern> ::= <date-pattern> | <time-pattern>

<date-pattern> ::= <era> | <year> | <month> | <day> | <dayofweek>

<time-pattern> ::= <period> | <hour> | <minute> | <second> | <timezone>

<era> ::= "{era.abbreviated" [<ideal-length>] "}"

<year> ::= "{year.full" [<ideal-length>] "}" |
           "{year.abbreviated" [<ideal-length>] "}"

<month> ::= "{month.full}" |
            "{month.solo.full}" |
            "{month.abbreviated" [<ideal-length>] "}"
            "{month.solo.abbreviated" [<ideal-length>] "}"
            "{month.integer" [<ideal-length>] "}"

<dayofweek> ::= "{dayofweek.full}" |
                "{dayofweek.solo.full}" |
                "{dayofweek.abbreviated" [<ideal-length>] "}"
                "{dayofweek.solo.abbreviated" [<ideal-length>] "}"

<day> ::= "{day.integer" [<ideal-length>] "}"

<period> ::= "{period.abbreviated" [<ideal-length>] "}"

<hour> ::= "{hour.integer" [<ideal-length>] "}"

<minute> ::= "{minute.integer" [<ideal-length>] "}"

<second> ::= "{second.integer" [<ideal-length>] "}"

<timezone> ::= "{timezone.full}" |
                "{timezone.abbreviated" [<ideal-length>] "}"

<ideal-length> ::= "(" <non-zero-digit> ")"

<non-zero-digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

语法限制了那些是有效的pattern字段:

{dayofweek.solo.<type>} where <type> is full / abbreviated / abbreviated(n)
{dayofweek.<type>} where <type> is full / abbreviated / abbreviated(n)
{day.<type>} where <type> is integer / integer(n)
{month.<type>} where <type> is full / abbreviated / abbreviated(n) / integer / integer(n)
{month.solo.<type>} where <type> is full / abbreviated / abbreviated(n)
{year.<type>} where <type> is full / abbreviated / abbreviated(n)
{era.<type>} where <type> is full / abbreviated / abbreviated(n)
{hour.<type>} where <type> is integer / integer(n)
{period.<type>} where <type> is full / abbreviated / abbreviated(n)
{minute.<type>} where <type> is integer / integer(n)
{second.<type>} where <type> is integer / integer(n)
{timezone.<type>} where <type> is full / abbreviated / abbreviated(n)
  • solo意味着standalone
  • integer(N),用来表示显示宽度
  • full,abbreviated,等等用来表示预设的版本

下面是一些例子:

(本篇完)