记录一次时间单位判断

前端在处理时间戳的时候,通常情况下都是处理 ms,但是由于历史原因不可描述的原因有些脏数据使用了 s。(希望你不要遇到我们这种场景)

怎么办?我们就需要判断下时间戳的单位?

从下面这段代码看出来,1698153828372 可能是 ms,也可能是 s,只是后者是 55782 年的事情了。

scss 复制代码
import dayjs from 'dayjs';

const time = Date.now(); // 1698153828372

// 如果 time 是 ms
dayjs(time).format(); // 2023-10-24T21:22:55+08:00

// 如果 time 是 s
dayjs(time * 1000).format(); // 55782-05-09T05:16:39+08:00

再看一段代码。

scss 复制代码
import dayjs from 'dayjs';

const time = dayjs('1970-02-01').valueOf(); // 2649600000

// 如果 time 是 ms
dayjs(time).format(); // 1970-02-01T00:00:00+08:00

// 如果 time 是 s
dayjs(time * 1000).format(); // 2053-12-18T00:00:00+08:00

也就是说没法通过时间戳判断单位,因为可能是 ms 也可能是 s,都是合理的。


然而实际使用过程中,我们知道不太可能使用很后面的时间,假设最大是 3000 年。

ini 复制代码
// 正常不太可能出现 3000 年以后的日期。所以假定最大时间
const maxDay = baseTime('3000-01-01');
// ms 最大值。 32503651200000
const maxMs = maxDay.valueOf();
// s  最大值。 32503651200
const maxS = maxMs / 1000;
// dayjs(maxS).format(); // 1971-01-12T12:47:31+08:00

也就是 time 如果 > maxS,则就能准确判断其一定为 ms,如果 < maxS,则可能是 ms 或者 s。

于是我们可以得到这段代码。通过 guessTimeUnit 识别出一定是 ms。但是判断不出 s 还是 ms。

好在这个 maxS 的界限在于 1971-01-12T12:47:31+08:00,也就意味着准确判断 ms 的概率非常大,我认为这个概率在 99% 了。

typescript 复制代码
import { isNumber } from 'lodash-es';

// 正常不太可能出现 3000 年以后的日期。所以假定最大时间
const maxDay = baseTime('3000-01-01');
// ms 最大值。 32503651200000
const maxMs = maxDay.valueOf();
// s  最大值。 32503651200
const maxS = maxMs / 1000;
// dayjs(maxS).format(); // 1971-01-12T12:47:31+08:00

type Result = 'ms' | undefined;

/**
 * 猜测时间单位,因为有假设不太可能出现 3000,所以带前缀 guess
 */
function guessTimeUnit(time: number /* s or ms */): Result {
  // 判断是数值
  if (isNumber(time)) {
    if (time >= maxS) {
      // 大于 maxS, 可能是 ms
      return 'ms';
    }
  }

  // 可能是 s or ms,判断不了,返回 undefined,交由调用方判断
  return;
}

这基本能解决很多问题了,如果假定业务极小概率出现 1971-01-12T12:47:31+08:00 之前的 ms。那么 time < maxS 就认定为 s。

当然这是一种假设,实际还是会发生的,程序需要严谨对待。


如果我们处于特定场景,可以就可以忽略小概率的事情。

比如函数 ms2s,正常入参是 ms,由于历史原因可能也传入了 s。这个时候可以这样应对。

1 能判断时间单位则按照判断的走。

2 如果不能判断(小概率),这按照函数的定义走。 ms2s 定义传入 ms,所以按照 ms 走。

sql 复制代码
const THOUSAND = 1000;

/** 可能传入的 time 没有按照要求,做个兼容 */
function compatible(unit, method) {
  /** time: s or ms */
  function compatibleMethod(time: number): number {
    // 做好判断
    if (isNumber(time)) {
      // 如果能判断出是毫秒,则做兼容
      if (isMs(time)) {
        if (unit === 's') {
          return Math.floor(time / THOUSAND);
        }
        if (unit === 'ms') {
          return Math.floor(time);
        }
      }

      // 是毫秒或者秒
      return method(time);
    }

    // 非 number, 可能 null undefined, 可能 string,没法处理,原样返回
    return time;
  }

  return compatibleMethod;
}

const ms2s = compatible('s', (time: number) => {
  return Math.floor(time / THOUSAND);
});
相关推荐
代码N年归来仍是新手村成员13 分钟前
【AWS】Lambda 初识与服务部署
javascript·react.js·ai·node.js·云计算·ai编程·aws
云水一下28 分钟前
JavaScript 从零基础到精通系列:流程控制、函数与作用域
前端·javascript
丷丩29 分钟前
MapLibre GL JS第28课:PMTiles源和协议
javascript·gis·map·mapbox·maplibre gl js
之歆41 分钟前
Day24_JavaScript正则表达式与性能优化实战:从入门到精通
javascript·性能优化·正则表达式
柚子科技1 小时前
Vue3 响应式原理:我被 ref 和 reactive 坑了3次后终于搞懂了
前端·javascript·vue.js
五月君_1 小时前
继 React、Vue 之后,Three.js 也有 Skills 了!AI 写 3D 终于不“晕”了
javascript·vue.js·人工智能·react.js·3d
scan7241 小时前
大模型只是知道要调用工具,本身不
前端·javascript·html
摇滚侠1 小时前
01 基础语法 JavaScript 入门到精通全套教程
开发语言·javascript·ecmascript
用户6919026813392 小时前
JS 初了解:从“网页玩具”到企业级语言的进化
javascript
月月大王的3D日记2 小时前
Three.js 材质篇(中):从兰伯特到PBR,一篇文章看懂五种光照材质
前端·javascript