import moment from 'moment'; const TOFIXED_DEICMAL = 1; /** * 若想要有等差的Y軸刻度,則必須確保index是乘以一個共通的被乘數 * 此被乘數就是 stepSize * @param {number} maxTimeInSecond * @returns {object} {resultStepSize, unitToUse} */ export const getStepSizeOfYTicks = (maxTimeInSecond, numOfParts) => { const {unitToUse, timeValue} = getTimeUnitAndValueToUse(maxTimeInSecond); let resultStepSize; resultStepSize = (timeValue * (1.125) / numOfParts); return {resultStepSize, unitToUse}; } /** * Convert second to possibly day or hour or mins. * @param {number} secondToDecide * @returns {object} {unitToUse, timeValue} where timeValue is measured in unitToUse */ const getTimeUnitAndValueToUse = (secondToDecide) => { const day = 24 * 60 * 60; const hour = 60 * 60; const minutes = 60; const dd = secondToDecide / day; const hh = secondToDecide / hour; const mm = secondToDecide / minutes; if (dd > 0 && dd > 1) { return { unitToUse: "d", timeValue: secondToDecide / day, }; } else if (hh > 0 && hh > 1) { return { unitToUse: "h", timeValue: secondToDecide / hour, }; } else if (mm > 0 && mm > 1) { return { unitToUse: "m", timeValue: secondToDecide / minutes, }; } else { console.log('less than one minutes final case timeValue:', secondToDecide, dd, hh, mm); return { unitToUse: "s", timeValue: secondToDecide, } } }; /** * For the display of PrimeVue chart. * According to the max time of the data given, * split the Y axis into equal part as ticks. * @param {number} stepSize stepSize of Y axis * @param {number} index index of current visiting tick on Y axis * @param {string} unitToUse time unit to display; "dhms" usually */ export function getYTicksByIndex(stepSize, index, unitToUse){ const rawStepsizeMultIndex = (stepSize * index).toString(); const shortenStepsizeMultIndex = rawStepsizeMultIndex.substring( 0, rawStepsizeMultIndex.indexOf('.') + 1 + TOFIXED_DEICMAL); return `${shortenStepsizeMultIndex}${unitToUse}`; }; /** * 將秒數轉換成帶有時間單位的格式 * @param {number} second 總秒數 * @param {number} fixedNumber 小數點後幾位 * @returns {string} 轉換完的格式(ex: 1 day, 6.8 hrs) */ export function getTimeLabel(second, fixedNumber = 0) { const day = 24 * 60 * 60; const hour = 60 * 60; const minutes = 60; // 取餘數的操作會把 second 限制在一天之內的範圍(即從0到86399之間), // 意思是過了多少天後剩下多少秒。 const dd = Math.floor(second / day); const hh = Math.floor((second % day) / hour); const mm = Math.floor((second % hour) / minutes); if(dd > 0){ return (second / day).toFixed(fixedNumber) + " days"; } else if(hh > 0){ return ((second % day) / hour).toFixed(fixedNumber) + " hrs"; } else if(mm > 0){ return ((second % hour) / minutes).toFixed(fixedNumber) + " mins"; } if(second == 0){ return second + " sec"; } return second + " sec"; } /** UNUSED * Converts seconds into a formatted string with time units. * 將秒數轉換成帶有時間單位的格式 * * @param {number} second - Total seconds * 總秒數 * @param {number} fixedNumber - Number of decimal places * 小數點後幾位 * @returns {string} - The formatted time string (e.g., 1 day, 6.8 hrs) * 轉換完的格式(ex: 1 day, 6.8 hrs) */ /** * 將秒數轉換成帶有縮寫時間單位的格式 * @param {number} second 總秒數 * @param {number} fixedNumber 小數點後幾位 * @returns {string} 轉換完的格式(ex: 1 d, 6.8 h) * 如果秒數(second)大於等於一天(86400 秒),返回以天為單位的時間,帶有 d 標誌。 * 如果秒數小於一天但大於等於一小時(3600 秒),返回以小時為單位的時間,帶有 h 標誌。 * 如果秒數小於一小時但大於等於一分鐘(60 秒),返回以分鐘為單位的時間,帶有 m 標誌。 * 如果秒數等於 0 秒,返回 "0s"。 * 如果秒數小於 60 秒但大於 0 秒,返回原始秒數,帶有 s 標誌。 */ export function simpleTimeLabel(second, fixedNumber = 0) { const day = 24 * 60 * 60; const hour = 60 * 60; const minutes = 60; const dd = Math.floor(second / day); const hh = Math.floor((second % day) / hour); const mm = Math.floor((second % hour) / minutes); if(dd > 0){ return (second / day).toFixed(fixedNumber) + "d"; } else if(hh > 0){ return ((second % day) / hour).toFixed(fixedNumber) + "h"; } else if(mm > 0){ return ((second % hour) / minutes).toFixed(fixedNumber) + "m"; } if(second == 0){ return second + "s"; } return second + "s"; } /** * 考慮到每包資料內的時間範圍有的大有的小, * 需要根據不同時間範圍級別的資料刻劃不同的Y軸座標, * 因此需要根據最大的時間值來決定Y軸刻度怎麼切分。 * 跟隨最大值的時間單位,將秒數轉換成帶有縮寫時間單位的格式 * @param {number} second 要轉換單位的秒數 * @param {number} max 該 data 中的最大值 * @param {number} fixedNumber 小數點後幾位 * @returns {string} 轉換完的格式(ex: 1 d, 6.8 h) */ export function followTimeLabel(second, max, fixedNumber = 0) { const day = 24 * 60 * 60; const hour = 60 * 60; const minutes = 60; const dd = max / day; const hh = max / hour; const mm = max/ minutes; let maxUnit = ''; let result = ""; if (dd > 1) { maxUnit = 'd'; } else if (hh > 1) { maxUnit = 'h'; } else if (mm > 1) { maxUnit = 'm'; } else { maxUnit = 's'; } switch (maxUnit) { case 'd': if((second / day) === 0) { fixedNumber = 0; } result = (second / day).toFixed(fixedNumber) + 'd'; break; case 'h': if(((second % day) / hour) === 0) { fixedNumber = 0; } result = (second / hour).toFixed(fixedNumber) + 'h'; break; case 'm': if((second / minutes) === 0) { fixedNumber = 0; } result = (second / minutes).toFixed(fixedNumber) + 'm'; break; case 's': if(second === 0) { fixedNumber = 0; } result = second.toFixed(fixedNumber) + 's'; break; } return result; } /** UNUSED * 將時間轉換成不同日期單位的格式 * @param { string } date 日期 * @param { string } maxX 該 data 最大的日期,格式是 timestamp * @param { string } minX 該 data 最小的日期,格式是 timestamp */ export function getDateLabelByMinMaxDate(date, maxDate, minDate) { // 將時間字串轉換為時間物件 // new Date(time) 之後不用 getTime(),因為在JavaScript中, // 日期物件是以時間戳記(timestamp)的形式存儲的。當創建一個新的日期物件時, // 它內部會自動轉換時間字串為時間戳記。 date = new Date(date); maxDate = new Date(maxDate); minDate = new Date(minDate); // 計算時間差距 let timeDiff = maxDate - minDate; // 計算相差的月份 let diffMonths = (maxDate.getFullYear() - minDate.getFullYear()) * 12; diffMonths -= minDate.getMonth(); diffMonths += maxDate.getMonth(); // 計算相差的日期,要取整數才能接續下方的邏輯判斷 `diffDays > 0` // 秒 * 分鐘 * 小時 = 一天的時間量 const diffDays = Math.floor(timeDiff / ( 60 * 60 * 24)); // 計算相差的小時、分鐘、秒 const diffHours = Math.floor(timeDiff / (60 * 60)); const diffMinutes = Math.floor(timeDiff / 60); const diffSeconds = Math.floor(timeDiff); // 顯示結果 if (diffMonths > 1) { return moment(date).format('YYYY/MM/DD'); } else if (diffDays > 1) { return moment(date).format('MM/DD'); } else if (diffHours > 1) { return moment(date).format('MM/DD hh:00'); } else if (diffMinutes > 1) { return moment(date).format('MM/DD hh:mm'); } else { return moment(date).format('hh:mm:ss'); } } /** * Select an appropriate time format based on the time difference. * 根據時間差距選擇適合的時間格式 * 舉例 月: 2022/06 * 舉例 日: 06/06 * 舉例 時: 03/05 12:00 * 舉例 分: 03/05 12:15 * 舉例 秒: 09:05:32 * @param {Array} timestamps - An array of timestamps. * @returns {string} - The suitable time format string. */ export const setTimeStringFormatBaseOnTimeDifference = (minTimeStamp, maxTimeStamp) => { const timeDifferenceInSeconds = maxTimeStamp - minTimeStamp; let dateFormat; if (timeDifferenceInSeconds < 60) { dateFormat = 'HH:mm:ss'; // 秒 } else if (timeDifferenceInSeconds < 3600) { dateFormat = 'MM/DD HH:mm'; // 分鐘 } else if (timeDifferenceInSeconds < 86400) { // 86400 秒 = 24 小時 dateFormat = 'MM/DD HH:mm'; // 小時 } else if (timeDifferenceInSeconds < 2592000) { // 2592000 秒 = 30 天 dateFormat = 'YYYY/MM/DD'; // 天 } else { dateFormat = 'YYYY/MM'; // 月 } return dateFormat; }; /** * Converts an array of Unix timestamps to formatted date strings based on the * specified format for use as axis ticks. * 根據指定的格式將 Unix 時間戳數組轉換為軸標籤的格式化日期字符串。 * @param {Array} timeStampArr * @param {string} timeFormat For example, 'MM/DD' */ export const mapTimestampToAxisTicksByFormat = (timeStampArr, timeFormat) => { if (timeStampArr) { return timeStampArr.map(ts => moment(ts).format(timeFormat)); } };