Skip to content

Instantly share code, notes, and snippets.

@vandy
Last active February 4, 2020 20:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vandy/2e10c67e778e17e6b5832fbed39bb948 to your computer and use it in GitHub Desktop.
Save vandy/2e10c67e778e17e6b5832fbed39bb948 to your computer and use it in GitHub Desktop.
/**
* Compares a date with today in the client's time zone. The comparison is day-wise,
* so that all dates since today's midnight till the next midnight are considered "today".
* Yesterday and tomorrow are separate from the past and future.
*
* @param dateRepresentation {string|number|Date}
* @returns {number}
* +2 - date is in the future (after tomorrow)
* +1 - tomorrow
* 0 - today
* -1 - yesterday
* -2 - date is in the past (before yesterday)
*/
export function relativeToLocaleToday(dateRepresentation) {
return relativeToDate(dateRepresentation, Date.now());
}
/**
* Compares a date with the reference date in the client's time zone. The comparison is day-wise,
* so that all dates since the date's midnight till the next midnight are considered "same day".
*
* @param dateRepresentation {string|number|Date}
* @param to {string|number|Date}
* @returns {number}
* +2 - the date is after the reference date (2 days or more)
* +1 - the date is next to the reference date
* 0 - the same day
* -1 - the date is one day before the reference date
* -2 - the date is earlier the reference date (2 days or more)
*/
export function relativeToDate(dateRepresentation, to) {
const date = new Date(dateRepresentation);
const referenceDate = new Date(to);
if (referenceDate.toDateString() === date.toDateString()) {
return 0;
}
const inFuture = date > referenceDate;
const midnight = new Date(
referenceDate.getFullYear(),
referenceDate.getMonth(),
referenceDate.getDate() + (inFuture ? 2 : -1)
);
if (inFuture) {
return midnight > date
? 1
: 2;
}
return midnight <= date
? -1
: -2;
}
/**
* Returns a range of dates between 'from' and 'to' exclusively: 'from', [N+1, N+2, ...], 'to'.
* If 'from' is greater than 'to', the range is reversed: 'from', [N-1, N-2, ...], 'to'.
* If 'include' argument is true and 'from' is the same day as 'to' (time may be different),
* the range would contain only one element, which is max('from', 'to').
*
* @param from {string|number|Date}
* @param to {string|number|Date}
* @param [include=false] {boolean} -
* include 'from' and/or 'to' to the resulting array.
* @param [transform=null] {null|true|Function} -
* if null, time of the dates between 'from' and 'to' would be the same as 'from'.
* if true, time of the dates would be set to locale midnight,
* if Function, each Date in the range would be passed to the function,
* returned value is used in the resulting array.
* @returns {[]}
*/
export function datesRange(from, to, {include = false, transform = null} = {}) {
const range = [];
from = new Date(from);
to = new Date(to);
const reversed = from > to;
if (reversed) {
[from, to] = [to, from];
}
const insert = reversed ? range.unshift.bind(range) : range.push.bind(range);
const formatter = typeof transform === 'function' ? transform : function (d) {
if (transform === true) {
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);
}
return d;
};
const fromToOffset = relativeToDate(from, to);
if (fromToOffset < -1) {
const toMidnight = new Date(to.getFullYear(), to.getMonth(), to.getDate());
const nextDay = new Date(from);
while (nextDay.setDate(nextDay.getDate() + 1) < toMidnight) {
insert(formatter(new Date(nextDay)));
}
}
if (include) {
insert(formatter(to));
if (fromToOffset) {
const resultFrom = formatter(from);
if (reversed) {
range.push(resultFrom);
} else {
range.unshift(resultFrom);
}
}
}
return range;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment