Like @mootari said, it’s tricky if you have sessions which span multiple days: you’d need to create multiple elements to display such sessions. Your data doesn’t appear to have any such sessions, at least in UTC time, but, here’s how you could do it:
sessions = (await FileAttachment("sessions.json").json())
.map(({start, end}) => ({
start: new Date(start),
end: new Date(end)
}))
.flatMap(({start, end}) => {
const days = d3.utcDay.range(d3.utcDay(start), end);
return days.map((day, i) => ({
start: i === 0 ? start : day,
end: i === days.length - 1 ? end : days[i + 1]
}));
})
.map(({start, end}) => ({
start,
end: new Date(end - 1) // convert to inclusive upper bound
}))
I did a slightly tricky thing which is that I subtracted one millisecond from the end dates. This is mainly so that when you have sessions that span multiple days, the sessions end at 23:59:59.999Z on the same day rather than on 0:0:0.000Z on the next day.
Then, if you want the intraday time on the y scale, you can map all the dates to the same day 1970-01-01 like you may have been doing before, like so:
new Date(d.start - d3.utcDay(d.start))
d3.utcDay(d.start)
returns the UTC midnight preceding or equal to d.start
, so by subtracting the two, you count the number of milliseconds since UTC midnight. If you pass that to the Date constructor, it’ll give you the equivalent UTC time on January 1, 1970. You probably also want to reverse the y scale so that time goes down ↓ like in a typical calendar.
Likewise if you want the x scale to show the start and end day, you can use d3.utcDay
to round d.start
down, and d3.utcDay.ceil
to round d.end
up. All together that might look like this:
Plot.plot({
x: {
tickFormat: "%d.%m",
round: true
},
y: {
grid: true,
tickFormat: "%I %p",
reverse: true,
nice: true
},
marks: [
Plot.rect(sessions, {
x1: d => d3.utcDay(d.start),
x2: d => d3.utcDay.ceil(d.end),
y1: d => new Date(d.start - d3.utcDay(d.start)),
y2: d => new Date(d.end - d3.utcDay(d.end)),
insetLeft: 0.5,
insetRight: 0.5
}),
Plot.ruleY([new Date("1970-01-01"), new Date("1970-01-01T23:59:59.999Z")])
]
})