i'm searching for a way to replicate oracle TRUNC date function in javascript
https://www.techonthenet.com/oracle/functions/trunc_date.php
basically its rounding a unix timestamp last interval (round time 11pm to 4hrs will result in 8pm)
my first attempt was:
const trunc = (ts,candleSize) => (Math.floor((ts)/(candleSize)) * candleSize)
but this worked for intervals up to 1hr only.
example: trunc(Date('2021-01-01T13:17:00'), 5*60) === Date('2021-01-01T13:15:00')
but trunc(Date('2021-01-01T13:16:00'), 60*60*4) !== Date('2021-01-01T12:00:00')
so i tried using modulo:
const trunc = (ts,candleSize) => (ts - (ts % candleSize)
and it worked fine for most intervals example: ``
but still i was not able to do things like (Quarter) or (first day of month) or first day of week
CodePudding user response:
I don't know exactly how Oracle's TRUNC works, but here's something that might suit. It will truncate (floor) to any multiple of the specified unit, e.g. start of century is "year*100", start of quarter is "month*3", etc. A missing multiple is 1, so "month" is equivalent to "month*1".
/* Truncate date to previous full unit, does not
* modify passed date.
* Start of week is Monday.
*
* @param {Date} date - date to truncate
* @param {string} unit - one of: year, month, week,
* day, hour, minute, second
* optional subunit separated by *
* hour*12 = trunc to nearest whole multiple of 12 hours
* minute*10 = trunc to nearest whole multiple of 10 minutes
*
* @returns {Date} truncated Date
*/
function trunc(date = new Date(), unit = 'day') {
let d = new Date( date);
// Parse unit & subunit
unit = unit.toLowerCase();
let [u, uSub] = unit.split('*');
// Deal with invalid or missing sub unit
if (!Number.isInteger( uSub)) uSub = 1;
// Truncating functions
let f = {
year: d => [d.getFullYear() - d.getFullYear() % uSub, 0],
month: d => [d.getFullYear(), d.getMonth() - d.getMonth() % uSub],
// Start of week is Monday
week: d => [d.getFullYear(), d.getMonth(), d.getDate() - d.getDay() 1],
day: d => [d.setHours(0,0,0,0)],
hour: d => [d.setHours(d.getHours() - d.getHours() % uSub, 0,0,0)],
minute: d => [d.setMinutes(d.getMinutes() - d.getMinutes() % uSub, 0,0)],
second: d => [d.setSeconds(d.getSeconds() - d.getSeconds() % uSub)],
millisecond: d => [d.setMilliseconds(d.getMilliseconds() - d.getMilliseconds() % uSub)]
};
// Validate unit & call appropriate function
if (f.hasOwnProperty(u)) {
return new Date(...f[u](d));
}
// If invalid unit, return undefined
}
// Examples
let d = new Date(2019, 11, 15, 23, 59, 41, 55);
console.log('Test date => ' d.toString());
'year*100 year*10 year month*3 month week day hour*12 hour*6 hour*4 hour*3 hour*2 hour minute*30 minute*20 minute*15 minute*10 minute*5 minute second*30 second'.split(' ')
.forEach(
unit => console.log(`${unit} => ${trunc(d, unit).toString()}`)
);
// Default (start of today)
console.log(`Default => ${trunc().toString()}`)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>