auspice
Version:
Web app for visualizing pathogen evolution
58 lines (51 loc) • 2.36 kB
JavaScript
/**
* Convert a numeric date to a calendar date (which is nicer to display)
* This is (for CE dates) meant to be used as the inverse ofthe TreeTime
* function `numeric_date` which places the numeric date at noon (12h00),
* i.e. Jan 1 is 0.5/365 of a year (if the year is not a leap year).
* @param {numeric} numDate Numeric date
* @returns {string} date in YYYY-MM-DD format for CE dates, YYYY for BCE dates
*/
export const numericToCalendar = (numDate) => {
/* for BCE dates, return the (rounded) year */
if (numDate<0) {
return Math.round(numDate).toString();
}
/* for CE dates, return string in YYYY-MM-DD format */
/* Beware: for `Date`, months are 0-indexed, days are 1-indexed */
const fracPart = numDate%1;
const year = parseInt(numDate, 10);
const nDaysInYear = isLeapYear(year) ? 366 : 365;
const nDays = fracPart * nDaysInYear;
const date = new Date((new Date(year, 0, 1)).getTime() + nDays*24*60*60*1000);
return dateToString(date);
};
/**
* Convert a calendar date to a numeric one.
* This function is meant to behave similarly to TreeTime's `numeric_date`
* as found in v0.7*. Note that for negative dates, i.e. BCE, no fraction
* in the year will be returned.
* @param {string} calDate in format YYYY-MM-DD
* @returns {float} YYYY.F, where F is the fraction of the year passed
*/
export const calendarToNumeric = (calDate) => {
if (calDate[0]==='-') {
const pieces = calDate.substring(1).split('-');
return -parseFloat(pieces[0]);
}
/* Beware: for `Date`, months are 0-indexed, days are 1-indexed */
const [year, month, day] = calDate.split("-").map((n) => parseInt(n, 10));
const oneDayInMs = 86400000; // 1000 * 60 * 60 * 24
/* add on 1/2 day to let time represent noon (12h00) */
const elapsedDaysInYear = (Date.UTC(year, month-1, day) - Date.UTC(year, 0, 1)) / oneDayInMs + 0.5;
const fracPart = elapsedDaysInYear / (isLeapYear(year) ? 366 : 365);
return year + fracPart;
};
export const currentCalDate = () => dateToString(new Date());
export const currentNumDate = () => calendarToNumeric(currentCalDate());
function dateToString(date) {
return `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}
function isLeapYear(year) {
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
}