从 Moment 迁移到 Luxon - (t) => moment(t).format('hh:mm') 等效

Migrating from Moment to Luxon - (t) => moment(t).format('hh:mm') equivalent

我正在将一段旧代码从 Moment 迁移到 Luxon 并碰到下面的函数:

export const TIME_FORMATTER = {
  HOUR: (t) => moment(t).format('hh:mm'),
  DAY: (t) => moment(t).format('M/DD'),
  HOUR_PERIOD: (t) => moment(t).format('hh:mm A'),
  DAY_HOUR_PERIOD: (t) => moment(t).format('hh:mm A M/DD'),
  SEC: (t) => moment(t).format('HH:mm:ss')
};

调用如下:

export const getFormatterByTimeInterval = (timeInterval: number) => {
  if (timeInterval <= 240) {
    return TIME_FORMATTER.DAY_HOUR_PERIOD;
  }
  else if (timeInterval > 480) {
    return TIME_FORMATTER.HOUR_PERIOD;
  }
  else {
    return TIME_FORMATTER.DAY;
  }
}

我最初的想法是使用与 Luxon 相同的调用格式:


const TIME_FORMATTER_LUXON = {
  HOUR: (t) => DateTime.local(t).toFormat("hh:mm"),
  DAY: (t) => DateTime.local(t).toFormat("M/d"),
  HOUR_PERIOD: (t) => DateTime.local(t).toFormat("t"),
  DAY_HOUR_PERIOD: (t) => DateTime.local(t).toFormat("t M/d"),
  SEC: (t) => DateTime.local(t).toFormat("HH:mm:ss")
};

这在另一个文件上被调用 const formatter = getFormatterByTimeInterval(timeInterval); 但它正在返回 Invalid DateTime

Luxon 可以吗?可能是什么问题?

我觉得你的旧代码可能有一些问题,所以我想在回答你的问题之前至少解决这些问题:

moment 接受 number 参数的唯一函数签名是 Unix Timestamp (milliseconds):

Similar to new Date(Number), you can create a moment by passing an integer value representing the number of milliseconds since the Unix Epoch (Jan 1 1970 12AM UTC).

const day = moment(1318781876406);

Note: ECMAScript calls this a "Time Value"

我不确定 timeInterval 参数在您的格式化程序解析器函数中代表什么:

function getFormatterByTimeInterval (timeInterval: number) {/* ... */}

但我暂时忽略它。顺便说一句,让我们看看条件:

export const getFormatterByTimeInterval = (timeInterval: number) => {
  // This formats as time and date information
  if (timeInterval > 240) {
    return TIME_FORMATTER.DAY_HOUR_PERIOD;
  }
  // This formats as time-only information
  // Also, this will never match because any `timeInterval` value which is
  // greater than 480 is also greater than 240, so the first conditional above
  // will match and return before reaching this one
  else if (timeInterval > 480) {
    return TIME_FORMATTER.HOUR_PERIOD;
  }
  // Shorter than either of the above
  // This formats as date-only information
  else {
    return TIME_FORMATTER.DAY;
  }
}

我不确定你的程序应该如何工作,但这对我来说似乎不是预期的行为。


关于您的转换问题:

从毫秒 number 类型实例化 DateTimeLuxon 等价物是 DateTime.fromMillis()。 (您无需担心使用 local 方法,因为 luxon 默认使用您系统的本地时区。)

关于等效的格式选项,它们是:

moment luxon
hh:mm hh:mm
M/DD L/dd
hh:mm A hh:mm a
hh:mm A M/DD hh:mm a L/dd
HH:mm:ss HH:mm:ss

用代码表示,大概是这样的:

import {DateTime} from 'luxon';

export const TIME_FORMATTER = {
  HOUR: (millis: number) => DateTime.fromMillis(millis).toFormat('hh:mm'),
  DAY: (millis: number) => DateTime.fromMillis(millis).toFormat('L/dd'),
  HOUR_PERIOD: (millis: number) => DateTime.fromMillis(millis).toFormat('hh:mm a'),
  DAY_HOUR_PERIOD: (millis: number) => DateTime.fromMillis(millis).toFormat('hh:mm a L/dd'),
  SEC: (millis: number) => DateTime.fromMillis(millis).toFormat('HH:mm:ss'),
};

然后,对您的解析器进行一个小的重构:

type FormatterFn = (millis: number) => string;

export const getFormatterByTimeInterval = (timeInterval: number): FormatterFn => {
  let key: keyof typeof TIME_FORMATTER;
  // I'm still not sure about these conditionals,
  // but this order matches longest duration first
  if (timeInterval > 480) key = 'HOUR_PERIOD';
  else if (timeInterval > 240) key = 'DAY_HOUR_PERIOD';
  else key = 'DAY';
  return TIME_FORMATTER[key];
};

你可以这样检查:

// The time you asked this question
const millis = DateTime.fromISO('2022-03-21T21:02:03Z').toMillis();

// Check each conditional range:
for (const timeInterval of [500, 300, 100]) {
  const formatter = getFormatterByTimeInterval(timeInterval);
  console.log(formatter(millis));
}

Code in the TypeScript Playground

来自 TS playground link 的已编译 JavaScript 的演示:

<script type="module">

import {DateTime} from 'https://unpkg.com/luxon@2.3.1/src/luxon.js';

export const TIME_FORMATTER = {
    HOUR: (millis) => DateTime.fromMillis(millis).toFormat('hh:mm'),
    DAY: (millis) => DateTime.fromMillis(millis).toFormat('L/dd'),
    HOUR_PERIOD: (millis) => DateTime.fromMillis(millis).toFormat('hh:mm a'),
    DAY_HOUR_PERIOD: (millis) => DateTime.fromMillis(millis).toFormat('hh:mm a L/dd'),
    SEC: (millis) => DateTime.fromMillis(millis).toFormat('HH:mm:ss'),
};
export const getFormatterByTimeInterval = (timeInterval) => {
    let key;
    // I'm still not sure about these conditionals,
    // but this order matches longest duration first
    if (timeInterval > 480)
        key = 'HOUR_PERIOD';
    else if (timeInterval > 240)
        key = 'DAY_HOUR_PERIOD';
    else
        key = 'DAY';
    return TIME_FORMATTER[key];
};
// The time you asked this question
const millis = DateTime.fromISO('2022-03-21T21:02:03Z').toMillis();
// Check each conditional range:
for (const timeInterval of [500, 300, 100]) {
    const formatter = getFormatterByTimeInterval(timeInterval);
    console.log(timeInterval, formatter(millis));
}

</script>