javascript - 给定一个日期间隔范围,创建一个包含一天中所有 1440 分钟的数组,其中包含源间隔中每分钟出现的频率

标签 javascript datetime d3.js date-fns

我目前正在分析我的 sleep 数据(在 d3 的帮助下),并且我的 sleep 跟踪应用程序有一系列时间/日期,代表 sleep 周期的开始和结束时间。

[
  {
    "startDate": "2017-12-25 00:09:00 +0100",
    "endDate": "2017-12-25 00:50:00 +0100"
  },
  {
    "startDate": "2017-12-25 01:45:00 +0100",
    "endDate": "2017-12-25 02:11:00 +0100"
  },
  {
    "startDate": "2017-12-25 02:26:00 +0100",
    "endDate": "2017-12-25 12:37:00 +0100"
  },
  ...
]

根据这些条目,我想创建一个直方图类型的图表,显示我在一天中的给定小时和分钟内 sleep 的可能性有多大。因此,沿 X 轴将有 1,440 个刻度,代表一天中的每一分钟,条形的高度将表示我在该给定分钟休眠的可能性(使用简单的计数)。

目前,我正在创建一个包含所有间隔之间的所有单独分钟的数组(即,在上面的第一个条目中,将有 41 个对象代表 00:09 到 00:50 之间的每一分钟),然后匹配它们一天总共 1,440 分钟。当它们匹配时,将“一天中的一分钟”的计数加一。

因此,随着时间的推移,我可以看到我可能会在 01:00 sleep ,并在 12:30 醒来。

我有大约 3,100 个 sleep 条目,虽然我当前的代码似乎可以工作,但需要很长时间才能浏览我的条目(可以理解,因为 map 中还有 map )。如果我尝试在 Codesandbox 中仅对 1,000 个条目运行它,则大约一分钟后我不会得到结果。

而且,它……感觉效率低下。我确信一定有一种更有效的方法来做到这一点(我想知道是否有一个 d3 函数可以使它更容易,但我找不到)。

我遇到的部分问题是知道要搜索什么 - 是直方图吗?频率图?还有别的吗?

import * as d3 from 'd3';
import { add, format, getHours, getMinutes } from 'date-fns';
import { flatMap, map } from 'lodash';


// For each interval in the source data, create an array of the minutes
// in that interval
// e.g. For an interval time 00:10:00 to 00:18:00,
//      return 9 dates (00:10:00, 00:11:00, 00:12:00, etc.)

const minutesFromIntervals = flatMap(data, (interval) =>
  d3.timeMinute.range(
    new Date(interval.startDate),
    new Date(interval.endDate),
  ),
);


// Create an array of all the minutes in a day between midnight and
// midnight (1440 minutes)

const minutesOfDay = d3.timeMinute.range(
  new Date(2020, 0, 1),
  add(new Date(2020, 0, 1), { hours: 24 }),
);


// Map over the minutes of a day and see which interval minutes match

const results = map(minutesOfDay, (o) => {
  let count = 0;

  const outerDate = new Date(o);
  const hour = getHours(outerDate);
  const minute = getMinutes(outerDate);

  map(minutesFromIntervals, (p) => {
    const innerDate = new Date(p);
    if (getHours(innerDate) === hour && getMinutes(innerDate) === minute) {
      count += 1;
    }
  });

  return {
    key: format(o, 'HH:mm'),
    value: count,
  };
});


console.log({ results });

// results (example):
// [
//   { key: "00:00", value: 0 },
//   { key: "00:01", value: 1 },
//   { key: "00:02", value: 1 },
//   { key: "00:03", value: 1 },
//   { key: "00:04", value: 2 },
//   { key: "00:05", value: 2 },
//   { key: "00:06", value: 1 },
//   { key: "00:07", value: 3 },
//   ...
// ]

最佳答案

恐怕您无法对 O(n^2) 复杂度做太多事情,但只需消除 就可以大大降低每个步骤的成本日期 方面,而是从整数 Angular 看待它。

当您处理时间时,您总是会遇到一个问题,即您还需要包含一些日期。然后还有闰年、时区和夏令时。相反,如果你看一下它,比如 1440 分钟,第 i 分钟表示午夜后的第 i 分钟,你就不必再处理时间了。

在这里,我将偏移量计算为自您休眠当天午夜以来的分钟数,然后计算您的 sleep 持续时间(以分钟为单位)。如果你在12点之前 sleep 并在12点之后醒来,我会使用%1440重新从午夜开始计数。

一直以来,我不是解析和计算 O(n^2) 日期,而是为每个条目只进行 5 次日期计算,因此 O(n)。现在您可以将其绘制为条形图,每第 60 个值上有一个刻度,刻度格式如 d + ":00"d + "h" 这使它看起来像一个时间戳。

const differenceInMinutes = dateFns.differenceInMinutes;
const parse = dateFns.parse;
const startOfDay = dateFns.startOfDay;

const data = [{
    "startDate": "2017-12-24 23:49:00 +0100",
    "endDate": "2017-12-25 00:03:00 +0100"
  },
  {
    "startDate": "2017-12-25 00:09:00 +0100",
    "endDate": "2017-12-25 00:50:00 +0100"
  },
  {
    "startDate": "2017-12-25 01:45:00 +0100",
    "endDate": "2017-12-25 02:11:00 +0100"
  },
  {
    "startDate": "2017-12-25 02:26:00 +0100",
    "endDate": "2017-12-25 12:37:00 +0100"
  },
].map(d => ({
  startDate: parse(d.startDate),
  endDate: parse(d.endDate),
}));

// This is the result, with minute `x` denoting `x` minutes after midnight
const total = 1440;
const result = new Array(total).fill(0);

data.forEach(d => {
  const offset = differenceInMinutes(d.startDate, startOfDay(d.startDate));
  const duration = differenceInMinutes(d.endDate, d.startDate);

  for (let i = 0; i < duration; i++) {
    result[(i + offset) % total] += 1;
  }
});

for (let i = 0; i < total; i += 60) {
  console.log(i / 60, "    ", result.slice(i, i + 60).join(" "));
}
<script src="https://pagecdn.io/lib/date-fns/123/date_fns.js"></script>

关于javascript - 给定一个日期间隔范围,创建一个包含一天中所有 1440 分钟的数组,其中包含源间隔中每分钟出现的频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64519645/

相关文章:

javascript - 使用窗口大小调整背景图像大小

php - 星期几到天数(星期一 = 1,星期二 = 2)

python - 带有偏移量索引的 Pandas 单个时间戳

javascript - 如果 d3 中没有缩放事件,我的矩形没有良好的坐标

javascript - ASP.NET MVC 表单 : Can submit with ENTER key but not Submit button

javascript - 如何从 highstock 中删除“From”和“To”过滤器?

javascript - 遍历嵌套对象以形成字符串

python - 如何创建一个等于 15 分钟前的 DateTime?

javascript - 缩放后如何应用 d3.js svg 裁剪

javascript - 堆叠动态线图 d3.js