import moment from "moment-timezone";
import { trimDate } from "./trimDate.js";
import { roundAndUseNull, useNull } from "./utils.js";
/**
* Calculates diurnal averages for the time series specified by `datetime` and `x`.
*
* The returned object contains two properties:
* * hour -- Array of local time hours [0-24].
* * count -- Array of hour-of-day counts of non-missing values.
* * min -- Array of hour-of-day minimum values.
* * mean -- Array of hour-of-day mean values.
* * max -- Array of hour-of-day maximum values
*
* By default, statistics are calculated using data from the most recent 7 days
* in the `datetime` array.
*
* @param {Array.<Date>} datetime Regular hourly axis (no missing hours)
* representing the time associated with each measurement.
* @param {Array.<number>} x Array of hourly measurements.
* @param {string} timezone Olson time zone to use as "local time".
* @param {number} dayCount Number of most recent days to use.
* @returns {object} Object with `hour`, `count`, `min`, `mean` and `max` properties.
*/
export function diurnalStats(datetime, x, timezone, dayCount = 7) {
// Start by trimming to full days in the local timezone
let trimmed = trimDate(datetime, x, timezone);
// Use the most recent dayCount days
let fullDayCount = trimmed.datetime.length / 24;
dayCount = fullDayCount < dayCount ? fullDayCount : dayCount;
let startIndex = trimmed.datetime.length - dayCount * 24;
let localTime = trimmed.datetime.map((o) => moment.tz(o, timezone));
let hours = localTime.map((o) => o.hours());
let value = useNull(trimmed.x);
let validValue = value.map((o) => (o === null ? 0 : 1));
let hour = [];
let hourly_count = [];
let hourly_min = [];
let hourly_mean = [];
let hourly_max = [];
// For each hour, average together the contributions from each day
for (let h = 0; h < 24; h++) {
let min = Number.MAX_VALUE;
let max = Number.MIN_VALUE;
let count = 0;
let sum = null;
for (let d = 0; d < dayCount; d++) {
let index = startIndex + h + d * 24;
if (validValue[index] === 1) {
min = value[index] < min ? value[index] : min;
max = value[index] > max ? value[index] : max;
count += 1;
sum += value[index];
}
}
hour[h] = h;
hourly_min[h] = min === Number.MAX_VALUE ? null : min;
hourly_max[h] = max === Number.MIN_VALUE ? null : max;
hourly_count[h] = count;
hourly_mean[h] = sum === null ? null : sum / count;
}
hourly_min = roundAndUseNull(hourly_min);
hourly_mean = roundAndUseNull(hourly_mean);
hourly_max = roundAndUseNull(hourly_max);
return {
hour: hour,
count: hourly_count,
min: hourly_min,
mean: hourly_mean,
max: hourly_max,
};
}