如何自定义日期时间格式
===========

#### 问题现象

如何实现自定义的日期时间格式？比如xx月xx日周xx下午xx:xx。

#### 背景知识

*   时间日期格式化将表示时间日期的Date对象，通过DateTimeFormat类的format()接口实现格式化。
    
    从API version 20开始，该接口建议使用[Intl.DateTimeFormat.prototype.format()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format)替代。
    
*   DateTimeOptions：时间、日期格式化时可设置的配置项。
    
    *   dateStyle和timeStyle需同时设置。设置timeStyle但不设置dateStyle时，只显示时间；设置dateStyle但不设置timeStyle时，只显示日期。
    *   设置dateStyle或timeStyle时，不支持设置年、月、日、时、分、秒、工作日格式；不设置dateStyle和timeStyle时，支持独立设置年、月、日、时、分、秒、工作日格式。
    
    从API version 20开始，建议使用[Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)替代。
    

#### 解决方案

可以将年月日看作整体设置DateTimeOptions配置项，把时分秒看作整体设置DateTimeOptions配置项。

import { i18n } from '@kit.LocalizationKit';

@Entry
@Component
struct Index {
  @State dateTime: string \= '';
  msg\_text: string \= '时间';
  msg\_button: string \= '打开时间选择器';
  selectedDate: Date \= new Date();

  build() {
    Column() {
      Text(this.dateTime \=== '' ? this.msg\_text : this.dateTime)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 });

      Button(this.msg\_button)
        .onClick(() \=\> {
          _// 获取系统语言，如果为英文，区域ID为en，否则为zh-CN_
          getSystemLanguage();

          let md \= getDateTimeFormat(systemLocale, mdOptions);
          let mdw \= getDateTimeFormat(systemLocale, mdwOptions);
          let ymdw \= getDateTimeFormat(systemLocale, ymdwOptions);
          let hourCycle \= getDateTimeFormat(systemLocale, hourCycleOptions);

          this.getUIContext().showDatePickerDialog({
            start: new Date('2000-1-1'),
            end: new Date('2100-12-31'),
            selected: this.selectedDate,
            showTime: true,
            useMilitaryTime: false,
            dateTimeOptions: { hour: 'numeric', minute: '2-digit' },
            onDateAccept: (value: Date) \=\> {
              if (systemLocale \=== 'en') { _//_ _判断区域ID为en或zh-CN_
               _ //__先判断当前是昨天、今天或明天_
                if (daysUS.includes(compareDates(value, systemLocale))) {
                  this.dateTime \=
                    compareDates(value, systemLocale) \+ ',' \+ md.format(value) \+ ' ' \+ hourCycle.format(value);
                } else if (isYear(value.getFullYear())) { _// 判断当前是否为今年_
                  this.dateTime \= mdw.format(value) \+ ' ' \+ hourCycle.format(value);
                } else {
                  this.dateTime \= ymdw.format(value) \+ ' ' \+ hourCycle.format(value);
                }
              } else {
                if (days.includes(compareDates(value, systemLocale))) {
                  this.dateTime \= md.format(value) \+ compareDates(value, systemLocale) \+ ' ' \+ hourCycle.format(value);
                } else if (isYear(value.getFullYear())) {
                  this.dateTime \= mdw.format(value) \+ ' ' \+ hourCycle.format(value);
                } else {
                  this.dateTime \= ymdw.format(value) \+ ' ' \+ hourCycle.format(value);
                }
              }
            },
            onCancel: () \=\> {
              console.info('DatePickerDialog:onCancel()');
            }
          });
        });
    }
    .height('100%')
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center);
  }
}

_//_ _区域ID_
let systemLocale: string \= '';

let days: Array<string\> = \['今天', '昨天', '明天'\];
let daysUS: Array<string\> = \['Today', 'Tomorrow', 'Yesterday'\];

let mdOptions: Intl.DateTimeFormatOptions \= { month: 'long', day: 'numeric' };
let mdwOptions: Intl.DateTimeFormatOptions \= { month: 'long', day: 'numeric', weekday: 'short' };
let ymdwOptions: Intl.DateTimeFormatOptions \= {
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  weekday: 'short'
};
let hourCycleOptions: Intl.DateTimeFormatOptions \= { hourCycle: 'h12', hour: '2-digit', minute: '2-digit' };

_//_ _获取一个DateTimeFormat对象_
function getDateTimeFormat(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {
  return new Intl.DateTimeFormat(locale, options);
}

_//_ _获取系统语言，如果为英文，区域ID为en，否则为zh-CN_
function getSystemLanguage() {
  let systemLanguage: string \= i18n.System.getSystemLanguage();
  if (systemLanguage \=== 'en-Latn-US' || systemLanguage.includes('en')) {
    systemLocale \= 'en';
  } else {
    systemLocale \= 'zh-CN';
  }
}

_//_ _判断当前是否为今年_
function isYear(year: number): boolean {
  if (year \=== new Date().getFullYear()) {
    return true;
  } else {
    return false;
  }
}

_//_ _判断当前是昨天、今天或明天_
function compareDates(selected: Date, systemLocale: string): string {
  const currentDate \= new Date(); _// 当前时间_
  currentDate.setHours(0, 0, 0, 0); _// 清零时分秒毫秒_

  const selectedDate \= new Date(selected); _// 选中时间_
  selectedDate.setHours(0, 0, 0, 0); _// 标准化选中日期_

  const timeDiff \= selectedDate.getTime() \- currentDate.getTime();
  const dayDiff \= Math.floor(timeDiff / (1000 \* 3600 \* 24));
  if (systemLocale \=== 'en') {
    if (dayDiff \=== 0) {
      return 'Today';
    } else if (dayDiff \=== 1) {
      return 'Tomorrow';
    } else if (dayDiff \=== -1) {
      return 'Yesterday';
    } else {
      return '';
    }
  } else {
    if (dayDiff \=== 0) {
      return '今天';
    } else if (dayDiff \=== 1) {
      return '明天';
    } else if (dayDiff \=== -1) {
      return '昨天';
    } else {
      return '';
    }
  }
}

#### 常见FAQ

Q：使用[Intl.DateTimeFormat.prototype.format()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format)对时间戳进行格式化时，无论入参时间戳为多少，格式化的结果都是当前手机显示的时间。

A：排查入参时间戳的数据类型是否为正确的类型（Date或number），如果传入的是string类型，那格式化出来的时间为当前系统时间。解决方案可以先通过Number("1762114200299")将string类型转换为number类型的入参时间戳，然后再进行格式化。